微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

在 C 中释放整个链表

如何解决在 C 中释放整个链表

我知道这个问题在这个网站上被问了很多,所以我很抱歉再次问这个问题,但我真的被卡住了。我正在尝试创建一个删除整个链表的函数(在 C 中)。任何建议都会真正帮助我。我附上了函数的当前代码、链表结构和 Valgrind 上的结果。

typedef struct node {
    void* data;
    struct node* next;
} node_t;

typedef struct list {
    node_t* head;
    int (*comparator)(void*,void*);
    void (*printer)(void*);
    void (*deleter)(void*);
    int length;
} list_t;

void DestroyList(list_t* list) {
    if (list == NULL) return;
    struct list_t* curr;
    
    while (list != NULL) {
        curr = list;
        list = list->head->next;
        free(curr);
    }
}

Valgrind 输出

[[ Valgrind Errors Detected ]]
==1045== Memcheck,a memory error detector
==1045== copyright (C) 2002-2017,and GNU GPL'd,by Julian Seward et al.
==1045== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==1045== Command: ./main
==1045== Parent PID: 16
==1045== 
==1045== Use of uninitialised value of size 8
==1045==    at 0x109DDC: DestroyList (hw2.c:123)
==1045==    by 0x10964F: _genos_unittest (DestroyList_small_list.c:30)
==1045==    by 0x109517: main (genos_unittest.h:173)
==1045== 
==1045== Invalid read of size 8
==1045==    at 0x109DDC: DestroyList (hw2.c:123)
==1045==    by 0x10964F: _genos_unittest (DestroyList_small_list.c:30)
==1045==    by 0x109517: main (genos_unittest.h:173)
==1045==  Address 0x2e2e2e35 is not stack'd,malloc'd or (recently) free'd
==1045== 
==1045== 
==1045== HEAP SUMMARY:
==1045==     in use at exit: 95 bytes in 8 blocks
==1045==   total heap usage: 10 allocs,2 frees,151 bytes allocated
==1045== 
==1045== 16 bytes in 1 blocks are definitely lost in loss record 6 of 8
==1045==    at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1045==    by 0x1095B0: _genos_unittest (DestroyList_small_list.c:17)
==1045==    by 0x109517: main (genos_unittest.h:173)
==1045== 
==1045== 16 bytes in 1 blocks are definitely lost in loss record 7 of 8
==1045==    at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1045==    by 0x10975A: InsertAtHead (linkedlist.c:54)
==1045==    by 0x109643: _genos_unittest (DestroyList_small_list.c:27)
==1045==    by 0x109517: main (genos_unittest.h:173)
==1045== 
==1045== 37 (16 direct,21 indirect) bytes in 1 blocks are definitely lost in loss record 8 of 8
==1045==    at 0x4C31B0F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==1045==    by 0x10975A: InsertAtHead (linkedlist.c:54)
==1045==    by 0x1095A6: _genos_unittest (DestroyList_small_list.c:15)
==1045==    by 0x109517: main (genos_unittest.h:173)
==1045== 
==1045== LEAK SUMMARY:
==1045==    definitely lost: 48 bytes in 3 blocks
==1045==    indirectly lost: 21 bytes in 2 blocks
==1045==      possibly lost: 0 bytes in 0 blocks
==1045==    still reachable: 26 bytes in 3 blocks
==1045==         suppressed: 0 bytes in 0 blocks
==1045== Reachable blocks (those to which a pointer was found) are not shown.
==1045== To see them,rerun with: --leak-check=full --show-leak-kinds=all
==1045== 
==1045== For counts of detected and suppressed errors,rerun with: -v
==1045== Use --track-origins=yes to see where uninitialised values come from
==1045== ERROR SUMMARY: 5 errors from 5 contexts (suppressed: 0 from 0)

再次,任何帮助将不胜感激。谢谢!

解决方法

list 的类型为 list_t*,但 list->head->next 的类型为 struct node*。您应该使用正确类型的指针来遍历列表。

它会是这样的:

void DestroyList(list_t* list) {
    if (list == NULL) return;
    node_t* itr = list->head;
    node_t* curr;
    
    while (itr != NULL) {
        curr = itr;
        itr = itr->next;
        // if appropriate
        // free(curr->data);
        free(curr);
    }
    // if appropriate
    // free(list);
}
,

您的 DestroyList() 实现错误(它甚至不应该编译,因为您试图将 struct node* 指针分配给 list_t* 指针)。

试试这个:

void DestroyList(list_t* list) {
    if (list == NULL) return;
    struct list_t *curr = list->head,*next;
    
    while (curr != NULL) {
        next = curr->next;
        free(curr);
        curr = next;
    }

    // depending on whether you want the list to be just cleared,// or actually destroyed,you need either:
    list->head = NULL;
    // or:
    free(list);
}
,

对于初学者来说,不清楚结构 data 的数据成员 struct node 是否指向动态分配的对象。

typedef struct node {
    void* data;
    struct node* next;
} node_t;

通常它应该指向一个动态分配的对象。

其次,struct list 类型的对象可以具有自动存储持续时间。因此,在函数 DestroyList 中,指针 list 不应用于释放 struct list 类型的指向对象。

在该函数中,您需要释放数据成员 data 指向的所有动态分配的节点和其他对象。

调用该函数后,列表应为有效的空列表。

并且每个列表只有一个 struct list 类型的对象。所以例如这些行

struct list_t* curr;
//...    
curr = list;
//...
free(curr);

没有意义。

因此可以通过以下方式定义函数

void DestroyList( list_t *list ) 
{
    while ( list->head != NULL ) 
    {
        node_t *curr = list->head;

        list->head = list->head->next;

        free( curr->data );
        free( curr );
    }

    list->length = 0;
}

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。