ошибка сегментации в программе c - PullRequest
6 голосов
/ 11 декабря 2010

только для тестирования я создал следующий код:

#include<stdio.h>

int main(){
    char *p = "Hello world";
    *(p+1) = 'l';
    printf("%s", p);
    return 0;
}

Но когда я запустил это на моем компиляторе "gcc" под Ubuntu 10.04, я получил:

Segmentation fault

Так чтоКто-нибудь объяснит, почему это произошло.

#include<stdio.h>
#include<stdlib.h>

int main(){
    char *p = malloc(sizeof(char)*100);
    p = "Hello world";
    *(p+1) = 'l';
    printf("%s", p);
    free(p);
    return 0;
}

это также может привести к ошибке сегментации. Заранее спасибо

Ответы [ 3 ]

5 голосов
/ 11 декабря 2010

char *p = "Hello world"; *(p+1) = 'l';

Изменение содержимого строкового литерала (т. Е. "Hello World" в вашем коде) - это неопределенное поведение.

ISO C99 (Раздел 6.4.5 / 6)

Не определено, различаются ли эти массивы при условии, что их элементы имеют соответствующие значения. Если программа пытается изменить такой массив, поведение не определено .

Попробуйте использовать массив символов.

char p[] = "Hello World";
p[1] = 'l'; 

РЕДАКТИРОВАТЬ

Ваш измененный код

#include<stdio.h>
#include<stdlib.h>
int main()
{
   char *p = malloc(sizeof(char)*100);
   p = "Hello world"; // p now points to the string literal, access to the dynamically allocated memory is lost.
   *(p+1) = 'l'; // UB as said before edits
   printf("%s", p);
   free(p); //disaster
   return 0;
}

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

2 голосов
/ 11 декабря 2010

Поскольку char *p = "Hello world" почти наверняка дал вам указатель на постоянную память, а это значит, что попытка изменить его с помощью *(p+1) = 'l' - это определенно нет-нет (даже если память не только для чтения,поведение по-прежнему не определено).

Соответствующая часть C99, ссылающаяся на строковые литералы, находится в 6.4.5 para 6:

Не определено, различаются ли эти массивы при условии, что их элементы имеют соответствующийценности.Если программа пытается изменить такой массив, поведение не определено.


Причина, по которой вы все еще получаете ошибку сегментации с чем-то вроде:

char *p = malloc (100);  // sizeof(char) is ALWAYS 1
p = "Hello";             // better would be: strcpy (p, "Hello")
*p = 'a';

потому что, даже если вы выделяете память, которую вам разрешено изменять, второй оператор изменяет указатель , чтобы он указывал на строковый литерал (давая вам утечку mmory по мере потеридоступ к выделенной памяти), который вы не можете изменять.

Вам необходимо отличать изменения указателя от изменений, на которые указывает указатель .

1 голос
/ 11 декабря 2010

"Hello world" - это строковый литерал . Он представлен фрагментом байтов в области памяти, которую нельзя изменить . char *p указывает на этот кусок байтов. *(p+1) = 'l' говорит, что следует перезаписать следующий байт после наведенного на него символом 'l'. Следующий байт после наведенного на него является частью фрагмента, который не может быть изменен. Попытка переписать что-то пытается изменить это. Попытка изменить что-то, что не может быть изменено, очень плохая.

Чтобы иметь в памяти копию текста, которую можно изменить, поместите ее в массив, например, char p[] = "Hello world";. (Обратите внимание, что объявление массива таким образом делает его точно достаточно большим, чтобы содержать строку, и поэтому вы не можете удлинить его, так как места больше нет.)

...