読者です 読者をやめる 読者になる 読者になる

値渡し(call by value)とポインタ渡し(call by pointer)について

C言語では、関数を呼び出す際に、値渡しという方法で引数を渡す。

 

値渡しは、仮引数に実引数の値をコピーすること。

ポインタ渡しは、仮引数に実引数のメモリアドレスの値をコピーすること。メモリアドレスの"値をコピーする"、という点ではポインタ渡しも値渡しといえる。呼び出された関数内では、コピーしたメモリアドレスを元に、実引数の値を見ることができ、かつ実引数の値を変更することができる。

 

実引数(argument)と仮引数(parameter)とは

実引数とは関数呼び出し時に引き渡す引数のこと。func( argument_a, argument_b );

仮引数とは関数定義時に使用される引数のこと。func( parameter_a, parameter_b ){ };

 

やってみよう!

変数aを定義して、関数funcAは値渡し、関数funcBはポインタ渡しで呼び出す。

それぞれの関数内で仮引数iの値を変更すると、結果はどうなるか。 

difference between call by value and call by point ...

 

f:id:bambinya:20150725084051p:plain

 

最初に、変数aには1が代入され、 メモリアドレスは0012FF5Cだと分かる。

funcAでは、実引数から仮引数に(代入された)値をコピーしているだけである。funcAが呼び出されると仮引数iのメモリ領域が変数aとは別に確保される。そのため、仮引数iの値を7に変更しても、変数aの値は1のままである。またiのメモリアドレスは0012FF58であり、変数aとは違うことがわかる。

一方、funcBでは、実引数から仮引数にメモリアドレスを渡しているので、仮引数iの値を222に変更すると、変数aの値も222になる。またiのメモリアドレスは0012FF5Cであり、変数aと同じことがわかる。

 

(以下は調べたけど、まだちゃんと検証してない) 

Javaでは、実引数が基本型(プリミティブ型)なら値渡し、クラスから作成したオブジェクトであれば参照渡しとなる。

プリミティブ型とは、データを格納するための、最も基本的な型である。 整数値や実数値といった、具体的な「値」を格納するための変数を作るための型が「プリミティブ型」である。プリミティブ型の変数は、変数用に割り当てられたメモリ領域の先頭アドレスがわかれば、CPUがメモリを読み書きできる。それに対しオブジェクトには、オブジェクトが含むメンバ変数が格納されるメモリ領域の先頭アドレスの値が入っている。オブジェクトを実引数として関数を呼ぶ場合、仮引数にはメンバ変数が格納されたメモリ領域の先頭アドレスがコピーされる。そのため、呼び出された関数内で仮引数を変更すると実引数の値も変更される。

文字列が実引数として渡される場合、文字列はStringクラスのオブジェクトなので、オブジェクトの先頭アドレスの値がコピーされる。しかし、仮引数に新しく文字列を代入すると、新しくオブジェクトが作られ、その先頭アドレスが仮引数に代入される。文字列の場合は、仮引数の値を変更しても、実引数の値は変更されない。