【问题标题】:Segmentation Fault while deferencing a char array取消引用 char 数组时出现分段错误
【发布时间】:2014-01-05 03:46:40
【问题描述】:
#include<stdio.h>
int main(void)
{
    char * p= "strings are good";
    printf("%s",*p);
    return 0;
}

有人可以告诉我为什么我在这里遇到分段错误吗?

【问题讨论】:

  • 用 '' 处理段错误,随机删除并添加 '' 直到它工作 - 它比真正的调试更快:)
  • @MartinJames:可能是这样,但它不是很有教育意义,IMO... PS:对 OP:const 是你的朋友。 char *p = "some string constant" 本质上与auto char *p = "some string constant"; 相同,后者又与const char *p = "some string constant"; 相同。写const,提醒自己p[2] = 'a';是不可能的事实

标签: c arrays char segmentation-fault


【解决方案1】:

有人可以告诉我为什么我在这里遇到分段错误吗?

C11:7.21.6 格式化输入/输出函数:

如果转换规范无效,则行为未定义。282) 如果任何参数不是相应转换规范的正确类型,则行为是 未定义。

3.4.3

1 未定义的行为 行为,在使用不可移植或错误的程序构造或错误数据时, 本国际标准对此没有要求。

2 注意 可能的未定义行为范围从完全忽略具有不可预测结果的情况,到在翻译或程序执行期间以环境特征的记录方式表现(无论是否发出诊断消息) ),终止翻译或执行(通过发出诊断消息)。

*p 的类型为 char%s 需要 char * 类型的参数。这将调用未定义的行为。在这种情况下,任何事情都可能发生。有时您可能会得到预期的结果,有时则不会。这也可能导致程序崩溃或分段错误(这里就是这种情况)。

对于%s,需要传递sting/literal的起始地址。

改变

printf("%s",*p);  

printf("%s",p);

【讨论】:

  • 我已经声明了一个指向“字符串很好”的指针 p,所以我应该尊重它以便正确访问它。??就像我会处理数字一样。??
  • @sidchelseafan 如果要取消引用指针(指向单个字符),请尝试 %c。 %s 可能希望你提供一个指针,而不仅仅是一个字符的值(这是你在取消引用时得到的)。
  • @sidchelseafan 您可能遇到了段错误,因为 printf 看到了 %s 并正在寻找读取数据,直到它到达一个标记字符串结尾的空值。然而,当你取消引用它时,你只给了它一个字符,所以它很可能读过了那个字符并爆炸了。
  • @hacks:不是这样的。只是:我认为 C 标准的精神更像是这样的:“当需要指针时,不应传递 char。如果程序员这样做,我们不会在任何情况下处理它方式:这是他/她的问题,而不是我们的问题”。 PHP 本来就是简单的,所以它会产生通知,但会帮助你。例如$undeclaredVar[] = 'Used as array'; 会产生一个通知,但 PHP 会将 var 初始化为一个数组并继续。如果你随后切换到更严格的语言,你就会开始意识到 PHP 让你变得多么懒惰
  • @hacks:我不会说你不应该。如果您来自 C 语言,那将很容易。有些事情会激怒你,有些事情会很有趣……我经常说 PHP 是一种事后思考和冗余设计的语言。功能刚刚加了,又加了,貌似不假思索,乱七八糟。还有很多懒人写PHP(懒得看半页文档)。这些是不好的部分。有趣的部分是:编写一个小脚本很快,它可以正确使用,如果你编写好的代码,它很容易阅读和维护
【解决方案2】:

问题来了:

printf("%s",*p);

printf 将解析const char * 格式字符串,在您的情况下为:"%s",并推断除格式之外的第一个参数也将是char *
现在,因为您取消引用指针,所以您传递了一个字符(char,没有*
现在,如果您将 char 的 size 与 char pointer 的大小进行比较:

printf("%d vs %d\n", sizeof(p), sizeof(*p));

您会看到 char 指针是 char 大小的 4 倍(或 64 位为 8 倍)。
考虑一下您实际上在做什么,即强制 printf 将 char 的值转换为指针,然后使用该指针读取字符串:

const char *p = "foobar";
printf("%p\nWhereas you wanted: %p\n", (void *) *p, (void *) p);

输出:

0x66 //not a valid pointer, too small
Whereas you wanted: 0x80485c8 //<-- actual address may vary

解决办法:

printf("%s\n", p);

不要取消引用指针,按原样传递。
一点小提示:学会爱上存储类修饰符const。在这种情况下,这是一个有用的提醒:

char *p;
//some code
p = "a string";
//more code, or passing p to a function that attempts to do:
p[0] = 'A';//ERROR!!

鉴于:

const char *p;//I can SEE p points to a constant
p = "a string";
p[0] = 'A';//error, the declaration of p tells me why

const 是一个视觉提醒,无论你要对p 做什么,你都应该记住它指向一个常量,并且值不能是已编辑。

【讨论】:

  • @Elias:非常感谢您的帮助。
【解决方案3】:

您在 printf 格式的输出中将单个字符作为字符串类型 (%s) 传递。 改成 p

【讨论】:

    猜你喜欢
    • 2011-05-20
    • 2021-10-24
    • 1970-01-01
    • 2017-02-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多