编译所有定义的唯一原因是您的 C 编译器在指针类型转换方面过于允许。如果你在这方面使用了一些使其更加迂腐的开关,它应该立即告诉你只有第三次初始化是有效的,而其余的都是错误的。
在大多数情况下(除了少数例外),当T[N]
表达式中使用类型数组时,它会“衰减”(隐式转换)为指针类型T *
- 指向其第一个元素的指针。换句话说,在任何数组的这种上下文中A
,A
表达式都等价于&A[0]
。唯一不会发生数组类型衰减的上下文是一元运算&
符、sizeof
运算符和用作char
数组初始值设定项的字符串文字。
在您的示例array
中是一个int [2][2]
类型的值。当在初始化的右侧使用时,它会衰减为指针类型int (*)[2]
。因此,这是无效的
int *pointer = array;
右手边是int (*)[2]
,而左手边是int *
。这些是不同的指针类型。你不能用另一个初始化一个。
这
int *ppppointer = &array[0];
与前一个完全相同:右侧产生一个int (*)[2]
类型的值。由于同样的原因,它是无效的。
该&array
表达式产生一个int (*)[2][2]
类型的指针。再次,出于这个原因
int *ppointer = &array;
是无效的。
您的示例中唯一有效的初始化是
int *pppointer = array[0];
array[0]
是int [2]
类型的表达式,它衰减为int *
类型 - 与左侧的类型相同。
换句话说,这里没有哪个“更好”的问题。你的初始化只有一个是有效的,其他的都是非法的。有效的初始化也可以写成
int *pppointer = &array[0][0];
由于我上面描述的原因。现在,哪个右侧“更好”(array[0]
或&array[0][0]
)取决于您的个人喜好。
为了使您的其他初始化有效,指针应声明如下
int (*pointer)[2] = array;
int (*ppointer)[2][2] = &array;
int (*ppppointer)[2] = &array[0];
但是这样的指针将具有与指针不同的语义int *
。你显然需要int *
特别。