- バックアップ一覧
- 差分 を表示
- 現在との差分 を表示
- ソース を表示
- 授業/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
プロトタイプ宣言 †
関数のプロトタイプ宣言は、関数の宣言です。
/* * 参照渡しで受け取った値を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; }
関数を使う前に、戻り値の型、関数名、引数の型、引数名を宣言しておかなければなりません。
luna% a.out >> 1 1
プロトタイプ宣言を省略できる場合 †
以下の二つの場合には、プロトタイプ宣言を省略することができます。
関数定義 †
関数定義は、プロトタイプ宣言の代わりにできます。
したがって、使用されるよりも前に関数が定義されている場合は、プロトタイプ宣言を省略できます。
これまでプロトタイプ宣言がなくても問題がなかったのは、このためです。
関数の戻り値がint型 †
プロトタイプ宣言がないと、戻り値はint型であると仮定してコンパイルを進めます。
関数定義において戻り値がint型でないと、コンパイル時にエラーが発生します。
ポインターによる参照渡し(おまけ) †
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; }