#c
#c
Вопрос:
Когда мы делаем
char *p ="house";
p = 'm';
Это недопустимо.
Но когда мы делаем
char p[] = "house";
p[0] = 'm';
printf(p);
Он выдает O / P как: мышь
Я не могу понять, как и где C выделяет память для строковых литералов?
Комментарии:
1. Ранее это можно было сделать с помощью опции компилятора
-fwriteable-strings
. Теперь*p = "house";
это константа.2. @Matty: Нет, это не сработает. Он будет компилироваться, но это вызовет неопределенное поведение и, скорее всего, сбой.
3. @ott—: Да, вы можете использовать опцию компилятора для включения доступных для записи строковых литералов (если у вашего компилятора есть такая опция), но если вам не нужно поддерживать очень старый код, вы не должны этого делать. Строковые литералы следует рассматривать как доступные только для чтения.
Ответ №1:
char p[] = "house";
"house"
это строковый литерал, хранящийся в папке, доступной только для чтения, но, p — это массив символов, помещенных в стек, в который "house"
копируется.
Однако in char *p = "house";
p
фактически указывает на местоположение, доступное только для чтения, которое содержит строковый литерал «house», таким образом изменяя его UB .
Примечание из стандарта 6.7.8 Initialization
14 Массив символьного типа может быть инициализирован строковым литералом, необязательно заключенным в фигурные скобки. Последовательные символы символьного строкового литерала (включая завершающий нулевой символ, если есть место или если массив неизвестного размера) инициализируют элементы массива.
Итак, у вас в основном есть массив символов. Это не должно быть так сложно или озадачивать вас в понимании того, как этот массив изменяется, Если вы использовали массивы ints
и floats
т. Д.
Ответ №2:
Когда вы используете char *p=»house» — компилятор собирает все строки «house» и помещает их в одно пространство, доступное только для чтения.
Когда вы используете char p[]=»house», компилятор создает пространство для строки в виде массива в локальной области видимости.
Основное отличие заключается в том, что 1000 указателей могут совместно использовать первый (именно поэтому вы не можете изменять), а второй является локальным для области видимости — поэтому, пока он остается того же размера, он может быть изменен.
Комментарии:
1. Но когда я использую int array_int = {1,2,3}; и int *array_int_ptr = array_int; и array_int_ptr[0] = 4 … Я могу изменить его значение… также, если я напишу int * int_ptr = {1,2,3}, я не смогу получить доступ к int_ptr[1] или int_ptr[2] .. это приводит к ошибке сегментации … как это работает тогда
Ответ №3:
char *p = "house"; // const char* p = "house";
Строковый литерал "house"
находится в папке только для чтения и не может быть изменен. Теперь то, что вы делаете, это —
*p = 'm' ; // trying to modify read-only location; Missed the dereferencing part
Теперь,
char p[] = "house";
"house"
копируется в массив p. Таким образом, его содержимое можно изменять. Итак, это действительно работает.
p[0] = 'm'; // assigning `m` at 0th index.
Комментарии:
1. p — указатель. Только когда вы объявляете его массивом, он становится немодифицируемым.
2. Но когда я использую int array_int = {1,2,3}; и int *array_int_ptr = array_int; и array_int_ptr[0] = 4 … Я могу изменить его значение… также, если я напишу int * int_ptr = {1,2,3}, я не смогу получить доступ к int_ptr[1] или int_ptr[2] .. это приводит к ошибке сегментации … как это работает?
3. Пожалуйста, взгляните на пример. Если у вас есть копия содержимого, вы можете ее изменить. И использование
[]
во время инициализации возвращает вам копию списка инициализаторов в переменную. ideone.com/mz5mC