char *s = "Hello"
char s[6] = "Hello"
以上任意一种语法都可以正常工作。
但是以下这种语法呢?
int a[3] = {1,2,3}
(这种方法非常好用)- 但为什么下面这种方法不行呢,
int *a = {1, 2, 3};
?
解释以及对比情况[2]和[4]将会很有帮助。
char *s = "Hello"
char s[6] = "Hello"
以上任意一种语法都可以正常工作。
但是以下这种语法呢?
int a[3] = {1,2,3}
(这种方法非常好用)int *a = {1, 2, 3};
?解释以及对比情况[2]和[4]将会很有帮助。
"Hello"
被替换成了字符串常量Hello的地址。因此,char *s = "Hello"
的意思是“将字符串常量Hello的地址分配给指针s
”。{1, 2, 3}
并不构成一个地址,也没有被替换。你不能给指针赋值除地址以外的任何东西,所以你不能写int *a = {1, 2, 3}
。无法工作的原因是初始化器的数据类型未定义。对于字符串文字,这是由语法隐式给出的。但是{1,2,3}
可以是数组、结构体或许多其他变体。
您必须指定数据类型:
int *ia = (int []){1,2,3};
这里使用了复合字面量(C99)。
需要注意的是这不仅适用于初始化,还可在普通代码中使用。
char *s="Hello"
这里,s
是一个指向 char
类型的指针,它指向字符串常量 "Hello"
的基地址。
char s[6]="Hello"
这里,s
是一个由 6 个 char
元素组成的数组,初始值为 H
,e
,l
,l
,o
和 \0
。
int a[3]={1,2,3}
这里,a
是一个由 3 个元素组成的 int
数组,其初始值为 1
,2
和 3
。
注意:上述三个示例都是合法的。
int *a={1,2,3}
是无效的。
这里,a
的类型是 int *
,而花括号中的列表并没有提供 int *
类型的值。因此,这不是一种定义行为,是无效的。
"Hello"
被称为 _字符串字面值_,它返回字面值的基地址。{1,2,3}
不是 int
字面值,它被称为 _花括号包含的初始化列表_。 - Sourav Ghosh"Hello"
返回一个 char *
,你可以将其放入另一个 char *
中,但 {1,2,3}
首先并不会返回一个 int *
。 - Sourav Ghosh{1, 2, 3}
这样的初始化器处理方式不同。像"Hello"
这样的字符串字面量是一个数组表达式,在大多数情况下,数组表达式会“衰减”为指针表达式。初始化器{1,2,3}
本身 不是一个数组表达式,因为语言定义是这样规定的。正如以下的余昊所指出的,(int[]){1,2,3}
(自C99起) 是 一个数组表达式,它会衰减为指针表达式,所以你可以写成 int *a = (int[]){1,2,3}
。 - John Bode不支持案例4而支持其他案例的原因是历史原因。这些因素包括早期有影响力的程序员和编译器供应商之间的游说和政治相互作用,而不是经过深思熟虑的技术决策。
因此,如果你正在寻找一个强有力的技术理由,你不会找到。
从历史上看,案例2和3在C语言的演变过程中早就得到了支持。你的案例2实现了与其他案例相同的效果。
char s[6] = {'H', 'e', 'l', 'l', 'o', '\0'};
对于除了char
类型以外的任何数组初始化,都没有与字符串字面量相对应的东西。
历史上,情况1是程序员引入的异常情况,他们想要实现的效果是
char s_temp[] = "Hello";
char *s = temp_s;
使用更少的键入(即作为一个单独的语句)。游说支持案例1最终获胜(它被引入主流编译器,后来成为标准)。案例1是标准中唯一的情况,其中指针可以直接使用数组初始化器进行初始化,而无需进行任何类型转换。
从历史上看,程序员从未要求或游说过案例4。
无论你喜不喜欢,这就是为什么支持案例1、2、3,但不支持案例4的原因。
案例2和案例4之间没有真正的比较,因为它们(试图)实现不同的功能。如案例2中的字符串字面值,是一个只适用于char
数组的数组初始化器 - 没有非char
类型的对应物。案例4试图使用数组初始化器初始化指针。
int *a = {1, 2, 3};
这段代码在语法上是不正确的,因为{1, 2, 3}
不能用于初始化指针。
但是稍作修改就可以使其正常工作:
int *a = (int []){1, 2, 3};
这是一个C99复合文字。
使用字符串初始化字符数组是一个特殊情况:char s[6] = "hello"
被视为代码 char s[6] = { 'h', 'e', 'l', 'l', 'o', '\0'};
。由于使用字符串初始化字符数组是一种常见情况,因此这种用法很有意义。
char s[6] = { 'h', 'e', 'l', 'l', 'o', '\0'};
会使它可写吗?我认为是的。 - Eregrithchar s[6] ="hello"
也是可写的。我的错误。 - Eregrith
int a[3] = {1,2,3};
这是数组的正常初始化语法。
char s[6] = "Hello";
这是一个特殊情况下的字符数组初始化语法,您可以在右侧写入字符串文字,它将扩展为上述正常初始化语法,即char s [6] = {'H','e','l','l','o','\ 0'};
char *s = "Hello";
这是标量变量的正常初始化语法,初始化为右侧的表达式。 在这里,"Hello"
是有效的C表达式。
int *a = {1, 2, 3};
这与(1)不同,因为{1, 2, 3}
不是有效的C表达式。