将字符串文字与数组分配给char

assigning string literal vs array to char

我有一个 char pointer 和这样的字符串文字 char *d="abc"; 我正在递增它

*(d+1)

如果我这样做 printf("%c",*(d+1))

我会得到类似 b 的东西

但是当我有这些行时

char *c={'a','b','c'}
printf("%c\n",*(c+1)); /// CAUSES SegFault

以上行抛出异常。当我尝试使用 gdb 进行回溯和打印 *(c+1) 时,它说 = 0x61 <error: Cannot access memory at address 0x61>

所以我的问题是为什么这与我将字符串文字分配给 char pointer

时相比不起作用

当我将 int 的数组分配给 int pointer 并以这种方式递增它时,也会发生同样的情况

非常感谢@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,摘录如下:

scalar types: arithmetic types and pointer types

指针恰好是标量类型,因为它只能保存 1 个值,即地址。所以编译器将只使用 'a' 来初始化 c 因为 c 只能保存 1 个值,并忽略其他所有内容(因为再次,scalar) . 'a' 的十六进制 ASCII 值是多少? 61,与 GDB 指出的地址完全相同。希望您了解现在发生的事情:

  • 当编译器看到char *c = {'a', 'b', 'c'};时,它会将聚合初始值设定项视为标量初始值设定项,因为c是一个标量变量,所以只取'a'并告诉你放了 2 个额外的字符。

  • 'a',一个 int 文字,被隐式转换为 char * 并成为一个地址。编译器也会对此发出警告。

  • 您尝试打印 *(c + 1),但由于这是无效的 address/you 不允许触及该地址,因此发生段错误。


我认为您真正想要做的是将 c 视为一个数组。为此,您可以将 c 的类型更改为数组:

char c[] = {'a', 'b', 'c'};

或者将 c 保留为 char * 并使用复合文字:

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

但是,char *c = {'a', 'b', 'c'}; 不是有效的 C,因为用大括号括起来的标量初始值设定项只允许包含 1 个表达式。 Vlad 的回答给出了证明这一点的标准的具体引用。使用 -pedantic-errors 编译此代码会将此处提到的所有警告替换为错误。

您忘记放置分号的声明

char *c={'a','b','c'};
                   ^^^^

在 C 中不是有效的构造。您不能使用包含多个初始化器的花括号列表来初始化标量对象。

来自C标准(6.7.9初始化)

11 The initializer for a scalar shall be a single expression, optionally enclosed in braces. The initial value of the object is that of the expression (after conversion); the same type constraints and conversions as for simple assignment apply, taking the type of the scalar to be the unqualified version of its declared type.

因此编译器将发出错误消息,实际上没有什么可讨论的,因为您有一个无法成功编译的程序。

你可以这样写

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

在这种情况下,带有逗号运算符的表达式将用作初始化表达式。这个初始化相当于

char *c = { 'c'};

因此指针c由字符'c'的内码初始化。例如,如果使用 ASCII table 那么上面的初始化等同于

char *c = 99;

编译器应该再次发出一条消息,表明您正在尝试用整数初始化指针。

由于用作地址的值 99 未指向程序中的有效对象,因此该语句

printf("%c\n",*(c+1));

调用未定义的行为。

或者您可以使用例如复合文字来初始化指针c,如下面的演示程序所示

#include <stdio.h>

int main(void) 
{
    char *c = ( char [] ){ 'a', 'b', 'c' };
    printf( "%c\n", *(c+1) );
    
    return 0;
}

在这种情况下,您将获得预期的结果。与指向字符串文字的指针的唯一区别是指向字符串的指针在程序中 c 不指向字符串。但是你可以像

一样初始化它
    char *c = ( char [] ){ 'a', 'b', 'c', '[=16=]' };

它将指向一个字符串。