2 関数のデータの渡し方

ここでは、abのデータを入れ替える関数swap()を通して、ポインターの使い方を 学習する。

2.1 関数についての復習

以前の関数の学習を思い出してほしい。C言語の関数とは、次のようなものであった。

データの受け渡しに、以下の2つの方法を学習した。

値渡し
実引数と仮引数の記憶領域が異なる。呼び出される関数がつか う仮引数の記憶領域に実引数の値がコピーされる。従って、呼 び出させた側の関数は、呼び出した側の記憶領域を操作するこ とができない。
アドレス渡し
実引数はアドレスで、仮引数はポインターである。呼び出さ れた関数は、ポインターをとおして、呼び出し側の関数の変数 の記憶領域を操作する。

次節では、実際のプログラムを通して、これらのデータの渡し方の違いを考える。

2.2 値渡し

値渡しでは、呼び出された側は実引数の値を受け取る。そして、呼び出された関数の記憶 領域(変数)に値を格納する。この場合、呼び出された側は、呼び出し側の記憶領域を使う ことができない。なぜならば、呼び出された側は呼び出し側の記憶領域のアドレスが分か らないからである。従って、値渡しでは、呼び出し側と呼び出された関数では、変数の名 前が同一でも、全く異なる記憶領域を使いデータを処理するのである。

リスト1に値渡しのプログラム例を示す。関数swapabのデータを入れ替えようとしているが、それは不可能である。理由は、 図1に示すプログラム実行状態のメモリーの様子を見て ほしい。


   1 #include <stdio.h>
   2 void swap(int a, int b);
   3 
   4 /*===============================================*/
   5 /*  main 関数                                    */
   6 /*===============================================*/
   7 int main(void){
   8 
   9   int a,b;
  10 
  11   a=1;
  12   b=2;
  13 
  14   swap(a, b);
  15  
  16   printf("a=%d\tb=%d\n", a, b);
  17 
  18   return 0;
  19 }
  20 
  21 /*===============================================*/
  22 /*  swap 関数(値渡し)                             */
  23 /*===============================================*/
  24 void swap(int a, int b){
  25   int temp;
  26 
  27   temp=a;
  28   a=b;
  29   b=temp;
  30 
  31 }
\fbox{実行結果}
a=1     b=2
図 1: プログラムの各実行段階でのメモリーの様子。メモリーの内容が空白の部分 は値が不明であることを示している。
\includegraphics[keepaspectratio, scale=1.0]{figure/memory_func_swap_value.eps}

2.3 アドレス渡し

アドレス渡しでは、呼び出された側は実引数のアドレスを受け取る。呼び出された関数は、 その専用の記憶領域(ポインター)にアドレスを格納する。呼び出された側は、呼び出し側 の変数のアドレスが分かるので、それを操作することができる。

リスト2にアドレス渡しのプログラム例を示す。先ほどの値 渡しと異なり、関数swapabのデータを入れ替えができている。デー タが入れ替えられた理由は、図2に示すプログラム実 行状態のメモリーの様子を見て考えて欲しい。


   1 #include <stdio.h>
   2 void swap(int *a, int *b);
   3 
   4 /*===============================================*/
   5 /*  main 関数                                    */
   6 /*===============================================*/
   7 int main(void){
   8 
   9   int a,b;
  10 
  11   a=1;
  12   b=2;
  13 
  14   swap(&a, &b);
  15  
  16   printf("a=%d\tb=%d\n", a, b);
  17 
  18   return 0;
  19 }
  20 
  21 /*===============================================*/
  22 /*  swap 関数(アドレス渡し)                        */
  23 /*===============================================*/
  24 void swap(int *a, int *b){
  25   int temp;
  26 
  27   temp=*a;
  28   *a=*b;
  29   *b=temp;
  30 
  31 }
\fbox{実行結果}
a=2     b=1
図 2: プログラムの各実行段階でのメモリーの様子。メモリーの内容が空白の部分 は値が不明であることを示している。
\includegraphics[keepaspectratio, scale=1.0]{figure/memory_func_swap_address.eps}

2.4 まとめ(ポインターとアドレス渡しの関係)

C言語では、関数によって、独立に記憶領域を持っている3。値渡しの場合、実引数の 値が仮引数に渡され、それを使って処理をする。呼び出された側の関数は、呼び出し側の 関数の変数の値を操作することができない。呼び出し側の関数の変数のアドレスが分から ないからである。

一方、アドレス渡しの場合、呼び出し側の変数のアドレスが渡される。そのため、呼び出 し側で呼び出し元の変数の値を書き換えることができる。



ホームページ: Yamamoto's laboratory
著者: 山本昌志
Yamamoto Masashi
平成19年6月24日


no counter