ProgrammingC開発者

C言語におけるポインタと配列の違いは何ですか?配列を関数に正しく渡す方法は?

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

回答。

C言語においてポインタと配列は関連していますが、同じではありません:

  • 配列 — メモリ内の同種の要素の集合で、サイズによって定義されます。
  • ポインタ — 配列や個々のオブジェクトが指し示すことができるメモリ内のアドレスを保持する変数です。

配列を関数に渡す際には、実際には配列の最初の要素へのポインタが渡されます(そのため、関数内でsizeofを使っても全体の配列のサイズではなく、ポインタのサイズしか得られません)。

渡し方の構文:

void foo(int arr[], int size) { // arrは実際にはint* for (int i = 0; i < size; ++i) printf("%d ", arr[i]); } int main() { int data[5] = {1,2,3,4,5}; foo(data, 5); }

引っ掛け問題。

質問: 関数内でsizeof(arr)という式は、arrがint arr[]型のパラメータである場合、何を返しますか?

回答: ポインタのサイズ(sizeof(int*))を返し、配列の全体のサイズではありません。つまり、関数には最初の要素へのポインタが渡されるため、長さに関する情報は失われます。

コード例:

void printSize(int arr[]) { printf("%zu ", sizeof(arr)); // sizeof(int*)は通常4または8 }

逸話

商業プロジェクトで、配列の平均値を計算するために書かれたコードでは、関数内で要素数をsizeof(arr) / sizeof(arr[0])で計算しており、常に1または2が返されていました。これにより、プログラムがデータを正しく処理できず、値の平均を正しく計算できませんでした。


逸話

あるプロジェクトでは、動的に割り当てられた配列が、サイズを別途保管せずに関数に渡されました。その結果、関数はどれだけの要素が割り当てられているのかを知ることができず、境界を越えたり、メモリリークや破損を引き起こしました。


逸話

誤って固定サイズの配列をポインタとして使用し、一部のコンパイラではmemcpyを使用して配列全体をその要素ではなく直接割り当てることが許可されていました。これにより、データ構造の一部が失われたり、スタックオーバーフローが発生するという明白でないエラーが引き起こされました。