Получение Ошибки Сегментации
Я видел много вопросов о получаю ошибку сегментации в программе C здесь, в SO, и я подумал, что было бы здорово иметь ссылку на тех, кто здесь, вопрос с некоторыми случаями, которые вызывают ошибку сегментации. Мой ответ опубликован ниже.
как написано в некоторых ответов, поведение не определено для всех случаев, хотя многие люди встречают их как ошибка сегментирования, поэтому вопрос о том, что вызывает это "симптом."
в случаях, ниже я получаю ошибку сегментации, когда я запустить программу, не могли бы вы определить, почему?
1)
char *str = "foo";
str[0] = 'b'; // << Segfault hre
2)
char str[] = "foo";
char *newStr = malloc(strlen(str));
strcpy(newStr, str);
free(newStr); // << Segfault here
3)
char *str = malloc(4 * sizeof(char));
str = "foo";
free(str); // << Segfault here
4)
char *str = malloc(4 * sizeof(char));
strcpy(str, "foo");
free(str);
if (str != NULL)
free(str); // << Segfault here
5)
char *str = "something and then foo";
printf("%s", str[19]); // << Segfault here
6)
typedef struct {
char *str;
}st;
...
st *s;
s = malloc(sizeof(st));
s->str = malloc(5);
free(s);
free(s->str); // << Segfault here
5 ответов
все ваши примеры вызывают неопределенное поведение, которое может привести к сбою (или оно может не нанести никакого вреда вообще).
вам не разрешается изменять строковый литерал. (см., например,здесь)
вы забыли выделить хранилище для завершающего байта nul, do
malloc(strlen(str) + 1);
вы вызываете free () на указателе, который вы не получили от malloc (или аналогичных функций). Как вы делаете
str
точка указатель на строковый литерал, вы потеряли указатель на память, выделенную с помощью malloc и утечки памяти здесь.вы вызываете free () дважды на одном указателе, что является неопределенным поведением.
%s в строке формата printf сообщает printf, что аргумент является строкой (символ*, указывающий на последовательность символов, заканчивающихся нулем), вы передаете ей символ, а не строку. Если вы хотите напечатать суффикс строки использовать
printf("%s", &str[19]);
вы передаете недопустимый указатель на free (), вы уже free'D
s
, вы не можете разыменовать его позже, когда вы делаетеs->str
. Обратный порядок освобождения:free(s->str); free(s);
Пример 1:char *str = "foo";
назначьте адрес строки в сегменте текста, который доступен только для чтения, и вы не можете написать ему, как это сделано во второй строке:str[0] = 'b';
.
Если вы хотите изменить текст, Используйте char str[] = "foo";
который создаст массив символов на стеке и назначьте его указатель на str.
Пример 2:strlen
возвращает длину строки без ''
chracter в конце, так что strlen("foo") = 3
, а strcpy
копирует строку, включая ''
символ, поэтому он копирует больше байтов, чем вы выделили.
случай 3:
Как и в случае 1, str = "foo";
присвоение адреса "foo"str
, это означает, что вы теряете адрес выделенной памяти и str
теперь содержит указатель на сегмент текста, который вы не можете free
потому что это не в куче, а только для чтения памяти.
пример 4:
The не назначает NULL
к указателю, полученному в качестве параметра (поскольку у него нет адреса, он не может этого сделать). И вы пытаетесь позвонить free
на буфере, который уже был free
d.
пример 5:str[19]
is char
, а не указатель на char, и "%s"
ожидает строку, что означает char *
. Рассматриваемый как адрес на многих платформах, этот char является незаконным адресом. printf()
не проверяет полученные аргументы.
случае 6:
Использование s->str
после s
is free
d ошибается. Правильным использованием будет первый вызов free(s->str);
а потом звоните free(s);
. Освободите внутреннюю выделенную память перед free
ing его контейнер.
- Неопределено Поведение: попытка изменить строковый литерал
- Неопределено Поведение: запись за конец массива
-
Неопределенный Bahaviour: переходя к
free()
указатель не получен черезmalloc()
-
Неопределено Поведение: переходя к
free()
недопустимый указатель -
Неопределено Поведение: incompatabilities между
printf()
формат описателя и фактические типы аргументов -
Неопределено Поведение: переходя к
free()
недопустимый указатель
неопределенное поведение может проявляться "ошибкой сегментации", но это никоим образом не является необходимым результатом. Могло случиться что угодно:)
- вы не выделили память. *STR-это просто указатель.
- причина для segfault находится в строке 2, вам нужно malloc strlen () + 1 из-за разделителя строк '\0'