C言語では、配列変数は変数名自体が先頭要素のアドレスを表すことになっている。
したがって、以下のコードのように、&を使わなくても各要素のアドレスを参照することができる。
#include <stdio.h>
int main(void)
{
int xs[5] = {1, 2, 3, 5, 8};
printf("%p\n", xs); /* &xs[0] と同じ*/
printf("%p\n", xs+1); /* &xs[1] と同じ*/
return 0;
}
上記の性質とポインタを合わせると、以下のサンプルコードのように複数の方法で配列の要素にアクセスできる。
#include <stdio.h>
int main(void)
{
int i;
int xs[5] = {1, 2, 3, 5, 8};
int *pi;
pi = xs; /* &xs[0] と同じ*/
for (i = 0; i < 5; i++)
printf("xs[%d]=%d pi[%d]=%d *(pi+%d)=%d *(xs+%d)=%d\n",
i, xs[i], i, pi[i], i, *(pi+i), i, *(xs+i));
return 0;
}
実行結果は以下のようになる。どの方法を用いても同じ値が参照される。
xs[0]=1 *(pi+0)=1 pi[0]=1
xs[1]=2 *(pi+1)=2 pi[1]=2
xs[2]=3 *(pi+2)=3 pi[2]=3
xs[3]=5 *(pi+3)=5 pi[3]=5
xs[4]=8 *(pi+4)=8 pi[4]=8
以下の図は上記サンプルプログラムにおいての、ポインタと配列の関係を示したものである。
ポインタ変数 pi に配列の先頭アドレスを代入した後(つまり、pi = xs)は、間接演算子*を使った表現やポインタ変数の配列のような表現を使うことができる。
ここで、もしポインタ変数の値を1だけ大きい値に変更した場合、ポインタ変数が指す配列の要素は配列の先頭ではなく、隣の要素を指すようになる。つまり、配列中のある特定の要素を直接指し示すことができる。
(そのため、同じ配列要素を参照するためには、ポインタ変数に対するオフセット値(あるいは添字の数)をそれぞれ1つずつ小さくする必要がある)
このようにポインタと配列は同じように使うことが可能である場合もあるが、全く同じものではない。例えば以下の例で、ポインタ変数は値の書き換えが出来るが、配列変数は書き換えができない。
int xs[5] = {1, 2, 3, 5, 8};
int *pi = xs;
pi = pi + 1; /* OK (ポインタ変数は書き換えられる) */
xs = xs + 1; /* エラー (配列変数は書き換えができない) */
array-ptr-test.cをコンパイル・実行し、これまでに説明した配列とポインタの関係を確認してください。