配列の配列 ポインタの配列 配列を指すポインタ ポインタを指すポインタ

※補足
マクロ関数の引数に()を付けていなかったので、意図した結果になってなかった。コードの修正と、結果の取り直しをした。

何度もネタにしているけど、この間C勉強会をした時に、まだよくわかっていない人がいた。そのたびに、手を変え品を変え説明しているが、またサンプルコードを書いてみた。

/* x[0][0]のメモリ配置 */

#include <stdio.h>

#define DPRINT(arg)	do { \
	printf("&" #arg " = %p, " #arg " = %p, " #arg "[0] = %p" , &(arg), (arg), (arg)[0]); \
	printf("\n\tsizeof(" #arg ") = %2u, sizeof(" #arg "[0]) = %2u\n", sizeof(arg), sizeof((arg)[0])); \
} while(0)

int main(int argc, char **argv)
{
	char	x1[3][2];
	char	x2[2][3];
	char	*x3[3] = {"hoge1", "hoge2", "hoge3"};
	char	(*x4)[3] = x2;
	char	**x5 = x3;

	DPRINT(x1);
	DPRINT(x2);
	DPRINT(x3);
	DPRINT(x4);
	DPRINT(x5);

	return 0;
}

実行の前に、どのような表示になるか予想してみて欲しい。
ちなみに私の環境では以下のようになった。gcc 3.4.6(cygwin)

$ ./main
&x1 = 0x22cd50, x1 = 0x22cd50, x1[0] = 0x22cd50
        sizeof(x1) =  6, sizeof(x1[0]) =  2
&x2 = 0x22cd40, x2 = 0x22cd40, x2[0] = 0x22cd40
        sizeof(x2) =  6, sizeof(x2[0]) =  3
&x3 = 0x22cd30, x3 = 0x22cd30, x3[0] = 0x404000
        sizeof(x3) = 12, sizeof(x3[0]) =  4
&x4 = 0x22cd2c, x4 = 0x22cd40, x4[0] = 0x22cd40
        sizeof(x4) =  4, sizeof(x4[0]) =  3
&x5 = 0x22cd28, x5 = 0x22cd30, x5[0] = 0x404000
        sizeof(x5) =  4, sizeof(x5[0]) =  4