Получение Ошибки Сегментации

Я видел много вопросов о получаю ошибку сегментации в программе 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 ответов


все ваши примеры вызывают неопределенное поведение, которое может привести к сбою (или оно может не нанести никакого вреда вообще).

  1. вам не разрешается изменять строковый литерал. (см., например,здесь)

  2. вы забыли выделить хранилище для завершающего байта nul, do malloc(strlen(str) + 1);

  3. вы вызываете free () на указателе, который вы не получили от malloc (или аналогичных функций). Как вы делаете str точка указатель на строковый литерал, вы потеряли указатель на память, выделенную с помощью malloc и утечки памяти здесь.

  4. вы вызываете free () дважды на одном указателе, что является неопределенным поведением.

  5. %s в строке формата printf сообщает printf, что аргумент является строкой (символ*, указывающий на последовательность символов, заканчивающихся нулем), вы передаете ей символ, а не строку. Если вы хотите напечатать суффикс строки использовать printf("%s", &str[19]);

  6. вы передаете недопустимый указатель на 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 freed ошибается. Правильным использованием будет первый вызов free(s->str); а потом звоните free(s);. Освободите внутреннюю выделенную память перед freeing его контейнер.


  1. Неопределено Поведение: попытка изменить строковый литерал
  2. Неопределено Поведение: запись за конец массива
  3. Неопределенный Bahaviour: переходя к free() указатель не получен через malloc()
  4. Неопределено Поведение: переходя к free() недопустимый указатель
  5. Неопределено Поведение: incompatabilities между printf() формат описателя и фактические типы аргументов
  6. Неопределено Поведение: переходя к free() недопустимый указатель

неопределенное поведение может проявляться "ошибкой сегментации", но это никоим образом не является необходимым результатом. Могло случиться что угодно:)


  1. вы не выделили память. *STR-это просто указатель.
  2. причина для segfault находится в строке 2, вам нужно malloc strlen () + 1 из-за разделителя строк '\0'

3:" foo " - это постоянная строка, не выделенная динамически.

Sidenote: это тоже утечка памяти.