Почему эта программа, связанная с C-списком, выдает «ошибку сегментации»? - PullRequest
0 голосов
/ 19 февраля 2010

Первая функция читает файл с набором символов и помещает их в связанный список.Это не работает: (.

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

struct list {
    char val;
    struct list* next;
};

typedef struct list element;

int lcreate(char* fname, element* list);
int ldelete(element* list);
int linsert(char a, char b, element* list);
int lremove(char a, element* list);
int lsave(char* fname, element* list);



int lcreate(char* fname, element* list) {
    element* elem = list;
    char c = 0;
    FILE * file = NULL;

    file = fopen(fname, "r");

    while ((c = getc(file)) != EOF)
    {
        if(list == NULL) {
            list = (element*)malloc(sizeof(element));
            if(list == NULL) {
                return 0;
            }
            list->val = c;
        }
        else {

            elem->next=(element*)malloc(sizeof(element));
            elem = elem->next;
            elem-> val = c;
        }
    }
    fclose(file);
    elem->next = NULL;
    return 1;
}



int main(void) {
    int i = 0;


    element * list = NULL;
    lcreate("list.txt", list);

    for(i = 0; i<4; ++i) {
        printf("%c", list->val);
        list = list->next;
    }

    return 0;
}

Исправлена ​​проблема с нулевым значением 'file'.

Ответы [ 6 ]

6 голосов
/ 19 февраля 2010

Здесь есть одна очевидная проблема:

FILE * file = NULL;

fopen(fname, "r");

Чтобы fopen достиг многого, вам нужно присвоить результат из fopen вашему FILE *:

file = fopen(fname, "r");

Edit: так как вы работаете в C, вы не можете передать указатель по ссылке. В качестве альтернативы вы можете передать указатель на указатель:

int lcreate(char *fname, element **list) {

     // ...
     *list = malloc(sizeof(element));
     (*list)->next = null;
     (*list)->val = c;
// ...
}

По сути, весь код внутри lcreate должен ссылаться на *list вместо list. В качестве альтернативы вы можете взять указатель на существующий список в качестве входных данных и вернуть указатель на список, так что в main у вас будет что-то вроде: list = lcreate("list.txt", list);

2 голосов
/ 19 февраля 2010

file равно NULL, и вы никогда не назначаете ему дескриптор файла.

1 голос
/ 19 февраля 2010

В вашей функции main вы также передаете list по значению lcreate.Внутри функции lcreate() вы перезаписываете локальную копию list, не меняя значения list в основной функции.Поскольку list инициализируется как NULL, при вызове list->val.

вы получите segfault.
1 голос
/ 19 февраля 2010

Да - то, что другие говорили о указателе FILE и передаче list по значению, а не по ссылке на lcreate(), верно.

Вы также не возвращаете размер списка из lcreate() - вы, вероятно, должны возвращать его через возвращаемое значение или аргумент указателя.

Вы пытаетесь повторить список 4 раза в функции main(), но в списке может быть менее 4 элементов. В конечном итоге printf() вызовет ошибку сегментации, если list равно NULL.

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

Обновление:

Также, пожалуйста, не забудьте освободить память, выделенную вам после прохождения списка, в противном случае вы получите утечку памяти (хотя на практике это не будет проблемой для вас, поскольку программа заканчивается, но Освобождение памяти - это хорошая привычка.

0 голосов
/ 19 февраля 2010

Было бы хорошо проверить, был ли malloc успешным, проверив ненулевой пинтер. Кроме того, вы можете выделить ссылку head / first за пределами while, чтобы избежать нулевой проверки заголовка каждый раз в цикле while. Конечно, это оптимизации, если ваш связанный список станет действительно большим!

0 голосов
/ 19 февраля 2010

Я также вижу дополнительную проблему. В операторе while, равном lcreate(), истинное предложение в операторе if malloc занимает некоторую память и присваивает его list, однако elem не обновляется.

while ((c = getc(file)) != EOF)
{
    if(list == NULL) {
        list = (element*)malloc(sizeof(element));
        if(list == NULL) {
            return 0;
        }
        list->val = c;
    }
    else {

В следующий раз через цикл while list не будет ненулевым, но elem по-прежнему будет нулевым, поэтому присваивание elem-> next пытается отложить нулевой указатель и, таким образом, ошибка сегментации (что, кстати, означает что вы пытались получить доступ к памяти, которая не была назначена вашему процессу): -

else {
    elem->next=(element*)malloc(sizeof(element));

Как уже отмечали другие, вы также не вернете list назад к основному, поэтому он будет равен NULL, когда вы нажмете цикл printf ().

Наконец, отладчик - ваш друг, когда вы смотрите на эти проблемы. Вы увидите, какая именно строка вызывает ошибку сегмента и каково было состояние переменных.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...