我试图理解为什么以下代码是非法的:
int main ()
{
char *c = "hello";
c[3] = 'g'; // segmentation fault here
return 0;
}
遇到char *c = "hello";
时编译器在做什么?
我理解它的方式,它是一个自动的char数组,而c
是指向第一个char的指针。如果是这样,c[3]
就像*(c + 3)
,我应该可以进行分配。
只是想了解编译器的工作方式。
答案 0 :(得分:9)
字符串常量是不可变的。您无法更改它们,即使您将它们分配给char *
(因此请将它们分配到const char *
,这样您就不会忘记)。
要详细了解一下,您的代码大致相当于:
int main() {
static const char ___internal_string[] = "hello";
char *c = (char *)___internal_string;
c[3] = 'g';
return 0;
}
这个___internal_string
通常被分配给只读数据段 - 任何改变数据的尝试都会导致崩溃(严格来说,其他结果也可能发生 - 这是'未定义行为的一个例子' “)。但是,由于历史原因,编译器允许您分配给char *
,给您错误的印象,您可以修改它。
请注意,如果您这样做,它将起作用:
char c[] = "hello";
c[3] = 'g'; // ok
这是因为我们正在初始化一个非const字符数组。虽然语法看起来很相似,但编译器会对它进行不同的处理。
答案 1 :(得分:7)
这些之间存在差异:
char c[] = "hello";
和
char *c = "hello";
在第一种情况下,编译器在堆栈上为6个字节分配空间(即5个字节用于“hello”,1个用于空终止符。
在第二种情况下,编译器在全局区域(也称为字符串文字)中生成一个名为“hello”的静态const字符串,并在堆栈上分配一个指针,该指针被初始化为指向该const字符串。
您无法修改常量字符串,这就是您遇到段错误的原因。
答案 2 :(得分:1)
您无法更改字符串文字的内容。你需要复制一份。
#include <string.h>
int main ()
{
char *c = strdup("hello"); // Make a copy of "hello"
c[3] = 'g';
free(c);
return 0;
}