Ошибка сегментации с помощью Char Массив и указатель в C на Linux

Итак, у меня есть следующая программа:

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

Это segfaults на строке "one [1] = 'b", что имеет смысл, потому что память, на которую указывает указатель "один", должна быть в памяти только для чтения. Однако вопрос заключается в том, почему строка "two [1] = 'b'" segfault? Глядя на сборку из gcc:

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

Мы видим, что обе строки находятся в разделе родата, поэтому они являются readonly. Итак, как получилось, что строка "two [1] =" b "не является segfault?

Ответы

Ответ 1

one указывает прямо на строку, расположенную на странице только для чтения. С другой стороны, two - это массив, выделенный в стеке, и инициализируется некоторыми постоянными данными. Во время выполнения строка в секции только для чтения исполняемого файла будет скопирована в стек. То, что вы изменяете, - это копия этой строки в стеке, а не страница памяти только для чтения.

На более высоком уровне, с точки зрения языка, "abcd" является выражением типа const char*, а не char*. Таким образом, изменение значения, указываемого таким выражением, приводит к поведению undefined. Оператор char* one = "something"; просто хранит указатель на строку в переменной (это не так, потому что он отбрасывает модификатор const). char two[] = "something"; полностью отличается. Он фактически объявляет массив и инициализирует его, подобно int a[] = {1,2,3};. Строка в кавычках здесь представляет собой выражение инициализации.

Ответ 2

"Другой", который вы видите в разделе rodata, будет скопирован в массив two, когда он будет инициализирован. С другой стороны, адрес строки "компьютер" будет назначен одному.

Итак, one указывает на сегмент только для чтения (и, следовательно, segfault on write), а two будет выделен в стеке, а затем в него будет скопирован "другой".

Ответ 3

Вторая форма создает массив, копируя литеральную строку.

Это эквивалентно:

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

Вы можете инициализировать массив символов с помощью переменных, например

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