非常感谢@nielsen 指出这一点,在他们发表评论后一切都变得清晰起来。
首先,让我们尝试一个不会出现段错误的类似程序:
#include <stdio.h>
int main()
{
char *a = {'a', 'b', 'c'};
printf("%p\n", (void *) a);
}
对我来说,这输出:0x61
. 那应该敲响警钟,这与 GDB 给出的地址相同。
然而,更重要的是我收到的警告:
main.c:5:16: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
char *a = {'a', 'b', 'c'};
^~~
main.c:5:16: note: (near initialization for ‘a’)
main.c:5:21: warning: excess elements in scalar initializer
char *a = {'a', 'b', 'c'};
main.c:5:16: warning: initialization makes pointer from integer without a cast [-Wint-conversion]
char *a = {'a', 'b', 'c'};
^~~
main.c:5:16: note: (near initialization for ‘a’)
main.c:5:21: warning: excess elements in scalar initializer
char *a = {'a', 'b', 'c'};
main.c:5:21: warning: excess elements in scalar initializer
char *a = {'a', 'b', 'c'};
^~~
main.c:5:21: note: (near initialization for ‘a’)
main.c:5:26: warning: excess elements in scalar initializer
char *a = {'a', 'b', 'c'};
^~~
main.c:5:26: note: (near initialization for ‘a’)
initialization makes pointer from integer without a cast [-Wint-conversion]
已经在评论中指出。然而,随着另一个警告,这变得很清楚:
main.c:5:21: warning: excess elements in scalar initializer
char *a = {'a', 'b', 'c'};
^~~
main.c:5:21: note: (near initialization for ‘a’)
main.c:5:26: warning: excess elements in scalar initializer
char *a = {'a', 'b', 'c'};
基本上,这并不像你认为的那样。完全没有。这{}
是一个“标量”初始化程序。来自https://en.cppreference.com/w/c/language/type,摘录如下:
标量类型:算术类型和指针类型
指针恰好是标量类型,因为它只能保存 1 个值,即地址。因此编译器将仅用于'a'
初始化c
,因为c
只能保存 1 个值,而忽略其他所有内容(因为又是scalar)。十六进制的 ASCII 值是'a'
多少?61,与 GDB 指出的地址完全相同。希望您了解现在发生的情况:
当编译器看到char *c = {'a', 'b', 'c'};
时,它会将聚合初始值设定项视为标量初始值设定项,因为c
它是一个标量变量,因此只需要'a'
并告诉您放置 2 个额外字符。
'a'
,一个int
文字,被隐式转换为char *
并成为一个地址。编译器也会就此发出警告。
您尝试打印*(c + 1)
,但由于这是一个无效地址/您不允许触摸该地址,因此会发生段错误。
我认为您真正想要做的是将c
视为一个数组。为此,您可以将c
's 的类型更改为数组:
char c[] = {'a', 'b', 'c'};
或保留c
为 achar *
并使用复合文字:
char *c = (char []) {'a', 'b', 'c'};
但是,char *c = {'a', 'b', 'c'};
C 是无效的,因为大括号封闭的标量初始值设定项只允许保存 1 个表达式。弗拉德的回答给出了证明这一点的标准的具体引用。编译此代码-pedantic-errors
会将此处提到的所有警告替换为错误。