Ошибка сегментации с помощью 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'};