为什么在向字符串常量写入时,scanf无法按预期工作?

5
include<stdio.h>
int main()
{
    //char b[10];
    char *a="goodone";
    //a=b;

    scanf("%s",a);//this scanf fails and thow segmentation fault.
    printf("%s",a);

} 

为什么这个不起作用?我尝试了很多次,但是当我为我的变量a保留内存(通过将a=b赋值给a,已注释)时,它可以正常工作。否则就不行。 我认为char *a会为其字符串分配一些内存(“goodone”),并将该内存位置返回到其值。printf可以正常工作,为什么scanf不行? 请帮我解决这个问题....


我强烈建议阅读C FAQ entry来解决这个问题。 - Lundin
这绝对是一篇不错的阅读材料:char a[] = “string”; 和 char *p = “string”; 有什么区别? - Alok Save
2个回答

2
这是因为您正在指示scanf将其读取的数据写入分配给const char*值的内存中,即写入只读内存。
如果您想使您的字符串常量可写,请更改
char *a="goodone";

为了

char a[]="goodone";

请注意,这种方法也不安全:当用户输入超过七个字符时,它可能会崩溃。为了解决这个问题,请在您的格式说明符中添加一个限制。
scanf("%7s",a);

附注:被注释掉的a=b可以正常工作,因为它没有修改字符串常量,而是修改了指向字符常量的指针,这是被允许的。


2
为了强调这一点,永远不要使用裸的%s格式与scanf()一起使用。无论您提供多大的缓冲区,都无法防止用户输入足以使其溢出。这和gets()一样不安全(也永远不应该使用)。 - Keith Thompson
@KeithThompson,gets()函数从C11起不再是标准C。 - Lundin
@Lundin:是的 - 但大多数或所有的实现仍然提供它(可能会有警告),遗憾的是仍然有很多书籍和教程在使用它。 - Keith Thompson

2

char *a 只是一个指向 char 的指针。当你将 "goodone" 赋值给它时,它就指向了这个字符串常量(只读),而 scanf 尝试在内存中重写该字符串,导致程序崩溃。

如果你将 b 赋值给它,则 a 指向可写的 10 个 char 的内存区域(即最大长度为 9+ 结束空字符)。因此,只要 scanf 不存储超过这个长度的内容,它就可以正常工作。

同样地,你也可以将 a 声明为数组(即 char a[] = "goodone";)。但同样需要注意不要存储超过其大小限制的内容。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接