我在网上的某个地方找到了这段代码。该程序的输出是 串 串 串 有人可以解释一下为什么第一个secon和第三个printf语句打印相同的输出,即使它们的参数不同?
#include<stdio.h>
int main()
{
char a[2][3][3] = {'s','t','r','i','n','g'};
printf("%s\n", *a);
printf("%s\n", a);
printf("%s\n", **a);
getchar();
return 0;
}
答案 0 :(得分:8)
由于这是三维数组(数组数组的数组),*a
,a
和**a
都引用相同的地址。对于前两个类型,printf()
的类型不正确,但在所有情况下都将被解释为平坦的char *
字符串。如果你打开编译器上的警告,你应该看到一些格式字符串和类型不匹配。
请注意,*a
与a[0]
类似,**a
与a[0][0]
类似。这可能会让他们更容易理解为什么他们引用相同的地址。
答案 1 :(得分:2)
您将char (*)[3]
和char (*)[3][3]
视为char *
。由于它们指向相同的地址,并且(在这种情况下)它们具有相同的内存中表示,因此它们的读取方式与指向该地址的char *
相同。
这是未定义的行为;不要这样做。
答案 2 :(得分:1)
让我们了解char a[2][3][3]
在内存中的排列方式。在我的机器上它是这样的:
0x7fffffffe220: 0x73 0x74 0x72 0x69 0x6e 0x67 0x00 0x00
0x7fffffffe228: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
0x7fffffffe230: 0x00 0x00
它很自然,因为所有数组实际上都是线性的。这些维度的含义对a[i][j][k]
等数组索引很方便。但从内存的角度来看,它只是一种从基地址计算偏移量的棘手方法。
现在因为你已经将它定义为三维数组,你可能想知道C在初始化后如何处理这个数组:
{{{0x73, 0x74, 0x72}, {0x69, 0x6e, 0x67}, {0x0, 0x0, 0x0}}, {{0x0, 0x0, 0x0}, {0x0, 0x0, 0x0}, {0x0, 0x0, 0x0}}}
现在让我们看看我们在这里有什么......
调用Printf来打印刺痛并传递地址。那么printf会做什么,就是抓住那个地址,然后尝试直到它看到空
对print
的每次调用都是一样的,因为:
(gdb) x/10xb **a
0x7fffffffe220: 0x73 0x74 0x72 0x69 0x6e 0x67 0x00 0x00
0x7fffffffe228: 0x00 0x00
(gdb) x/10xb *a
0x7fffffffe220: 0x73 0x74 0x72 0x69 0x6e 0x67 0x00 0x00
0x7fffffffe228: 0x00 0x00
(gdb) x/10xb a
0x7fffffffe220: 0x73 0x74 0x72 0x69 0x6e 0x67 0x00 0x00
0x7fffffffe228: 0x00 0x00
最后一句建议,就是这样编码。如果你足够聪明,只需按指针做一切。但它更容易出错。因此,虽然底层将几乎可以互换地处理指针和数组,但是你坚持使用你已经开始的东西。如果可以用手操纵东西,可以像指针一样处理。如果你想通过索引进行更严格的操作,可以对待像数组这样的东西。