Строковые литералы программы C

#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