2005年12月19日

配列へのポインタと配列へのリファレンス

C/C++ のあまり使われない機能に、配列へのポインタと配列へのリファレンスがあります。ここでは、それらがどのようなものかまとめたいと思います。

 

配列へのポインタ

C 言語には配列の先頭要素へのポインタとは別に配列へのポインタ が存在します。。プログラミング言語Cの 5.7 に多次元配列を受け取る関数の例が載っています。

次のプログラムではサイズ 256 の char 型の配列を作り、その配列へのポインタ p を作っています。++p を実行すると p の指すアドレスは 256 バイト分進みます。

#include <stdio.h>
int main() {
    char foo[256];
    char (*p)[sizeof(foo)] = &foo;
    printf("%p\n", p);
    ++p;
    printf("%p\n", p);  // 256 バイト分進む
    return 0;
}

配列へのリファレンス

C++ には配列へのリファレンスがあります。通常、配列のデータを関数に渡すときはポインタと長さで渡したり、末尾に番兵を添えてポインタで渡したりしますが、C++ では配列へのリファレンスを使う方法もあります。

次のプログラムでは "abc" という文字列の配列 foo を作り、その配列へのリファレンス ref を作っています。ref[0] を書き換えると foo の1文字目が書き換わります。

#include <stdio.h>
int main() {
    char foo[] = "abcdef";
    char (&ref)[sizeof(foo)] = foo;
    ref[0] = 'A';
    printf("%s\n", foo);  // "Abcdef" が表示される
    printf("%d\n", sizeof(ref));  // これは 7
    return 0;
}

まとめ

どちらの機能も使う機会はそれほどなさそうですが、覚えておくといざというときに役立つかもしれません。これは万能の言い訳、「覚えておくといざというときに役立つかもしれない、という口実で雑多な知識を吸収してしまう」の法則という気もしますが、いざというときの一例がみつかりました。

この例では、配列へのリファレンスとテンプレートを組み合わせて、文字列へのハッシュ関数の適用をコンパイル時に行っています。コンパイラの最適化により、文字列の長さと同じ数だけ生成されるはずのテンプレート関数はすべて消えて整数値 (この場合 1064) だけが残る仕組みです。覚えておくといざというときに役に立ちそうですね。