C言語の二次元配列は、一次元配列をさらに配列にしたもの
と考えられる。例として二次元配列 x[3][4]
を考えよう。
この配列の初期要素を以下のようにする。
int x[3][4] = {
1, 2, 3, 4, /* x[0][*] の4要素 */
10, 20, 30, 40, /* x[1][*] の4要素 */
100, 200, 300, 400 /* x[2][*] の4要素 */
};
上記の宣言によって、以下のような値が入る。
x[R][C] | x[*][0] |
x[*][1] | x[*][2] |
x[*][3] |
---|---|---|---|---|
x[0][*] | 1 | 2 | 3 | 3 |
x[1][*] | 10 | 20 | 30 | 40 |
x[2][*] | 100 | 200 | 300 | 400 |
これをまとめて別の関数に受け渡す場合、もらう側の仮引数では かならず第2添字のサイズを指定しなければ正しく受け取ることができない。 つまり、以下のようにする。
/* もらう側の関数定義 */ float sub(int array[][4], int n) { ....... } /* 呼出側の記述 */ int main() { int x[3][4] = { 1, 2, 3, 4, /* x[0][*] の4要素 */ 10, 20, 30, 40, /* x[1][*] の4要素 */ 100, 200, 300, 400 /* x[2][*] の4要素 */ }; float result; avg = sub(x, 5); }
コンピュータのメモリは、1バイトをしまう場所に一つ一つアドレス(番地)が ついている。アドレスは数字一つの通し番号なので、これは1次元である。
0000 | 0001 | 0002 | …… | 0200 | …… |
---|---|---|---|---|---|
…… | …… |
もし、x[3][4]
のような配列があっても、それが実際に
x[R][C] | x[*][0] |
x[*][1] | x[*][2] |
x[*][3] |
---|---|---|---|---|
x[0][*] | 1 | 2 | 3 | 3 |
x[1][*] | 10 | 20 | 30 | 40 |
x[2][*] | 100 | 200 | 300 | 400 |
のような2次元平面の上にに配置されるわけではなく、各要素が順番に配置さ れる。もし、0x1000番地(16進数)から順番に配列要素を保存するとしたら、
x[0][0]
x[0][1]
x[0][2]
x[0][3]
x[1][0]
x[1][1]
x[1][2]
x[1][3]
x[2][0]
:
:
という風に格納される。コンピュータは、配列の添字から実際の 格納アドレスを知るために、2次元配列の添字を使ってアドレスを計算する。
x[R][C] のアドレス = 1000番地 + R×4 + C
このようなアドレスを求めるためには、第2添字の最大個数が 分からなければ計算できない。この理由により、関数で配列を受け取るときには
/* もらう側の関数定義 */
float sub(int array[][4], int n)
{
.......
}
のように第2添字の大きさを指定しなければならないのである。
1次元配列といい2次元配列といいサイズをいちいち指定しないと
いけなくてめんどいな… とくに2次元配列なんか配列を大きくすると
仮引数の書き方も変えなきゃいけないからプログラムの修正が
繁雑そうだ… うーむ、これでいいのか?
続く.....