C++の値渡しとポインタ渡しと参照渡し

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になることもないのでポインタ渡しより安全です。
これが参照渡しです。

スポンサーリンク