C++の値渡しとポインタ渡しと参照渡しについてです。
C言語にも値渡しとポインタ渡しはあるかと思います。
まず下記のような適当な構造体でみていきます。
typedef struct {
unsigned short a;
unsigned char b;
} Test;
値渡し
値渡しを確認してみます。
int main()
{
Test t = { 0 };
t.a = 1;
t.b = 2;
printf("1. t:0x%08X, t.a:%d, t.b:%d", (unsigned int)&t, t.a, t.b);
test1(t);
printf("3. t:0x%08X, t.a:%d, t.b:%d", (unsigned int)&t, t.a, t.b);
}
void test1(Test t)
{
t.a = 3;
printf("2. t:0x%08X, t.a:%d, t.b:%d", (unsigned int)&t, t.a, t.b);
}
test1という関数を用意し、引数はTest構造体で、関数内で値を書き換えています。
呼び出し前後でprintfで値を確認してみます。
実行結果は次のようになりました。
1. t:0xD92FF9D4, t.a:1, t.b:2 2. t:0xD92FF9B0, t.a:3, t.b:2 3. t:0xD92FF9D4, t.a:1, t.b:2
関数test1の中で出力した結果はaが3になっていますが、アドレスが異なっています。
なのでmainのTest構造体tとtest1のtは別物ということになります。
呼び出し後の出力結果でも、aの値がもとのままになっています。
関数呼び出しの際に値をコピーして渡しています。これが値渡しです。
ポインタ渡し
ポインタ渡しを確認してみます。
int main()
{
Test t = { 0 };
t.a = 1;
t.b = 2;
printf("1. t:0x%08X, t.a:%d, t.b:%d", (unsigned int)&t, t.a, t.b);
test2(&t);
printf("3. t:0x%08X, t.a:%d, t.b:%d", (unsigned int)&t, t.a, t.b);
}
void test2(Test *t)
{
if (!t)
{
return;
}
t->a = 3;
printf("2. t:0x%08X, t->a:%d, t->b:%d", (unsigned int)t, t->a, t->b);
}
test2という関数を用意し、引数はTest構造体のポインタで、関数内で値を書き換えています。
呼び出し前後でprintfで値を確認してみます。
実行結果は次のようになりました。
1. t:0xD92FF9D4, t.a:1, t.b:2 2. t:0xD92FF9D4, t->a:3, t->b:2 3. t:0xD92FF9D4, t.a:3, t.b:2
今回はtest2の中で出力した結果もアドレスが同じになっていて、呼び出し後の出力結果もaが3になっています。
関数呼び出しの際にコピーせず、呼び出し元と呼び出し先で同じ変数を参照しています。
これがポインタ渡しです。
また、ポインタなのでアクセスする前にNULLのチェックが必要になります。
参照渡し
参照渡しを確認してみます。これはC言語のほうにはないものになります。
int main()
{
Test t = { 0 };
t.a = 1;
t.b = 2;
printf("1. t:0x%08X, t.a:%d, t.b:%d", (unsigned int)&t, t.a, t.b);
test3(t);
printf("3. t:0x%08X, t.a:%d, t.b:%d", (unsigned int)&t, t.a, t.b);
}
void test3(Test &t)
{
t.a = 3;
printf("2. t:0x%08X, t.a:%d, t.b:%d", (unsigned int)&t, t.a, t.b);
}
test3という関数を用意し、引数はTest構造体の参照で、関数内で値を書き換えています。
呼び出し前後でprintfで値を確認してみます。
実行結果は次のようになりました。
1. t:0xD92FF9D4, t.a:1, t.b:2 2. t:0xD92FF9D4, t.a:3, t.b:2 3. t:0xD92FF9D4, t.a:3, t.b:2
ポインタ渡しと同じ結果です。
コピーではなく同じ変数を参照していることがわかります。
また、ポインタと違って、普通の構造体変数のときと同じようにaやbなどにアクセスでき、NULLになることもないのでポインタ渡しより安全です。
これが参照渡しです。
