ここでの話で特に重要なことは、配列の添え字から、データが格納されているアドレスを 割り出す方法である。そして、それを理解したならば、関数への配列の受け渡し方につい て考える。最終的には、配列を関数へ渡す方法を理解して欲しい。
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