C字符串赋值给出了分段错误

时间:2015-12-01 19:33:41

标签: c c-strings

我是C的新手,我想执行此任务:声明并初始化一个字符串,然后将每个字符串元素重新分配给一个新值。

以这种方式编写代码:

char *str = "geeksforgeeks\0";

for (int i = 0; str[i] != '\0'; ++i) {
    str[i] = 'a';
}

引发分段错误。

但是如果我以这种方式编写代码:

char string[] = "geeksforgeeks\0";
char *str = string;

for (int i = 0; str[i] != '\0'; ++i) {
    str[i] = 'a';
}

程序行为正确。

此代码:

char str[] = "geeksforgeeks\0";

for (int i = 0; str[i] != '\0'; ++i) {
    str[i] = 'a';
}

行为正确。

两者有什么区别?不应该等同吗?

4 个答案:

答案 0 :(得分:5)

如果你有:

char *str = "geeksforgeeks\0";

字符串(通常)存储在只读内存中,当您尝试修改它时会出现分段错误。 (实际上不需要\0;字符串末尾有两个空字节。)

最简单的解决方法是使用数组而不是常量字符串(这基本上就是你在第二种工作情况下所做的):

char str[] = "geeksforgeeks";

请注意,您应该将此字符串用于字符串,因为字符串不可修改:

const char *str = "geeksforgeeks";

答案 1 :(得分:3)

  

char * str =“geeksforgeeks \ 0”;

此字符串在readonly *内存中分配,您无法修改它。空终结符也是多余的。

与您定义的数组不同,这就是它工作的原因。在数组的情况下,字符串文字被复制到数组所在的内存中 - 您可以修改该数组的内容。所以使用这个

char *str = string;

你指向数组的第一个元素 - 如上所述,它是可修改的(以及数组的所有元素)。

*它们可能不存储在只读存储器中,取决于平台。但无论如何你不能修改它们。

答案 2 :(得分:1)

原因很简单。

在第一个示例中,您有一个指向静态字符串的指针。这就是你得到分段错误的原因。

char *str = "Test";

这实际上是一个常量字符串。但在第二个例子中,它是一个你改变的变量。

// You have a variable here
char str_array[] = "Test";
// Now you have a pointer to str_array
char *str = str_array;

答案 3 :(得分:1)

你已经遇到了一些丑陋的传统行李。当您编写文字"geeksforgeeks\0"时,编译器会将其转换为指向字符数组的指针。如果稍后再次使用字符串"geeksforgeeks\0",则允许将两个引用指向同一个数组。这仅在您无法修改数组时有效;否则,fputs(stdout, "geeksforgeeks\0");将打印aeeksforgeeks。 (Fortran最重要的是:在至少一个编译器上,你可以将常量1按名称传递给函数,将其设置为-1,然后所有循环都会向后运行。)另一方面,C标准没有说修改字符串文字不会工作,并且有一些旧代码可以做到。这是未定义的行为。

当您分配一个数组来保存字符串时,您正在创建一个唯一的副本,并且可以修改该副本而不会在其他位置导致错误。

那么为什么不是字符串文字const char *而不是char *?早期版本的C没有const关键字,标准委员会也不想打破这么多旧代码。但是,您可以并且应该将指向字符串文字的指针声明为const char* s = "geeksforgeeks\0";,这样编译器就会阻止您在脚下拍摄自己。