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

C string assignment gives segmentation fault

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

这样写代码:

char *str = "geeksforgeeks[=10=]";

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

抛出分段错误。

但是如果我这样写代码:

char string[] = "geeksforgeeks[=11=]";
char *str = string;

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

程序运行正常。

还有这个代码:

char str[] = "geeksforgeeks[=12=]";

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

行为正确。

两者有什么区别?不应该是等价的吗?

char *str = "geeksforgeeks[=11=]";

此字符串分配在只读*内存中,您无法修改它。还有空终止符是多余的。

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

char *str = string;

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

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

原因很简单

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

char *str = "Test";

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

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

如果你有:

char *str = "geeksforgeeks[=10=]";

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

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

char str[] = "geeksforgeeks";

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

const char *str = "geeksforgeeks";

你发现了一些丑陋的遗留包袱。当您编写文字 "geeksforgeeks[=10=]" 时,编译器会将其转换为指向字符数组的指针。如果您稍后再次使用字符串 "geeksforgeeks[=10=]" ,则允许将两个引用指向同一个数组。这仅在您无法修改数组时才有效;否则,fputs(stdout, "geeksforgeeks[=12=]"); 将打印 aeeksforgeeks。 (Fortran 可以胜过这一点:在至少一个编译器上,您可以按名称将常量 1 传递给一个函数,将其设置为等于 -1,然后您的所有循环都会向后 运行 .) 另一方面,C 标准并没有说修改字符串文字 不会 起作用,并且有一些旧代码确实如此。这是未定义的行为。

当您分配一个数组来保存字符串时,您正在创建一个唯一的副本,并且可以对其进行修改而不会在其他地方引起错误。

那么为什么字符串文字不是 const char * 而不是 char *? C 的早期版本没有 const 关键字,标准委员会不想破坏那么多旧代码。但是,您可以而且应该将指向字符串文字的指针声明为 const char* s = "geeksforgeeks[=19=]";,这样编译器就会阻止您搬起石头砸自己的脚。