- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- 授業/C言語基礎/値渡しと参照渡し へ行く。
関数に引数を渡す方法には、値渡しと参照渡しがあります。
値渡し †
関数に値を引数として渡すと、関数は引数を記憶するための領域をメモリー内の別の場所に確保し、受け取った値をそこに代入します。
つまり、呼び出された関数が受け取った引数(変数)は、関数を呼び出したときに渡した引数(変数または定数)とは別の場所に記憶されます。
これを値渡しといいます。
値渡しのとき、呼び出された側で受け取った引数の値を変更しても、呼び出した側が渡した引数の値は変更されません。 これは、別の場所に記憶されている変数の値を変更しているだけだからです。
次のプログラムでは、main関数がinc関数に変数 i を渡し、inc関数が受け取った引数 i の値を 1 増やしていますが、main関数で宣言されている変数 i の値は変わりません(プログラム1)。
/* * 受け取った引数の値を1増やして出力する */ void inc(int i) {{ i++; printf(">> %d\n", i) } int main(void) { int i = 0; inc(i); // 変数を渡す printf("%d\n", i); return 0; }
このプログラムを実行すると、次のようになります。
luna% a.out >> 1 0
参照渡し †
関数に、変数を記憶している領域のアドレス(参照)を渡し、受け取った関数も同じ領域に格納されている変数にアクセスする引数の渡し方を参照渡しといいます
参照渡しのとき、呼び出された側で受け取った引数の値を変更すると、呼び出した側が渡した引数の値も変更されます。 渡した引数と同じアドレスの変数にアクセスし、その値を変えたからです。
C言語の参照渡しは、ポインター型の引数に、変数を記憶している領域のアドレスを渡すことによって行いま す。
ポインターとアドレスについては、C言語応用で勉強する内容なので、ここでは詳しくは説明しません。
配列は参照渡し †
配列を関数の引数にすると、配列の要素数は無視されます。
実は、配列を宣言すると、配列名がポインター型の変数となり、配列を記憶している領域の先頭のアドレスを記憶します。
したがって、配列を関数の引数にすることは、ポインター型の引数に配列を記憶している領域の先頭アドレスを渡していることになり、参照渡しと同じになります。
/* * 受け取った配列の先頭要素の値を1増やして出力する */ void inc(int a[]) {{ a[0]++; printf(">> %d\n", a[0]) } int main(void) { int a[] = { 0 }; inc(a); // 配列を渡す printf("%d\n", a[0]); return 0; }
luna% a.out >> 1 1
プロトタイプ宣言 †
これまで、自分で関数を定義するときはmain関数の前、つまり、関数が呼び出される場所よりも前にしていました。
ところが、関数の数が増えてくると、どの関数がどの関数から呼び出されているのかを全て把握し、どの関数からも呼び出される前に関数を定義することは難しくなります。
そこで、プロトタイプ宣言を使って関数の宣言だけを先にしておくと、関数の定義は自由な場所でできるようになります。
/* * 参照渡しで受け取った値を1増やす */ void inc(int *i) { (*i)++; printf(">> %d\n", *i); } int main(void) { int i = 0; inc(&i); // 変数 i のアドレスを渡す printf("%d\n", i); return 0; }
プロトタイプ宣言がないと、戻り値はint型であるとしてコンパイルを進めます。
したがって、呼び出される前に定義されている関数と戻り値がint型の関数はプロトタイプ宣言をしなくても使えますが、それ以外の関数はプロトタイプ宣言が必要になります。
luna% a.out >> 1 1
ポインターによる参照渡し(おまけ) †
C言語の参照渡しは、ポインター型の引数に、変数を記憶している領域のアドレスを渡すことによって行います。
ポインターとアドレスについては、C言語応用で勉強する内容なので、ここでは詳しくは説明しません。
/* * 受け取った引数にゼロを代入する */ void zero(int x){ x = 0; return; } int main(void){ int a = 1; zero(a); printf("%d\n", a); }
int main(void){ char s[16]; input(s); printf("%s\n", s); return 0; }