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=]";
,这样编译器就会阻止您搬起石头砸自己的脚。
我是 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=]";
,这样编译器就会阻止您搬起石头砸自己的脚。