首页 文章

Linux上C字符串和指针的分段故障

提问于
浏览
15

所以我有以下程序:

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

它在“one [1] ='b'”这一行上有段错误,因为指针“one”所指向的内存必须位于只读内存中 . 然而,问题是为什么“2 [1] ='b'”行不是段错误?查看gcc的程序集输出:

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

我们看到两个字符串都在rodata部分,因此它们是只读的 . 那么为什么“两个[1] ='b'这一行不会出现段错误?

3 回答

  • 0

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

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

  • 1

    您在rodata部分中看到的"another"将在数组 two 中被初始化时复制 . 另一方面,字符串"computer"的地址将分配给一个 .

    因此, one 指向只读段(因此写入时的段错误),而 two 将在堆栈上分配,然后"another"将被复制到其中 .

  • 38

    第二种形式通过复制文字字符串来创建数组 .

    它相当于:

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

    您可以使用变量初始化字符数组,例如

    char c = 'a';
    char two[] = {'a', 'n', c, '\0'};
    

相关问题