微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

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

如何解决将字符串文字与数组分配给 char

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

*(d+1)

如果我执行 b,我会得到类似 printf("%c",*(d+1)) 的结果

但是当我有这些行

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

上面的行抛出异常。当我尝试使用 gdb 进行回溯并打印 *(c+1) 时,它说 $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','c'};                                                                                                                             
                ^~~                                                                                                                                         
main.c:5:16: note: (near initialization for ‘a’)                                                                                                            
main.c:5:21: warning: excess elements in scalar initializer                                                                                                 
     char *a = {'a','c'};

main.c:5:16: warning: initialization makes pointer from integer without a cast [-Wint-conversion]                                                           
     char *a = {'a','c'};

main.c:5:21: warning: excess elements in scalar initializer                                                                                                 
     char *a = {'a','c'};                                                                                                                             
                     ^~~                                                                                                                                    
main.c:5:21: note: (near initialization for ‘a’)                                                                                                            
main.c:5:26: warning: excess elements in scalar initializer                                                                                                 
     char *a = {'a','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','c'};

基本上,这并不像您认为的那样。在所有。 {} 是一个“标量”初始值设定项。来自 https://en.cppreference.com/w/c/language/type 的摘录:

标量类型:算术类型和指针类型

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

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

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

  • 您尝试打印 *(c + 1),但由于这是一个无效地址/您不能触摸该地址,因此发生了段错误。


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

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

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

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

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

,

这个你忘记加分号的声明

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

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

来自 C 标准(6.7.9 初始化)

11 标量的初始值设定项应为单个表达式, 可选用大括号括起来。 对象的初始值是 表达式的(转换后);同类型约束 和适用于简单赋值的转换,采用 标量是其声明类型的非限定版本。

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

你可以写例如

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

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

char *c = { 'c'};

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

char *c = 99;

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

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

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

调用未定义的行为。

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

#include <stdio.h>

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

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

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

它会指向一个字符串。

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。