Рассмотрите фрагмент на C: "char *s = \"hello\"; s[0] = 'H';" — объясните, что здесь происходит с памятью и почему такой код может привести к ошибке; как правильно изменить строку в этом случае?
Коротко: в строке char *s = "hello"; переменная sss указывает на строковый литерал, который размещается в памяти с статическим временем жизни (обычно в сегменте только для чтения). Попытка изменить этот литерал: s[0]=′H′;s[0] = 'H';s[0]=′H′;
даёт неопределённое поведение — в лучшем случае ничего не произойдёт, в худшем программа упадёт с сегфолтом. Почему так происходит (память): - Сам указатель sss хранится в стеке (или там, где объявлен), но данные литерала — в отдельной области памяти с static storage duration. Многие реалии реализуют эту область как read-only, поэтому запись в неё запрещена. Стандарт C говорит, что модифицировать строковый литерал — UB. Правильные способы изменить строку: 1) Использовать массив символов (копия литерала в изменяемой памяти): char s[] = "hello"; тогда sss — массив размером 666 (включая нуль-терминатор), и s[0]=′H′;s[0] = 'H';s[0]=′H′;
корректно. 2) Выделить память динамически и скопировать: char *s = malloc(strlen("hello") + 1); if (s) { strcpy(s, "hello"); s[0] = 'H'; free(s); } Вывод: нельзя менять строковый литерал через char∗char *char∗. Для изменения делайте копию в изменяемой памяти (массив или malloc).
char *s = "hello";
переменная sss указывает на строковый литерал, который размещается в памяти с статическим временем жизни (обычно в сегменте только для чтения). Попытка изменить этот литерал:
s[0]=′H′;s[0] = 'H';s[0]=′H′; даёт неопределённое поведение — в лучшем случае ничего не произойдёт, в худшем программа упадёт с сегфолтом.
Почему так происходит (память):
- Сам указатель sss хранится в стеке (или там, где объявлен), но данные литерала — в отдельной области памяти с static storage duration. Многие реалии реализуют эту область как read-only, поэтому запись в неё запрещена. Стандарт C говорит, что модифицировать строковый литерал — UB.
Правильные способы изменить строку:
1) Использовать массив символов (копия литерала в изменяемой памяти):
char s[] = "hello";
тогда sss — массив размером 666 (включая нуль-терминатор), и
s[0]=′H′;s[0] = 'H';s[0]=′H′; корректно.
2) Выделить память динамически и скопировать:
char *s = malloc(strlen("hello") + 1);
if (s) {
strcpy(s, "hello");
s[0] = 'H';
free(s);
}
Вывод: нельзя менять строковый литерал через char∗char *char∗. Для изменения делайте копию в изменяемой памяти (массив или malloc).