ProgrammingC開発者

C言語の関数における引数の渡し方はどのように機能しますか?異なる型、構造体、配列の変数を渡す際に型のエラーを回避する方法は何ですか?

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

回答。

C言語では、関数への引数は常に値渡しされます。つまり、関数は引数の値のコピーを受け取ります。単純な型(int, float)の場合は明らかです:関数内での変更は元の変数に影響を及ぼしません。配列と構造体にはニュアンスがあります:

  • 配列を関数に渡すと、実際には最初の要素へのポインタが渡されますが、ポインタ自体は依然として値で渡されます。
  • 構造体は明示的にコピー(値渡し)できますが、そのコピーはポインタを介して渡す方が便利です—そうすると関数は元の構造体を変更できます。

例:配列と構造体の処理

#include <stdio.h> typedef struct { int a; int b; } Pair; void modifyArray(int arr[], int size) { arr[0] = 42; // 元の配列を変更 } void modifyStruct(Pair s) { s.a = 100; // ローカルコピーだけを変更 } void modifyStructPtr(Pair *s) { s->a = 200; // ポインタを介して元の値を変更 } int main() { int nums[2] = {1, 2}; Pair p = {10, 20}; modifyArray(nums, 2); modifyStruct(p); modifyStructPtr(&p); printf("nums[0]=%d, p.a=%d\n", nums[0], p.a); // nums[0]=42, p.a=200 return 0; }

トリッキーな質問。

質問: void func(int arr[10])と宣言された関数は、常にその内部で10要素を持つ配列になりますか?

回答: いいえ。引数のint arr[10]は実際にはint *arrと同等であり、配列のサイズは渡す際に失われます。関数は配列の実際の長さを知りませんので、常にその長さを持つ追加のパラメータを受け取るべきです。そうしないと、配列の境界を越える可能性や未定義の動作(UB)が発生します。

例:

void foo(int arr[10]) { printf("%d\n", arr[9]); // arrが必ずしも10要素を含むわけではない! }

歴史

信号処理のプロジェクトで、配列を関数に渡して長さが常に同じであると見込んでいましたが、ある場合に小さい配列を渡しました。結果はメモリの境界を越えるアクセス、アプリケーションのクラッシュ、コントローラー上での予測不可能な動作を引き起こしました。


歴史

銀行ソフトウェアで、構造体をポインタではなく値渡しして変更しようとしました。変更が保存されなかったため、処理モジュールは口座の状態を更新せず、計算のエラーを引き起こしました。


歴史

テレメトリーシステムで、学生が配列をクリアする関数を追加しましたが、長さを渡すことを忘れ、配列のサイズが異なりました。エラーは大量の不正確なデータの収集とバグの長時間の検索の後に発見されました。