ProgrammingC開発者

C言語における関数への配列の渡し方のメカニズムについて詳しく説明してください。このモデルに関連するリスクは何ですか?関数内で配列の安全な操作を正しく整理する方法は?

Hintsage AIアシスタントで面接を突破

回答

C言語では、配列は値渡しではなく、ポインタで渡されます。配列を引数として渡すと、実際には配列の最初の要素へのポインタが関数に渡されます。これにより、関数は元の配列を修正しますが、そのコピーは修正しません。

例えば:

void fillArray(int arr[], int n) { for (int i = 0; i < n; ++i) arr[i] = i*i; } int main() { int myarr[5]; fillArray(myarr, 5); // OK }

関数内では

  • sizeof(arr)を使用して元の配列のサイズを知ることはできません。これはポインタのサイズを返し、配列のサイズではありません。
  • 明示的に渡したサイズのメモリ部分でのみ作業できます。

配列と安全に正しく作業する方法:

  • 常に配列のサイズを別の引数として明示的に渡す。
  • サイズのために定数またはマクロラッパーを使用する。
  • 配列を変更から保護する必要がある場合、const int *arrを渡す。

潜在的な質問

質問: 関数内でint arr[]という引数を使用して、元の渡された配列のサイズをsizeof(arr)で知ることはできますか?

回答: いいえ、できません!sizeof(arr)は関数内でポインタのサイズ(例えば、4バイトまたは8バイト)を返しますが、配列のサイズは返しません。

例:

void f(int arr[]) { printf("%zu\n", sizeof(arr)); // ポインタのサイズ、配列ではない! } int main() { int x[10]; f(x); // 通常8(x86_64)または4(x86)を出力 }

実際のエラーの例


逸話

産業プロジェクトで、配列をコピーする関数は、関数内でsizeof(arr)/sizeof(int)を使用して配列の長さを動的に計算しようとしました。これにより、常にサイズが1(8/8)になり、配列の一部のみがコピーされ、データが予測不可能な方法で上書きされました。


逸話

あるネットワークアプリケーションで、データ送信関数はバッファを配列として扱い、サイズを明示的に指定しなかったため、全バッファが送信されず、また配列の境界外でゴミデータを読み込むことになり、送信エラーや接続の不安定さが引き起こされました。


逸話

画像処理ライブラリを書いている際に、プログラマーは画像配列を塗りつぶす関数にサイズの必須パラメータを追加しませんでした。これによりバッファオーバーフローが発生し、特定の入力でプログラムがクラッシュしましたが、これは統合テストで大きな画像を使用して初めて発見されました。