ここでの話で特に重要なことは,配列の添え字から,データが格納されているアドレスを 割り出す方法である.
1 #include <stdio.h> 2 3 int main(void){ 4 int *p, a[3], i; 5 6 a[0]=11; 7 a[1]=22; 8 a[2]=33; 9 10 p=a; 11 12 printf("%p %p\n", &p, p); 13 14 for(i=0;i<3; i++){ 15 printf("%p %d %p %d %p %d\n", &(a[i]), a[i], a+i, *(a+i), p+i, *(p+i)); 16 } 17 18 return 0; 19 }
0xbffff69c 0xbffff680 0xbffff680 11 0xbffff680 11 0xbffff680 11 0xbffff684 22 0xbffff684 22 0xbffff684 22 0xbffff688 33 0xbffff688 33 0xbffff688 33
このプログラムの実行直後のメモリーの様子を図1に示す.このメ モリーの様子と実行結果から,次に示す2つのことが分かるだろう.
まずは,配列名は配列の先頭アドレスを示すポインターのように動作する.したがって, リスト5の10行目のように,左辺値として配列名を指定して,それを ポインターに代入することができる.
次に分かることは,配列への要素のアクセスは,ポインターを使って表現できる.すなわ ち,a[i]は,*(a+i)と同じであることがわかる.事実,コンパイラーはこのよ うにしてメモりーにアクセスするように機械語に変換するのである.
これまでの話で,一元のポインターは分かった.2次元以上はどうなっているのだろうか?. 同じようにプログラムを作成して調べてみるのが良いだろう.ここでは,配列の添え字か らどのようにしてメモりーのアドレスの導出方法に興味がある.そのために,リスト 6の2次元の配列を使ったプログラムを考える2.
このプログラムの実行結果と図2のメモリーの様子から,a[i][j] は配列名の先頭アドレスaに3*i+j加算したアドレスになることが分かる.
さらに,ここでも配列はポインターを用いて,
a[i][j] *(a+i)[j] *(*(a+i)+j)となっていることが分かる.ここのところは分からなくても良い.
1 #include <stdio.h> 2 3 int main(void){ 4 int a[2][3], i,j; 5 int *p; 6 7 p=a; 8 9 printf("pointer p address %p value %p\n", &p, p); 10 11 a[0][0]=0; a[0][1]=1; a[0][2]=2; 12 a[1][0]=10; a[1][1]=11; a[1][2]=12; 13 14 for(i=0; i<2; i++){ 15 for(j=0; j<3; j++){ 16 printf("%p %d %p %d %p %d\n", 17 &(a[i][j]), a[i][j], p+3*i+j, *(p+3*i+j), *(a+i)+j, *(*(a+i)+j)); 18 19 } 20 } 21 22 return 0; 23 }
pointer p address 0xbffff674 value 0xbffff680 0xbffff680 0 0xbffff680 0 0xbffff684 1 0xbffff684 1 0xbffff688 2 0xbffff688 2 0xbffff68c 10 0xbffff68c 10 0xbffff690 11 0xbffff690 11 0xbffff694 12 0xbffff694 12