15

所以我有以下程序:

int main(){
  char* one = "computer";
  char two[] = "another";
  two[1]='b';
  one[1]='b';
  return 0;
}

它在“one [1] ='b'”行上出现段错误,这是有道理的,因为指针“one”指向的内存必须在只读内存中。但是,问题是为什么“two[1]='b'”行没有段错误?查看 gcc 的程序集输出:

.file   "one.c"
        .section        .rodata
.LC0:
        .string "computer"
.LC1:
        .string "another"
        .text
.globl main
        .type   main, @function
main:

我们看到两个字符串都在rodata部分,所以它们是只读的。那么“two[1]='b'”这一行怎么没有段错误呢?

4

3 回答 3

38

one直接指向位于只读页面中的字符串。另一方面,two是一个分配在堆栈上的数组,并使用一些常量数据进行初始化。在运行时,可执行文件的只读部分中的字符串将被复制到堆栈中。您正在修改的是堆栈上该字符串的副本,而不是只读内存页面。

在更高的层次上,从语言的角度来看,"abcd"是类型的表达const char*而不是char*. 因此,修改此类表达式所指向的值会导致未定义的行为。该语句char* one = "something";仅将指向字符串的指针存储在变量中(不安全,因为它正在丢弃const修饰符)。char two[] = "something";是完全不同的。它实际上是在声明一个数组并对其进行初始化,就像int a[] = {1,2,3};. 这里引号中的字符串是初始化表达式。

于 2009-11-20T20:36:51.457 回答
1

您在rodata 部分看到的“另一个”two是初始化时将复制到数组中的内容。另一方面,字符串“computer”的地址将被分配给一个。

因此,one指向只读段(因此写入时的段错误),而two将在堆栈上分配,然后将“另一个”复制到其中。

于 2009-11-20T20:40:46.493 回答
0

The second form creates an array by copying the literal string.

It is equivalent to:

char two[] = {'a', 'n', 'o', 't', 'h'. 'e', r', '\0'};

You can initialize a character array with variables, such as

char c = 'a';
char two[] = {'a', 'n', c, '\0'};
于 2009-11-20T21:02:41.763 回答