我对这两个表达式有点困惑:(arry+i)
和*(arry+i)
在二维数组中,两个表达式都给出相同的输出,即数组第 i 个元素的地址。
为什么会这样,*(arry+i)
不应该指出第 i 个元素的值而不是第 i 个地址。
main() {
int arry[3][4] = { 1, 2, 3, 4,
4, 3, 2, 8,
7, 8, 9, 0
};
printf("%un", arry + 1);
printf("%un", *(arry + 1));
};
输出结果为:
2346225936 2346225936
正如我所期望的那样:
2346225936 四
如果你有一个二维数组声明如下
T a[M][N];
其中,当表达式( a + i )
具有T( * )[N]
类型并指向数组的第 i 个"行"时,T
是某种类型。
表达式*( a + i )
(即取消引用上面所示类型的指针)生成指向的"行"的左值,该值是类型T[N]
的数组。在表达式中使用,数组指示符被转换为指向其第一个元素的指针。在这种情况下,数组将转换为类型T *
。
因此,T ( * )[N]
和T *
类型的两个指针都指向容纳第 i 个"行"的相同内存范围的开头。也就是说,指针的值彼此相等,但指针本身具有不同的类型。
造成混淆的原因确实有多种:
-
arry
定义为 3 个数组的数组,每个数组 4 个int
。初始值设定项的可读性更强,如下所示:int arry[3][4] = { { 1, 2, 3, 4 }, { 4, 3, 2, 8 }, { 7, 8, 9, 0 } };
arry
是此 2D 数组的名称,它不同于指向数组的指针。它的类型是int[3][4]
.导致混淆的原因是数组自动转换为指向其第一个元素的指针,每当它们在表达式中使用或作为函数参数传递时,都会隐式发生。(此规则的极少数例外:数组用作sizeof()
和_Alignof()
的参数时不会转换。
-
arry + 1
是这种转换的一个例子:arry
被隐式转换为指向其第一个元素的指针,&(arry[0])
,该元素的类型为int (*)[4]
,指向 4 个整数数组的指针。向其添加1
会提供一个指向 2D 数组下一个元素的指针,&(arry[1])
具有相同类型的int (*)[4]
。若要打印此指针的值,应使用%p
并将表达式转换为指向void
的指针:printf("%pn", (void *)(arry + 1));
%u
需要一个unsigned int
,它可能具有不同的表示和参数传递约定,从而导致您的代码具有未定义的行为。
-
取消引用上述指针,
*(arry + 1)
生成一个类型为int [4]
的 L 值,该值是arry + 1
指向的 4 个整数数组(作为&(arry[1])
更具可读性。如果int
的大小为4
字节,此数组可用作sizeof
和生成16
的参数,但将其传递给printf
会导致它转换为指向其第一个元素&(arry[1][0])
的指针。同样,您应该使用不同的语法来打印此地址:printf("%pn", (void *)(*(arry + 1)));
输出是相同的,因为数组及其第一个元素具有相同的地址,就像街道及其第一所房子具有相同的 GPS 坐标一样。
这是一个修改后的程序:
#include <stdio.h>
int main() {
int arry[3][4] = {
{ 1, 2, 3, 4 },
{ 4, 3, 2, 8 },
{ 7, 8, 9, 0 }
};
printf(" arry -> %-16p %sn", (void *)(arry), "the address of the 2D array");
printf(" sizeof(arry) -> %-16zu %sn", sizeof(arry), "the size of the 2D array");
printf(" arry+0 -> %-16p %sn", (void *)(arry+0), "the value of a pointer to row 0");
printf(" sizeof(arry+0) -> %-16zu %sn", sizeof(arry+0), "the size of a pointer to row 0");
printf(" *(arry+0) -> %-16p %sn", (void *)(*(arry+0)), "the address of row 0");
printf(" sizeof(*(arry+0)) -> %-16zu %sn", sizeof(*(arry+0)), "the size of row 0");
printf(" arry[0] -> %-16p %sn", (void *)(arry[0]), "the address of row 0");
printf(" sizeof(arry[0]) -> %-16zu %sn", sizeof(arry[0]), "the size of row 0");
printf(" &arry[0][0] -> %-16p %sn", (void *)(&arry[0][0]), "the value of a pointer to row 0, col 0");
printf("sizeof(arry[0][0]) -> %-16zu %sn", sizeof(arry[0][0]), "the size of the array element at 0,0");
printf(" arry[0][0] -> %-16d %sn", arry[0][0], "the value of the array element at 0,0");
printf("n");
printf(" arry+1 -> %-16p %sn", (void *)(arry+1), "the value of a pointer to row 1");
printf(" sizeof(arry+1) -> %-16zu %sn", sizeof(arry+1), "the size of a pointer to row 1");
printf(" *(arry+1) -> %-16p %sn", (void *)(*(arry+1)), "the address of row 1");
printf(" sizeof(*(arry+1)) -> %-16zu %sn", sizeof(*(arry+1)), "the size of row 1");
printf(" arry[1] -> %-16p %sn", (void *)(arry[1]), "the address of row 1");
printf(" sizeof(arry[1]) -> %-16zu %sn", sizeof(arry[1]), "the size of row 1");
printf(" &arry[1][0] -> %-16p %sn", (void *)(&arry[1][0]), "the value of a pointer to row 1, col 0");
printf("sizeof(arry[1][0]) -> %-16zu %sn", sizeof(arry[1][0]), "the size of the array element at 1,0");
printf(" arry[1][0] -> %-16d %sn", arry[1][0], "the value of the array element at 1,0");
return 0;
}
输出:
arry -> 0x7fff512997c0 2D 数组的地址 sizeof(arry) -> 48 2D 数组的大小 arry+0 -> 0x7fff512997c0指向第 0 行的指针的值 sizeof(arry+0) -> 8 指向第 0 行的指针的大小 *(arry+0) -> 0x7fff512997c0第 0 行的地址 sizeof(*(arry+0)) -> 16 行 0 的大小 arry[0] -> 0x7fff512997c0第 0 行的地址 大小(Arry[0]) -> 16 行 0 的大小 &arry[0][0] -> 0x7fff512997c0指向第 0 行、列 0 的指针的值 sizeof(arry[0][0]) -> 4 数组元素的大小为 0,0 arry[0][0] -> 1 数组元素的值为 0,0 arry+1 -> 0x7fff512997d0指向第 1 行的指针的值 sizeof(arry+1) -> 8 指向第 1 行的指针的大小 *(arry+1) -> 0x7fff512997d0第 1 行的地址 sizeof(*(arry+1)) -> 16 第 1 行的大小 Arry[1] -> 0x7fff512997d0第 1 行的地址 sizeof(arry[1]) -> 16 第 1 行的大小 &arry[1][0] -> 0x7fff512997d0指向第 1 行 col 0 的指针的值 sizeof(arry[1][0]) -> 4 数组元素的大小为 1,0 arry[1][0] -> 4 数组元素的值为 1,0
如您所见,arry
、arry[0]
和arry[0][0]
的地址是相同的,指针的值是相同的,&arry
、&arry[0]
和&arry[0][0]