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