C言語では、関数の引数は常に値渡しされます。つまり、呼び出し元のコードから値のコピーが関数に渡されます。関数の外で変数の値を変更する必要がある場合は、ポインタを使って渡します。
スカラー(例えば、int)を渡す場合、関数はそのコピーを受け取ります:
void foo(int a) { a = 10; } int main() { int x = 5; foo(x); // x == 5, 変更されません! }
変数の値を変更するためにはポインタを使います:
void foo(int* a) { *a = 10; } int main() { int x = 5; foo(&x); // x == 10, 値が変更されました! }
配列は関数の引数として参照渡しですか?
多くの人が「参照渡し」と答えますが、C言語では、関数のシグネチャで配列は参照渡しされることはなく、実際にはポインタにダウングレードされます。
正しい答え:
配列が関数に渡されると、実際にはその最初の要素へのポインタが渡されます。つまり、呼び出された関数は配列の実際のサイズを知らず、配列の要素への変更は元の配列に影響します。
void foo(int arr[]) { arr[0] = 100; } int main() { int a[3] = {1,2,3}; foo(a); // a[0] は100になります! }
歴史
int arr[10]として宣言された配列の値を更新していましたが、呼び出し元のコードでは配列のサイズが小さいものでした。関数は実際のサイズを知らなかったため、バッファオーバーフローが発生し、メモリが破損しました。開発者はスカラーを「参照」で(ポインタを介して)渡すことで元の値の不変性を保証されると期待していましたが、誤ってポインタを通じてスコープの外のメモリを変更してしまい(ポインタ算術のエラー)、予測できない結果を引き起こしました。