2012-07-26 81 views
1

我在网上找到了这段代码。该程序的输出是 字符串 字符串 字符串 有人可以请解释我为什么第一个secon和第三个printf语句打印相同的输出,即使他们的参数不同?c程序输出说明

#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

@chris数组的总大小为18,初始化为6个元素,所有后面的元素都是'0'。 – ecatmur 2012-07-26 13:52:46

+0

@chris我知道。但是我没有在网上发现自己编写的代码。 – Prateek 2012-07-26 13:54:39

+0

@ecatmur,哎呀,没错。出于某种原因,我认为所有的元素都被设置了。 – chris 2012-07-26 13:54:42

回答

8

由于这是3维阵列,*aa(数组的数组的数组),和**a都指的是相同的地址。前两种的printf()类型不正确,但在所有情况下,它将被解释为平坦的char *字符串。如果您在编译器上显示警告,则应该看到一些关于格式字符串和类型不匹配的信息。

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

2

您正在将char (*)[3]char (*)[3][3]视为char *。由于它们指向相同的地址,并且(在这种情况下)它们具有相同的内存中表示,所以它们被读取为与指向该地址的char *相同。

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

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被调用来打印一个sting并传递一个地址。那么,什么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 

最后一个忠告,做这样编码。如果你足够聪明,就单单用指针来做每件事。但它更容易出错。因此,虽然底层将几乎可以互换地处理指针和数组,但您坚持使用开始的内容。如果可以用手操纵东西,就像指针一样处理。如果你想通过索引进行更严格的操作,就像处理数组一样处理。