C言語において、配列は同じ型の要素の順序付きセットを保存するための基本的な構造です。インデックスによる高速アクセスを提供し、ポインタの操作とも密接に関連しています。配列は静的に、自動的に(スタック上)、または動的に(ヒープ上)宣言できます。割り当てタイプは配列のライフタイム、コードの異なる部分からの利用可能性、メモリ管理の要求に影響を与えます。
問題の歴史
最初のCでは、静的および自動配列のみを定義できましたが、動的メモリ割り当て(malloc、calloc、free 関数)の登場により、新しいデザインパターンが生まれ、コードの柔軟性が高まりました。
問題
開発者は、配列のサイズ、ライフタイム、クリーニングに関してしばしば間違いを犯し、メモリリーク、レースコンディション、およびメモリの損傷を引き起こします。
解決策
タスクに応じた格納タイプの慎重な選択、初期化の監視、動的配列のメモリを適時解放することが重要です。
コードの例:
#include <stdio.h> #include <stdlib.h> int main() { // 自動(スタック上) int auto_arr[5] = {1,2,3,4,5}; // 静的(プログラムが動作している間生存) static int static_arr[5]; // 動的(ヒープ上) int *dyn_arr = malloc(5 * sizeof(int)); for (int i = 0; i < 5; i++) dyn_arr[i] = i * 2; // 使用 for (int i = 0; i < 5; i++) printf("%d ", dyn_arr[i]); printf(" "); free(dyn_arr); return 0; }
主な特徴:
動的配列のサイズをsizeofで知ることはできますか?
いいえ、動的配列のための sizeof(ptr)はポインタのサイズを返し、配列のサイズは返しません。サイズを手動で保存するか、別の変数を使用する必要があります。
int* arr = malloc(10 * sizeof(int)); printf("%zu\n", sizeof(arr)); // ポインタのサイズ、配列のサイズではない
配列の境界を越えるとどうなりますか?
C言語には配列の境界の自動チェックはなく、境界外へのアクセスは未定義の動作を引き起こします。エラーは実行時にのみ発生するか、全く発生しないことがあります。
関数からローカル(自動)配列を返すことはできますか?
いいえ!関数内で宣言された配列は、関数が終了すると削除されます。これを返すと、すでに解放されたメモリにアクセスすることになります。
int* create_wrong_array() { int arr[10]; return arr; // エラー:スタック上のポインタを返す }
開発者がスタック上に配列を作成し、それへのポインタを関数から返します。プログラムは時々クラッシュしたり、ゴミを返すことがあります。
利点:
欠点:
サイズを引数として渡す動的割り当てを使用し、メモリをfreeでクリアします。すべてのメモリ解放ケースはユニットテストで検証されます。
利点:
欠点: