在char数组声明中,将字符串字面量放在大括号中是否有效?(例如,char s [] = {"Hello World"})

51

无意中发现这行代码 char s[] = {"Hello World"}; 能够正确编译,而且似乎与 char s[] = "Hello World"; 的处理方式相同。但是第一个声明 ({"Hello World"}) 不是包含一个 char 数组元素的数组吗?因此 s 的声明不应该写成 char *s[] 吗?实际上,如果我把它改成 char *s[] = {"Hello World"}; 编译器也能够像预期的那样接受。

在寻找答案时,我唯一找到提到这个问题的地方是 这里,但没有引用标准。

所以我的问题是,为什么这行代码 char s[] = {"Hello World"}; 能够编译通过,虽然左边的类型是 char 数组,而右边的类型是 char 数组的数组

以下是一个可工作的程序:

#include<stdio.h>
int main() {
    char s[] = {"Hello World"};
    printf("%s", s); // Same output if line above is char s[] = "Hello World";
    return 0;
}

感谢任何澄清。

附言:我的编译器是gcc-4.3.4。


我几个月前发布了一个类似的问题:https://dev59.com/7V3Ua4cB1Zd3GeqP8wt6 - Antoine
6个回答

65

这是允许的,因为标准规定如此:C99 第6.7.8节第14条:

字符类型数组可以通过字符字符串字面值初始化,可选地包含在大括号中。 字符字符串字面值的连续字符(如果有空间或数组大小未知,则包括终止空字符)初始化数组的元素。

这意味着两者都可以:

char s[] = { "Hello World" };

并且

char s[] = "Hello World";

只不过是语法糖的另一种表现形式。

char s[] = { 'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd', 0 };

顺带一提(同一部分,§11),C语言还允许在标量初始化器周围加上大括号,如下:

int foo = { 42 };

顺便提一下,这恰好符合复合字面量的语法。

(int){ 42 }

3
几乎相同的文本出现在C++2003的8.5.2条款中。 - Robᵩ
2
使用多余的大括号来初始化标量对象的能力也支持 C 语言中的“通用零初始化器”习惯用法,其中 = { 0 } 可以用于将几乎 任何 类型的对象初始化为零。 - AnT stands with Russia
一般来说,花括号只是将其中包含的所有语句组合成一个大语句。这就是为什么在单行 if 分支(或者 while 等)中不需要 { }。编译器只需在 if 后查找 下一条语句 并根据条件执行它。因此,如果您想要两个语句,请使用花括号将它们括起来,使它们看起来像一个语句。 - dcow
3
@DavidCowden说的不正确。a = (x = 1, y = 2, z = 3);会将a设置为3,而不是1 - Nawaz
3
在初始化的上下文中,{}的使用与它们在复合语句语法中的使用完全无关。 - AnT stands with Russia
显示剩余4条评论

22
大括号是可选的,表达式等同于一个字符数组。

你也可以这样写:

 int a = {100}; //ok

演示:http://ideone.com/z0psd

实际上,C++11将这种语法进行了推广,以便统一初始化非数组及数组。因此在C++11中,您可以使用以下语法:

int a{}; //a is initialized to zero, and it is NOT an array

int b[]{1,2,3,4}; //b is an array of size 4 containing elements 1,2,3,4

int c[10]{}; //all 10 elements are initialized to zero

int *d{}; //pointer initialized to nullptr

std::vector<int> v{1,2,3,4,5}; //vector is initialized uniformly as well.

4

任何类型的变量(如intchar等)都可以看作是长度为1的数组。

char s = {0};

同样也适用于这里。


2

我可能错了,但我认为这不是一个字符数组的数组,而是一个包含字符数组的块。 int a = {1}; 也可以起作用。


1
这也符合C++标准,引用如下:

[dcl.init.string] §1

窄字符类型([basic.fundamental])、char16_t数组、char32_t数组或wchar_t数组可以通过窄字符串字面值、char16_t字符串字面值、char32_t字符串字面值或宽字符串字面值进行初始化,或者通过用大括号括起来的适当类型的字符串字面值进行初始化([lex.string])。[snip]


1
实际上,如果我把它改成 char *s[] = {"Hello World"}; 编译器也会接受,正如预期的那样。编译器接受它是因为你实际上创建了一个未定义大小元素的二维数组,在其中只存储了一个元素,即 "Hello World" 字符串。就像这样:
char* s[] = {"Hello world", "foo", "baa" ...};

在这种情况下,您不能省略括号


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