ポインタの配列

前のエントリのお題を再掲する。

以下の違いを説明せよ。
1)int a[2][3];
2)int a[3][2];
3)int *a[3];
4)int (*a)[3];
5)int **a;

次は3)のポインタの配列がどのようにメモリ上に配置されるかを見る。お題はint *a[3]であるが、扱いやすさと、実際のコードに現れやすいchar *a[3]を使ってサンプルコードを書く。C文字列はconst charの配列であるので、そこに特有の処理があるが、本質は同じである。

#include <stdio.h>

#define ARRAY_NUM_OF(array)	((sizeof(array)) / (sizeof(array[0])))

int main(void)
{
	char *a[3] = {"C", "C++", "Java"};
	int i, j;

	printf("char *a[3] (array[3] Pointer to char)\n");
	printf("sizeof(a) = %u, sizeof(a[0]) = %u\n", sizeof(a), sizeof(a[0]));
	for (i = 0; i < ARRAY_NUM_OF(a); i++) {
		printf("   a[%d] is @ %p\n", i, &a[i]);
	}
	printf("====================== \n");
	for (i = 0; i < ARRAY_NUM_OF(a); i++) {
		for (j = 0; a[i][j] != '\0'; j++) {
			printf("a[%d][%d] is @ %p\n", i, j, &a[i][j]);
		}
	}
	
	return	0;
}

実行結果は以下のようになる。

$ ./main
char *a[3] (array[3] Pointer to char)
sizeof(a) = 12, sizeof(a[0]) = 4
   a[0] is @ 0x22cd50
   a[1] is @ 0x22cd54
   a[2] is @ 0x22cd58
======================
a[0][0] is @ 0x404000
a[1][0] is @ 0x404002
a[1][1] is @ 0x404003
a[1][2] is @ 0x404004
a[2][0] is @ 0x404006
a[2][1] is @ 0x404007
a[2][2] is @ 0x404008
a[2][3] is @ 0x404009

配列の配列の場合とは、メモリ上のアクセスの方法が、全く異なることがわかるだろう。
実行結果から、メモリマップを図に起こすと、以下のようになる。

[超重要ポイント]a[i][j]と言う記述だけでは、配列の配列なのかポインタの配列を[]演算子で参照しているのか不明