你所有定义都能编译通过的唯一原因是你的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 *
。
%p
打印指针地址。然后,您可以将指针增加1
并查看指针移动了多少字节 :) - mmirzadehprintf("ptr = %p\tshifted_ptr = %p\n", (void*)array, (void*)(array+1))
- mmirzadeh