下面显示的两个代码都给出相同的输出,即** a和* a(在printf
中)。为什么会这样?
我对多维数组不是很好,我尝试了各种博客来理解,但仍然失败。我不明白两种情况下的输出如何相同。预先谢谢你。
两种情况的输出都是 abcdefghijklm
// CODE 1
int main()
{
char a[2][3][3] = {'a','b','c','d','e','f','g',
'h','i','j','k','l','m'};
printf("%s ", **a);
return 0;
}
///代码2
int main() {
char a[2][3][3] = {'a','b','c','d','e','f','g',
'h','i','j','k','l','m'};
printf("%s ", *a);
return 0;
}
答案 0 :(得分:0)
这很有趣。
请记住,数组元素是连续布置的-a
在内存中看起来像这样:
+---+
a: |'a'| a[0][0][0]
+---+
|'b'| a[0][0][1]
+---+
|'c'| a[0][0][2]
+---+
|'d'| a[0][1][0]
+---+
|'e'| a[0][1][1]
+---+
|'f'| a[0][1][2]
+---+
|'g'| a[0][2][0]
+---+
|'i'| a[0][2][1]
+---+
|'j'| a[0][2][2]
+---+
|'k'| a[1][0][0]
+---+
|'l'| a[1][0][1]
+---+
|'m'| a[1][0][2]
+---+
| 0 | a[1][1][0]
+---+
| 0 | a[1][1][1]
+---+
...
由于您提供的初始化程序数量少于数组可容纳的大小(12对18),因此其余元素被初始化为0(这在以后很重要)。
首先,介绍一些数组背景:
除非它是sizeof
或一元&
运算符的操作数,否则它是用于在声明中初始化类型为 expression 的声明中的字符数组的字符串文字。 “ T
的N个元素数组将被转换(“衰减”)为“指向T
的指针”类型的表达式,并且该表达式的值将是该元素的第一个元素的地址数组。
数组下标操作a[i]
被定义为*(a + i)
-给定起始地址a
,偏移量i
元素(不是字节!),然后取消引用结果。这意味着*a == *(a + 0) == a[0]
。
那么,这如何适用于您的代码?
表达式 a
的类型为“ char
的3元素数组的3元素数组的2元素数组。如果a
不是sizeof
或一元&
运算符的操作数,则该表达式“衰减”以键入“指向{{1}的3元素数组的3元素数组的指针” }”,表达式的值是数组第一个元素的地址-char
。
表达式&a[0]
解引用该指针,并且表达式的类型为“ *a
的3元素数组的3元素数组”。同样,此表达式不是char
或一元sizeof
操作数的操作数,因此它被转换为“指向&
的3元素数组的指针”,其值是地址数组第一个元素的值,即char
。从&(*a)
开始,这也可以视为*a == a[0]
。
表达式&a[0][0]
取消引用**a
(其类型为“指向*a
的3元素数组的指针”)的结果,表达式的类型为“ 3元素char
的数组”。同样,此表达式不是char
或一元sizeof
运算符的操作数,因此它会“拒绝”键入“指向&
的指针”。
巧合的是char
所期望的。 %s
转换说明符希望其自变量具有类型%s
,并指向字符序列中的第一个,后跟一个0值的终止符。还记得我之前说过数组的其余6个元素将初始化为0吗?也许毫无意义,您已经在<{1}中存储了 string 。
因此,这就是获得char *
的输出的原因。但是a
为什么也能工作?
数组的地址与数组的第一个元素的地址-**a
相同(您可以从上面的ASCII文字中看到)。 *a
的 类型是错误的-是&a[0] == &a[0][0] == &a[0][0][0]
而不是*a
-因此严格来说,行为是不确定的,但其 value (至少其逻辑值)与char (*)[3]
相同。不同的指针类型可能具有不同的表示形式,因此可能存在一个平台,其中char *
的表示形式可能与**a
的表示形式不同,从而使此代码无法正常工作。但是,在类似char (*)[3]
的平台上,所有指针类型都具有相同的表示形式,因此char *
的值与x86
的值的解释方式相同。