第 8 章 関 数 37
8.4 引数で渡される関数値の参照と変更
以下は, 整数 aと b を関数内で入れ換えることを意図して,関数change()を作成した 上でプログラムを記述した例である. ただし,以下の解答例(1)は誤った解答例であり,そ の具体的な理由については後述する.
第8章 関 数 41
例題8–2 整数 a と b を関数内で入れ換えるプログラムを作成せよ.
解答例 8–2 (1) (誤ったプログラムの例)
1: #include <stdio.h>
2: #include <stdlib.h>
3: int main(void){
4: int a = 3;
5: int b = 8;
6: void change( int, int );
7:
8: printf("a = %d, b = %d\n", a, b);
9:
10: change ( a, b );
11:
12: printf("値を入れ換えました...\n");
13: printf("a = %d, b = %d\n", a, b);
14: return(0);
15: } 16:
17: void change(int x, int y){
18: int tmp1, tmp2;
19: tmp1 = x;
20: tmp2 = y;
21: x = tmp2;
22: y = tmp1;
23: }
関数内での文法は, 基本的にmainと同じである. ただし, 引数として関数内にて参照 される変数 x, y の宣言の場所に注意すること. 上の例のように, 関数の引数を記述する
”main( )”の括弧内に, 変数宣言のフォーマットに従って記述する必要がある. なお, 関
数の中だけで使用されるローカル変数(ここでは tmp1とtmp2)は, main関数と同様にプ ログラム本文の中で宣言する. なお, 6行目は関数 change のプロトタイプ宣言 であり, 戻り値を持たない関数であることからvoid型として宣言されている.
このプログラムでは, aと bが関数changeに渡され,change内部で交換されることに なっているように見えるが, 実際は正しく動作しない. なぜならば, 引数として渡された 変数(または定数)は, その値を参照することしか許されていないからである.
C言語では, プログラムの処理が関数内に移るにあたって, 変数(定数)の値のコピーが 渡される. そのため, 関数の内部ではコピーされた値に対して入れ換えが実行されるもの の,結果として親の関数に戻ってきた場合, その変更は破棄されてしまう.
変数に格納された値を変更する場合には, 関数にアドレスを渡す必要がある. 変数のア ドレスを渡すようにして解答例(1)を正しく書き直すと以下のようになる.
第8章 関 数 42 解答例 8–2 (2) (正しいプログラム例)
1: #include <stdio.h>
2: #include <stdlib.h>
3: int main(void){
4: int a = 3;1G 5: int b = 8;
6: void change( int*, int* );
7:
8: printf("a = %d, b = %d\n", a, b);
9:
10: change ( &a, &b );
11:
12: printf("値を入れ換えました...\n");
13: printf("a = %d, b = %d\n", a, b);
14: return(0);
15: } 16:
17: void change(int *x, int *y){
18: int tmp1, tmp2;
19: tmp1 = *x;
20: tmp2 = *y;
21: *x = tmp2;
22: *y = tmp1;
23: }
上記の解答例に示されているように, 親関数であるmainから子の関数changeに変数 aとbのアドレス “&a, &b” が渡されている. 関数 change 内では, 渡されたアドレスを 使って,その実体(*a, *b)を変更することができる. このように,アドレス(ポインタ) を使った変数の受渡しがなされた場合のみ, 関数内で変数の値の変更が可能となる,と覚 えておくとよい.
なお,関数の中で,親ルーチンからの引数の‘受け側’として宣言されている変数,この 例題における変数x, yのことを,仮引数と呼ぶ.親ルーチンから渡されるアドレスを受 ける側の仮引数は,ポインタとして宣言されいることに注意したい.
16行目の関数の定義文におけるフォーマット:
16: void change(int *x, int *y)
は,引数のxとyの実体, すなわち*xと*yがint型であることを表す.すなわちxとyそ のものはint型へのポインタである.関数changeのプロトタイプ宣言を行っている部分:
6: void change( int*, int* );
も同様の表現であり,関数changeの引数が,整数へのポインタであることを表している.
しかしながら,このプロトタイプ宣言のフォーマットは,少々わかりずらい表現である (むしろ,‘int*’ の部分が‘&int’ だったら分りやすかったかもしれない).しかしながら,
これらの形の表記はC言語のプログラミングにおいて頻繁に用いられるので,慣れてお くようにしたい.
第8章 関 数 43