C言語において、ポインタまたは配列を関数に渡す際に実際にはポインタの値(すなわちメモリアドレス)のコピーが渡されるだけであり、配列そのものやメモリの内容が渡されるわけではありません。C言語では配列は値として渡されず、代わりに配列の最初の要素へのポインタが関数へ渡されます。このメカニズムはメモリを節約しますが、誤った使い方をすることで望ましくない副作用を招く可能性があります。
問題 — ポインタと配列の混同:開発者はしばしば、関数内では配列を変更できないと考えたり、関数が渡された配列のサイズを自動的に知っていると誤解したりします。実際には関数は配列の元々のサイズを失い、簡単にその範囲を超えることができます。
解決策 — 常に配列のサイズを別の引数として明示的に渡し、ポインタのコピーとオブジェクトのコピーの違いを明確に理解し、ポインタを介した変更が元のデータに反映されることを忘れないことです。
配列を正しく渡す例:
void print_array(const int* arr, size_t size) { for (size_t i = 0; i < size; ++i) printf("%d ", arr[i]); } int main() { int nums[] = {1,2,3,4,5}; print_array(nums, sizeof(nums)/sizeof(nums[0])); return 0; }
重要な特徴:
関数内で int arr[10] として宣言された配列の長さを関数が知ることができるか?
回答:いいえ、関数内で sizeof(arr) の式はポインタのサイズを返し、配列全体のサイズではありません。サイズは別途渡す必要があります。
関数における配列の渡し方として int arr[] と int arr は同じか?*
回答:はい、関数のシグネチャにおいては同等で、どちらも int へのポインタが渡されます。違いは文法にのみあります。
関数内で配列の要素を変更した場合、元の配列は変更されるのか?
回答:はい、ポインタが渡されたため、関数はそのポインタが指すメモリを変更します。
プロジェクトは配列を初期化する関数を実装し、内部で配列のサイズを sizeof(arr) / sizeof(arr[0]) で定義していました。テスト段階では関数は機能しましたが、他の配列を処理すると異なるメモリを上書きしたり、正しく動作しないことがありました。
利点:
欠点:
関数は常に配列のサイズを別のパラメータとして受け取り、長さは呼び出し側が計算しました。関数内部では渡されたパラメータのみで作業しました。
利点:
欠点: