对于固定大小的数组和可变修改的数组,观察到的行为是相同的:
#include <stdio.h>
int main(void)
{
enum { m = 3, n = 4 };
int a[m][n];
int (*p)[m][n] = &a;
printf("p : %p, *p : %p, **p : %p\n", p, *p, **p);
return(0);
}
在我的机器上,这产生了:
p : 0x7fff6c542520, *p : 0x7fff6c542520, **p : 0x7fff6c542520
当然,p
是指向两个程序中的二维数组的指针(我不会再次添加“在两个程序中”限定符,即使它适用)。当您打印时p
,您将获得分配给它的数组的地址,即a
. 因为p
is 指向 2D 数组的指针,所以*p
'is' 2D 数组,但在大多数情况下,数组引用变成指向其第一个元素*p
的指针,指向 的指针也是如此a[0]
,它与引用位于相同的内存位置a
。类似地,**p
“是”一维数组,但类似地,**p
是指向 的指针a[0][0]
,它也是与a
引用相同的内存位置。因此,这三个值应该是相同的,并且编译器是正确的。
这并不容易阅读,但是它试图解释的 C 也不是。
这是原始程序的一个小变化,它说明了和指向的不同对象的p
大小:*p
**p
#include <stdio.h>
int main(void)
{
enum { m = 3, n = 4 };
int a[m][n];
int (*p)[m][n]=&a;
printf("p+0 : %p, (*p)+0 : %p, (**p) + 0 : %p\n",
(void *)(p+0), (void *)((*p)+0), (void *)((**p)+0));
printf("p+1 : %p, (*p)+1 : %p, (**p) + 1 : %p\n",
(void *)(p+1), (void *)((*p)+1), (void *)((**p)+1));
return(0);
}
严格来说,%p
应该给转换规范一个void *
; 这里的演员强制执行这一点。官方来说,原始代码有点草率,尽管很少有机器会影响它。
输出是:
p+0 : 0x7fff63453520, (*p)+0 : 0x7fff63453520, (**p) + 0 : 0x7fff63453520
p+1 : 0x7fff63453550, (*p)+1 : 0x7fff63453530, (**p) + 1 : 0x7fff63453524
请注意指向的对象的大小是如何不同的,如+1
版本所示:
sizeof(*p) = 0x30
sizeof(**p) = 0x10
sizeof(***p) = 0x04