C言語入門:関数へのポインタ渡しと値渡し
ここでは、ポインタに関して理解するために、int型ポインタを関数に渡した場合の挙動を紹介します。
サンプル
#include <stdio.h>
void
funcA(int i)
{
i = 7;
}
void
funcB(int *i)
{
(*i) = 222;
}
int
main()
{
int a = 1;
printf("a=%d\n", a);
funcA(a);
printf("after funcA() : a=%d\n", a);
funcB(&a);
printf("after funcB() : a=%d\n", a);
return 0;
}
上記例を実行すると「1」以下のように表示されます。
> ./a.out
a=1
after funcA() : a=1
after funcB() : a=222
この結果を見ると、funcA()の中で変数の値を変更しても、main()の中のint aは変わらず、funcB()の中で(*i)を変更するとmain()の中のint aが変わることがわかります。
funcA()とfuncB()の違いは、変数の渡し方です。 funcA()は、intをそのまま「値渡し」しています。 一方、funcB()は、intのポインタを引数とする事で「参照渡し」をしています。
funcA()の引数の渡し方では、main()の中のint aは、funcA()の引数であるint iにコピーされて渡されます。 funcA()のint iには、main()のint aと全く同じ値が入っていますが、所詮はコピーでしかないので、その値を変更してもmain()のint aの値は変わりません。
一方、funcB()は、int aへのポインタをint *iとして渡しています。 このため、int *iは、int aの実体がある場所を指しています。 funcB()中で使われている(*i)というのは、「*iが指す実体に対して」という意味があるので、(*i)を変更すると、main()のint aの中身が変更されます。
もう一つ最後に少しややこしい話をしますが、funcB()のint *iという引数は参照渡しではありますが、実はfuncA()と同じでコピーでもあります。 何故コピーかというと、main()でfuncB()を呼び出すときに渡している引数であるint aへのポインタという「値」をint *iとしてコピーして渡しているからです。 たとえば、funcB()内で(*i)に対して何かの操作をするのではなく、iに対して操作をしてもint &aというmain()の中での表現に影響は与えません(ただしポインタであるiに対する変な操作を下後で値を代入したりするとバッファオーバーフローを発生させる可能性があるのでご注意下さい)。
最後に
関数の引数を扱うとき、値渡しとポインタ渡し(参照渡し)で意味が全く違ってきます。 値渡しで関数にデータを渡しておいて「あれ?変化しないぞ?」というバグで悩むのは、初心者が必ず通る道である気がしています。
次:__LINE__
おまけ