ここでの話で特に重要なことは、配列の添え字から、データが格納されているアドレスを 割り出す方法である。そして、それを理解したならば、関数への配列の受け渡し方につい て考える。最終的には、配列を関数へ渡す方法を理解して欲しい。
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つのことが分かるだろう。
まずは、配列名は配列の先頭アドレスを示すポインターのように動作する。したがって、 リスト1の10行目のように、左辺値として配列名を指定して、それを ポインターに代入することができる。
次に分かることは、配列への要素のアクセスは、ポインターを使って表現できる。すなわ ち、a[i]は、*(a+i)と同じであることがわかる。事実、コンパイラーはこのよ うにしてメモりーにアクセスするように機械語に変換するのである。
これまでの話で、一元のポインターは分かった。2次元以上はどうなっているのだろうか?。 同じようにプログラムを作成して調べてみるのが良いだろう。ここでは、配列の添え字か らどのようにしてメモりーのアドレスの導出方法に興味がある。そのために、リスト 2の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
多次元配列の例でも分かるように、配列のデータへアクセスする場合、配列名と添え字の 値と、配列のサイズが必要である。例えば、int hoge[10][20][30]と配列を定義した場 合を考える。このとき、hoge[i][j][k]のデータにアクセスするためには、
このことから、関数に配列の全てを渡す場合には、配列名とサイズを渡す必要があること が分かる。ただし、配列名直後のサイズは不要である。配列の要素にアクセスする時には 不要である。配列を引数にした関数は、リスト3のように書くこと ができるのである。
実行結果を見て分かるように配列の場合は、アドレス渡しとなっている。通常の変数は値
渡しであるが、配列は特別な扱いを受けている。これは、通常の配列は非常に大きいので、
値渡しでいちいちメモりーにコピーしていては時間がかかりすぎるからである。
1 #include <stdio.h> 2 void double_array(int fuga[][20][30]); 3 4 /* ======================================================== */ 5 /* main function */ 6 /* ======================================================== */ 7 int main(void){ 8 9 int hoge[10][20][30]; 10 int i, j, k; 11 12 for(i=0; i<10; i++){ 13 for(j=0; j<20; j++){ 14 for(k=0; k<30; k++){ 15 hoge[i][j][k]=i+j+k; 16 } 17 } 18 } 19 20 double_array(hoge); 21 22 for(i=7; i<10; i++){ 23 printf("hoge[%d][%d][%d]=%d\n", i, i, i, hoge[i][i][i]); 24 } 25 26 return 0; 27 } 28 29 /* ======================================================== */ 30 /* function double_array */ 31 /* ======================================================== */ 32 void double_array(int fuga[][20][30]){ 33 34 int i, j, k; 35 36 for(i=0; i<10; i++){ 37 for(j=0; j<20; j++){ 38 for(k=0; k<30; k++){ 39 fuga[i][j][k]=2*fuga[i][j][k]; 40 } 41 } 42 } 43 44 }
hoge[7][7][7]=42 hoge[8][8][8]=48 hoge[9][9][9]=54