Двойная ошибка с двунаправленным списком - PullRequest
0 голосов
/ 13 октября 2018

Итак, я пытаюсь сделать метод для очистки двусвязного списка для школы, где двусвязный список и узлы определены как:

struct word_entry
{
    char *unique_word ;
    int word_count ;
} ;

struct node
{
    struct word_entry one_word ;
    struct node *p_previous ;
    struct node *p_next ;
} ;

struct linked_list
{
    struct node *p_head ;
    struct node *p_tail ;
    struct node *p_current ;
} ;

У меня есть метод для очистки связанного списка с помощьюделая

int clear_linked_list( struct linked_list *p_list ) //return how many nodes were cleared
{
    if (p_list->p_head == NULL) {
        return 0;
    }
    else {
        int count = 0;
        struct node *curr = p_list->p_head;

        while (curr != NULL) {
            struct node *next = curr->p_next;

            free(curr->one_word.unique_word);
            free(curr);
            curr = next;
            count++;
        }

        return count;
    }
}

Я делаю free () для curr-> one_word.unique_word, потому что это массив символов malloc'd.Меня научили освобождать при использовании malloc, вот и все.

Проблема, с которой я сталкиваюсь, заключается в том, что я получаю «фиктивный указатель (double free?)» И дамп ядра при запуске тестового файла, предоставленногомой профессор.Я работал над этим в течение нескольких часов и не могу понять, где (или как) я звоню бесплатно дважды.

Ответы [ 3 ]

0 голосов
/ 13 октября 2018

При освобождении памяти рекомендуется устанавливать в NULL указатели, которые были освобождены, чтобы избежать подобных проблем.Так что вы должны сделать:

free(curr->one_word.unique_word);
curr->one_word.unique_word=NULL; 
//if that one_word.unique_word was shared between multiples nodes that free could cause problems if you dont set it to NULL afterwards
free(curr);
curr=NULL; //or curr=next...

Также.Убедитесь, что при создании узлов, которые:

  • * p_next равен NULL на последнем узле двойного связанного списка
  • * p_previous - NULL на первом узле списка
0 голосов
/ 13 октября 2018

Вы не обнуляете p_head до выхода из функции очистки.

Таким образом, если вы вызовете его дважды, у вас будут проблемы (т. Е. p_head будет указывать на уже освобожденный узел).Аналогично для p_tail.

Кроме того, если вы попытаетесь снова добавить в список, у вас возникнут аналогичные проблемы.

В противном случае с вашим чистым кодом все в порядке.

Итак, можете ли вы доказать, что список составлен правильно (например, перед вами free, добавьте printf, который печатает все указатели узла до , когда вы освобождаете что-либо).

0 голосов
/ 13 октября 2018

Когда вы перебираете список, вы должны постоянно менять положение головы, так что даже если вы повторите clear_linked_list, вы не получите ошибку.

int clear_linked_list(struct linked_list* p_list)  // return how many nodes were cleared
{
    if (p_list->p_head == NULL) {
        return 0;
    } else {
        int count = 0;
        while (p_list->p_head != NULL) {
            struct node* curr = p_list->p_head;
            p_list->p_head = p_list->p_head->p_next;

            free(curr->one_word.unique_word);
            free(curr);
            count++;
        }

        return count;
    }
}
...