配列の配列

1次配列と2次配列の違い

一次配列を駆使すれば、どんな複数のデータでも扱えます。
例えば、3つクラス1組、2組、3組があり、それぞれ25人の学生がいて、それぞれの点数を記憶して、 データを管理したい場合を考えてみます。
そのための配列を ten の名前で用意する場合、3クラス×25人=75 より、
int ten[75] と記憶域を用意すればサイズ的に足ります。

変数 n_kumi に、2組の2を記憶し、 変数 n_gaku に10番目学生の意味で 10を記憶し、 これを利用して、その人に100点数を記憶したい場合、次のように記憶すると決めて使うことになります
ten[(n_kumi-1)*25 + n_gaku-1]=100;

つまり、1組で1番目の人は、 ten[0] に記憶することになり、
つまり、2組で1番目の人は、 ten[25] に記憶することになり、
つまり、3組で1番目の人は、 ten[50] に記憶することになります。

2次配列を使う

さてこのような場合、 配列で配列を作ると表現が簡単になります。その宣言は次のようになります。
int ten[3][25];
これは、『 int型が[25]個並ぶ領域 』の配列を3個用意する配列で、2次配列とよばれます。
この宣言は、 [3]個の要素を持つ配列で、各要素を 『 [25]個のint型が並ぶ領域 』 に指示するものですが、その記憶域を 割り当てるメモリのイメージは、次のように、『 int型が[25]個並ぶ領域 』を連続して3個並べた形になります。

□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□□

このイメージは、□の1つがint型要素で、右側にある程、そのアドレスが大きくなるメモリ空間です

n_kumi に、2組の2を記憶し、 n_gaku に10番目学生の意味で10を記憶し、 これを利用して、その人に100点数を記憶したい場合、次のように記憶すると決めて使うことになります
ten[n_kumi-1][n_gaku-1]=100;

つまり、1組で1番目の人は、 ten[0][0] に記憶することになり、
つまり、2組で1番目の人は、 ten[1][0] に記憶(上記の所です)することになり、
つまり、3組で1番目の人は、 ten[2][0] に記憶することになります。

このように、int型で宣言した2次配列なので、[]演算子を2つ使った ten[2][0] の表現で、 (int)型記憶域になります。

そして、この2次配列名に、[]演算を一つだけ使った ten[2]の表現は、 (int)型記憶域を指し示すポインタで、 それは(int *)型になります。それは、アドレス演算子&を使った(&ten[2][0])と同じです。

そして、配列名 ten の表現は、 (int)型記憶域が25個並んだところを指し示すポインタで、 その型は(int (*)[25])型という表現になります。

2次配列の初期化

2次配列も1次配列と同様に、添え字をどのように使うかを決めて、使います。
『1月から 12月を0から11の添え字に使って、それぞれの月の日数を各要素へ記憶する』と決めてプログラミングしました。 それを2つ並べた2次配列の例で、2月は、months[0][1]の28と、閏年の場合につかう months[1][1]の29があります。

char months[2][12] = {
	{ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 },/* 通常の年間月のデータ */
	{ 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 } /* 閏年の年間月のデータ */
};

2次配列を初期化する場合、一つの配列構造を { } で囲むので、
それを {     } の中で並べた表現になります。 この時、最初の [2] の中の2だけ省略可能で、その場合は、中で並べた { } の数で要素数が決まります。
その並べる対象となる [12] の12は、省略した表記ができません。(省略するとエラーです。)

なお、配列名 months の表現は、 (char)型記憶域が12個並んだところを指し示すポインタで、 その型は(char (*)[12])型という表現になります。

そして、months[0]や、months[1]の表現は、(char *)型です。
ですから、char *mp = months[1];と管理でき、 この時 mp[0]からmp[11]で、閏年の1月から12月の日数データを処理するプログラムが作れます。

char型2次配列の文字列による初期化

char の2次配列では、次のように文字列を並べた初期化が可能です。

char a[][5] = {
	"ab",
	"x",
	"1234"
};

この場合、aの配列のメモリーイメージは次のようになります。

a[0][0] a[0][1] a[0][2] a[0][3] a[0][4] a[1][0] a[1][1] a[1][2] a[1][3] a[1][4] a[2][0] a[2][1] a[2][2] a[2][3] a[2][4]
'a' 'b' '\0' '\0' '\0' 'x' '\0' '\0' '\0' '\0' '1' '2' '3' '4' '\0'

なおこのイメージで、a[1][0] の文字から始まる文字列をputsで表示する場合は、
puts( a[1] )または、puts( & a[1][0] )で、できます。