int a[3][3]={5};
printf("&a = %u \n a = %u \n*a = %u\n&a[0][0]=%d\na[0][0]", &a, a, *a, &a[0][0], a[0][0]);
输出:-
&a = 2359028
a = 2359028
*a = 2359028
&a[0][0]=2359028
a[0][0] =5
这些怎么可能都一样?如果 a=2359028 的值,那么不应该*a
在地址 2359028 即 5 处给出值吗?
&a
给你数组的地址。它的类型int (*)[3][3]
。简单的。
a
表示数组本身,并将进行数组到指针的转换,成为指向数组第一个元素的指针。数组的第一个元素是一个类型为 的子数组int[3]
,所以我们得到一个指向该子数组的指针。该指针的类型为int (*)[3]
。这与以前的地址相同,因为第一个子数组位于数组的开头。
使用*a
,数组再次进行数组到指针的转换,以获得与以前相同的指向子数组的指针。然后取消引用以获取子数组本身。然后这个表示子数组的表达式也进行数组到指针的转换,给你一个指向它的第一个元素的指针。第一个元素是 type int
,所以指针是 type int*
。第一个元素的地址与它所在的子数组的地址相同,正如我们所见,它与整个数组的地址相同。
&a[0][0]
首先获取第一个子数组的第一个元素,然后获取它的地址。这为您提供了与前一点完全相同的指针。
因此,所有这些指针都具有相同的值。
图解:
0,0 0,1 0,2 1,0 1,1 1,2 2,0 2,1 2,2
┌─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┬─────┐
│ int │ int │ int │ int │ int │ int │ int │ int │ int │
└─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┴─────┘
└─────────────────────────────────────────────────────┘
&a points at the entire array
└─────────────────┘
a gives you a pointer to the first subarray
└─────┘
*a gives you a pointer to the element 0,0
and so does &a[0][0]
这些区域都从相同的地址开始,因此指针具有相同的值。
“......不应该 *a 在地址 2359028 即 5 处给出值吗?”
是和不是。*a
确实应该在 address给你对象a
。但是,在您的情况下a
有 type int[3][3]
。这意味着在这个间接级别上,地址处的对象a
(如果我们将其解释a
为指针)并不5
像您错误地认为的那样,它实际上是整个一维数组a[0]
。*a
is的类型int [3]
和存储的值*a
同样是整个 1D subarray a[0]
。
因此,当您尝试 时printf
*a
,实际上是在将整个a[0]
子数组指定为参数。该子数组衰减为指针,该指针自然指向相同的位置(因为整个数组a
及其第一个子数组a[0]
在内存中具有相同的位置)。这就是为什么打印a
和*a
as 指针(以及&a
)会导致打印相同的数值。
如果你想5
在这种情况下访问,你必须这样做**a
。只是*a
还不够。
在 C 语言中,当数组涉及到表达式时(例如,当传递给函数或指针算术时),它会隐式转换为指针。因为您要传递a
到printf
,所以它被隐式转换为指向 的指针a
,这与&a
.
*a
您可能会对看起来像相对于 的双重取消引用的事实感到困惑&a
,它返回了数组的地址,因此*a
这种逻辑应该导致a[0][0]
. 但事实并非如此。