C строка неизменна?
Согласно моему пониманию обе строки кода создают строку из 6 элементов:
char * output = "AAAAAA" ;
char * output [6] ;
Итак, почему cprogramm падает в первом случае, когда я пытаюсь изменить первый байт массива. А почему не вылетает во втором случае?
* output = 49;
printf("%s\n",output);
7 ответов
Ваше понимание неверно.
Первая строка создает указатель на тип char, который указывает на строку "AAAAAA", которая обычно хранится в разделе неизменяемых данных вашего исполняемого файла. Тот факт, что вы можете указывать на него неконстантным указателем, является печальной проблемой обратной совместимости. Вот почему он падает. Вы должны написать:
const char* output = "AAAAAA";
Кстати, массив символов там имеет 7 элементов: в 6 раз больше "А" и терминатор.
Вторая строка не делает то, что вы хотите вообще. Это массив из 6 указателей на char, и код использования даже не компилируется. Ты наверное имел ввиду
char output[6];
который представляет собой массив из 6 символов и, таким образом, предлагает место для строки длиной 5 (все еще требуется место для терминатора). В любом случае, этот массив является изменяемым, поэтому вы можете изменять его элементы.
Изменение элементов строкового литерала приводит к неопределенному поведению "6.4.5 Строковые литералы [# 6]".
PS. Я вижу строковые литералы, упомянутые как доступные только для чтения, это не является обязательным требованием в стандарте C, хотя оно распространено среди реализаций C. Другое соображение заключается в том, что разные (как лексемы) строковые литералы, представляющие одну и ту же последовательность символов, могут соответствовать одному статическому массиву длительности хранения.
Первый случай должен был быть написан как const char * output = "AAAAAA" ;
, Компилятор создает строковую константу в доступном только для чтения разделе программы и указывает output
на него. Вы можете изменить где output
указывает, но не может свободно изменять содержимое раздела только для чтения вашего приложения.
Первый - это просто указатель, который инициализируется для неизменяемой части памяти, содержащей вашу строку.
Вторым является массив, который инициализируется теми же данными.
Вы не можете изменить данные, на которые указывает указатель из первой строки, но ваш массив, конечно, полностью читается / записывается, как любой другойconst
массив будет.
Думайте о строковых литералах как имеющих тип const char *
,
Инициализация массива C-String - это изменчиво?
Первый создает указатель, который указывает на строковый литерал "hello", который, вероятно, хранится в недоступной для записи памяти в исполняемом образе программы. Даже если это не так, вам не разрешено изменять содержимое этого массива.
char*
а также char[]
это не одно и то же.
Вот что говорит стандарт об этом:
6.6.32
Содержимое массивов является изменяемым. С другой стороны, объявление char *p = "abc"; определяет p с типом '' pointer to char '' и инициализирует его так, чтобы он указывал на объект с типом '' массив char '' длиной 4, элементы которого инициализируются литералом символьной строки. Если предпринята попытка использовать p для изменения содержимого массива, поведение не определено.
Нет
char * output [6];
создает массив из шести указателей на char
, Даже если бы вы использовали
char output [6];
что вы, вероятно, имели в виду, это не строка, а просто массив символов. Чтобы массив символов был строкой, необходимо дополнительно соблюдать соглашение, гарантирующее, что один из символов 0
,
Поскольку вы не инициализируете массив, такой гарантии нет.
Теперь для вашего первого случая, это на самом деле не "создает" новую строку, а указывает на строковый литерал. Строковые литералы на самом деле не изменяемы, и у clang есть все права на вас.
Потому что первый 'char *output = "AAAAA";' объявляет вывод как указатель на область памяти только для чтения, содержащую символы AAAAA.
Затем вы пытаетесь изменить первый байт этого, что, вероятно, является неопределенным поведением.