1

我在网上的某个地方找到了这段代码。程序的输出是 string string string 有人可以解释一下为什么第一个和第三个 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;
}
4

3 回答 3

8

由于这是 3 维数组(数组数组中的数组),所以*a, a, 和**a都指向同一个地址。前两个的类型不正确printf(),但在所有情况下都会被解释为扁平char *字符串。如果您在编译器上打开警告,您应该会看到一些关于格式字符串和类型不匹配的信息。

请记住,*a就像a[0]**a就像a[0][0]。这可能更容易理解它们为什么引用相同的地址。

于 2012-07-26T13:53:04.877 回答
2

您将 achar (*)[3]和 achar (*)[3][3]视为char *. 由于它们指向相同的地址,并且(在这种情况下)它们具有相同的内存表示,因此它们的读取方式与char *指向该地址的 a 相同。

这是未定义的行为;不要这样做。

于 2012-07-26T13:56:14.363 回答
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]. 但从内存的角度来看,这只是一种计算基地址偏移量的棘手方法。

现在因为您已将其定义为 3 维数组,您可能想知道 C 在初始化后将如何处理此数组:

{{{0x73, 0x74, 0x72}, {0x69, 0x6e, 0x67}, {0x0, 0x0, 0x0}}, {{0x0, 0x0, 0x0}, {0x0, 0x0, 0x0}, {0x0, 0x0, 0x0}}}

现在让我们看看我们这里有什么......

调用 Printf 以打印字符串并通过地址传递。所以 printf 会做的是获取那个地址,并尝试直到它看到一个 null

每次调用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

最后一句忠告,这样做编码。如果您足够聪明,请仅凭指针做所有事情。但它更容易出错。因此,尽管底层将几乎可以互换地处理指针和数组,但你还是坚持你已经开始的。如果可以用手操作东西,请处理指针之类的东西。如果您想通过索引进行更严格的操作,请处理数组之类的东西。

于 2012-07-26T14:17:46.617 回答