C字符数组与C字符指针的初始化方式有何不同?

6
下面这段代码被gcc 6.3版本认为是有效的C语言代码:
char white[] = { 'a', 'b', 'c' };
char blue[]  = "abc";
char *red    = "abc";

然而,以下操作失败了:
 char *green = { 'a', 'b', 'c' };   // gcc error

我相信这种情况肯定有合理的原因,但我想知道是什么。这个问题是由于初始化字节数组时(所以是无符号的char而不是char),很容易写出类似于 { '\x43', '\xde', '\xa0' } 而不是 "\x43\xde\xa0",一旦你忘记写my_array[]而不是*my_array,你就会被编译器抓住。

5
你对“white”的定义与另外两个不相同,因为它缺少字符串末尾的空终止符(\0)。 - abelenky
@abelenky 哦,是的,这是一个我忽略了的好点子,谢谢你。 - Sven Williamson
尝试使用char *green = { "a", "b", "c" };.... ;) - LPs
2个回答

9
以下内容将会产生错误。
char *green = { 'a', 'b', 'c' };

由于 green 的初始化器不是您所认为的字符数组。它没有类型,只是括号括起来的初始化列表。它在前面的示例(即 white)中初始化的事物决定了它的解释方式。相同的初始化程序可用于初始化任何能够容纳 3 个字符的聚合体。
但是,green 是一个指针,不是一个聚合体,因此您不能使用大括号括起来的初始化器列表作为其初始值。现在,以下两个结果都可以,但语义上非常不同:
char blue[]  = "abc";
char *red    = "abc";

blue 是一个数组。它将保存与文字字面量 "abc" 相同的内容。而 red 是一个指针,指向文字字面量 "abc"


  1. You can use a compound literal expression:

    char *green = (char[]){ 'a', 'b', 'c' };
    

    It tells the compiler to create an unnamed object (the life time of which depends on the scope of the declaration), that is of character array type and is initialized with those three characters. The pointer is then assigned the address of that object.


非常正确。然而,如果答案展示如何通过将初始化列表更改为char数组字面量(而不是字符串字面量),并讨论这样做的意义,那么答案会更好。 - John Bollinger
@JohnBollinger - 我刚刚在输入有关复合字面量的信息。 - StoryTeller - Unslander Monica
@StoryTeller 非常感谢您的帮助。 - Sven Williamson

6

这三项声明:

char white[] = { 'a', 'b', 'c' };
char blue[]  = "abc";
char *red    = "abc";

它们是不同的。

第一个声明了一个字符数组,该数组包含与初始值化程序的数量完全对应的三个字符。

第二个声明了一个四个字符的字符数组,因为它是由一个包括终止零的四个字符的字符串字面量进行初始化的。所以这个字符数组包含一个字符串。

第三个定义了一个字符串字面量,它是一个字符数组,并声明了一个类型为char *的指针,该指针由与字符串字面量相对应的字符数组的第一个字符的地址进行初始化。

你可以将此声明想象成

char unnamed = { 'a', 'b', 'c', '\0' };
char *red = unnamed;

这个声明
char *green = { 'a', 'b', 'c' };   

此处无效,因为左侧对象是标量,不可以用包含一个以上初始化程序的列表进行初始化。

请注意,您可以使用复合字面值来初始化指针。例如

char *green = ( char[] ){ 'a', 'b', 'c' };   

非常感谢。 - Sven Williamson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接