在ac字符串中更改一个char

yot*_*moo 8 c arrays

我试图理解为什么以下代码是非法的:

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)我应该能够完成作业.

只是想了解编译器的工作方式.

bdo*_*lan 9

字符串常量是不可变的.您无法更改它们,即使您将它们分配给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字符数组.虽然语法看起来很相似,但编译器会对它进行不同的处理.

  • +1表示*大致*...但在C中,字符串文字类型不是`const char [N]`("N"足够大).字符串文字实际上有类型`char [N]`但是未定义更改它们. (2认同)

Nat*_*man 8

这些之间有区别:

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字符串,这就是你得到段错误的原因.