配列のポインタ渡しと参照渡しの違い

ポインタ渡しとは以下のような処理です。

#include <iostream>
using std::cout; using std::endl;

// ポインタ渡し
void func(int *a) {
    cout << a[0] << endl;
}

int main () {
    int a[] = {3,4,5,6};
    func(a);
}

また、以下のようにも書くことができます。

void func(int a[]) {
    cout << a[0] << endl;
}

関数の仮引数におけるint a[]はint *aのシンタックスシュガーなのでまったくの同義なのです。

またこのとき要素数の指定も出来ますが、*aのシンタックスシュガーなので無視されます。

#include <iostream>
using std::cout; using std::endl;

// int *aのシンタックスシュガー
void func(int a[10000]) {
    cout << a[0] << endl;
}

int main () {
    int a[] = {3,4,5,6};
    func(a);
}

上記処理はコンパイルエラーになりません。


さてお次は参照渡しの場合です。

#include <iostream>
using std::cout; using std::endl;

// 参照渡し
void func(int (&a)[4]) {
    cout << a[0] << endl;
}

int main () {
    int a[] = {3,4,5,6};
    func(a);
}

参照渡しの場合は要素数の指定まで正確にしないとコンパイルエラーになります。

// 要素数10000にしてみる
void func(int (&a)[10000] {
    cout << a[0] << endl;
}

int main () {
    int a[] = {3,4,5,6};
    func(a);
}
$ cl /W4 /EHsc main.cpp
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
main.cpp(12) : error C2664: 'func' : 1 番目の引数を 'int [4]' から 'int (&)[10000]' に変換できません。(新しい機能 ; ヘルプを参照)

となります。

また参照渡しの場合にした場合、ポインタ配列を渡すことができなくなります。

void func(int (&a)[4]) {
    cout << a[0] << endl;
}

int main () {
    int a[] = {3,4,5,6};
    int *b = a;
    func(b);
}
$ cl /W4 /EHsc main.cpp
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
main.cpp(12) : error C2664: 'func' : 1 番目の引数を 'int *' から 'int (&)[4]' に変換できません。(新しい機能 ; ヘルプを参照)

またあくまでも参照なので当然のごとくポインタの演算も出来ません。

void func(int (&a)[4]) {
    a++; // ポインタ演算
    cout << a[0] << endl;
}

int main () {
    int a[] = {3,4,5,6};
    func(a);
}
$ cl /W4 /EHsc main.cpp
Microsoft(R) 32-bit C/C++ Optimizing Compiler Version 15.00.30729.01 for 80x86
Copyright (C) Microsoft Corporation.  All rights reserved.

main.cpp
main.cpp(5) : error C2105: '++' には左辺値が必要です。

まとめ

ポインタ渡しの場合
  • ポインタ配列を渡せる
  • 配列の要素数コンパイルチェックができない
  • ポインタの演算ができる
参照渡しの場合
  • ポインタ配列が渡せない
  • 配列の要素数コンパイルチェックができる
  • ポインタの演算ができない


静的な配列を扱う場合は参照渡しのほうが断然良いですね。