双向链表的双重自由错误

Double free error with doubly linked list

所以我正在尝试做一种方法来清除学校的双向链表,其中双向链表和节点定义为:

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;
    }
}

我在 curr->one_word.unique_word 上执行了一个 free() 因为它是一个 malloc 的字符数组。我用malloc的时候被教过free,所以就这样了。

我 运行 遇到的问题是,当我 运行 我的教授提供的测试文件时,我得到了一个 "bogus pointer (double free?)" 和一个核心转储。我已经为此工作了几个小时,但似乎无法找出我两次拨打免费电话的位置(或方式)。

循环列表的时候要不断改变头部的位置,这样即使重复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;
    }
}

释放内存时,最好将已释放的指针设置为 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

您在离开清除函数之前不会清零 p_head

所以,如果你调用它两次,你就会遇到问题(即 p_head 会指向一个已经释放的节点)。 p_tail.

同样

此外,如果您再次尝试添加到列表中,您也会遇到类似的问题。

否则,你的清晰代码就好了。

那么,你能证明列表构造正确吗(例如,在你free之前,添加一个printf打印出所有节点的指针你释放任何东西之前)。