さて、ポインタというものがどういう働きをするかは良く分かったと思います。しかし、これが役に立つ、言われてもいまいちピンとこないことでしょう。そこで、ポインタを便利に使うことのできる、
関数での利用法を見てみましょう。
関数には、引数の値の渡し方の違いにより、
値を渡す方式(call by value)と、
アドレスを渡す形式(call by reference)があります。今まで習ってきた関数はほとんど call by value を使っています。この方法は関数を呼び出すときに、
仮引数に実引数の値がコピーされるだけです。つまり、関数内で仮引数の値を変更しても実引数には影響しません。
一方、call by reference は関数の呼び出し時に、
仮引数に実引数が表すアドレスがコピーされます。よって call by value の場合と違い関数内で仮引数の指している値を変更すると実引数側も影響を受けてきます。この特徴は、引数が同時に
戻り値的な役割を果たすことになるので、call by value の時には戻り値が1つしか返せなかったのを call by reference によって複数の結果を戻すことが可能になるのです。では実際に両方の違いを下のプログラムで確認してみましょう。
[ 例 ] 関数への引数の渡し方の違い
ex9-3.c
/* ---< プロトタイプ宣言 >--- */
void comp_v (int val1, int val2);
void comp_r (int *val1, int *val2);
void main(void)
{
int dat1 = 10, dat2 = 4;
/* 実引数を値渡しで関数に渡す */
comp_v (dat1, dat2);
printf ("[@main_1] dat1 = %d, dat2 = %d\n", dat1, dat2);
/* 実引数をアドレス渡しで関数に渡す */
comp_r (&dat1, &dat2);
printf ("[@main_2] dat1 = %d, dat2 = %d\n", dat1, dat2);
}
void comp_v(int val1, int val2)
{
int temp;
/* 作業用 */
/* val1の方が大きければ入れ換える */
if ( val1 > val2 ) {
temp = val1;
val1 = val2;
val2 = temp;
}
/* 表示 */
printf ("[@comp_v] %d < %d\n", val1, val2);
}
void comp_r(int *val1, int *val2)
{
int temp;
/* 作業用 */
/* *val1の方が大きければ入れ換える */
if ( *val1 > *val2 ) {
temp = *val1;
*val1 = *val2;
*val2 = temp;
}
/* 表示 */
printf ("[@comp_r] %d < %d\n", *val1, *val2);
}
値渡し(call by value)の場合
アドレス渡し(call by reference)の場合
この他にも役に立つ場面はあります。例えば、実行時に使うメモリを小さくしたい時や高速化を行うときです。値渡しの場合は引数に使う分余計にメモリを消費します。ほとんどの場合気にならないのですが、メモリが極度に限られた環境や、関数の呼び出しが頻発するような時にはアドレス渡しの方が適している場合があります。また値渡しの場合は引数を関数が呼び出される前にコピーする必要があるので若干オーバーヘッド(目的の処理が実行されるまでの準備段階)が大きくなります。
いずれにしろケースバイケースで必ずどちらかが良いということはないので、適宜どちらを使うのか検討するのがいいでしょう。
○ソースファイルのダウンロード○
この章に使った例のソースファイルを1つにまとめて圧縮してあります。
【中に含まれているソースファイル】
ex9-1.c ex9-2.c ex9-3.c
example09.lzh (2,199 Bytes)