【问题标题】:Freeing a singly linked list in c在c中释放单链表
【发布时间】:2016-06-22 23:48:46
【问题描述】:

在实现单链表时,我遇到了一个似乎很奇怪的问题。我调用 list_destroyer 并将指针传递给列表的头部,但是当方法返回时,传递的指针仍然指向完整列表。我不相信我已经在任何地方传递了结构。

这是我的结构列表和类型定义

typedef struct list list_t
struct list{
    void* datum;
    list_t* next;
};

这是导致问题的代码

void list_destroy(list_t *head){
    list_t *destroy = head;
    while(head){
        //printf("%d \n", list_size(head));
        head = head->next;
        free(destroy);
        destroy = head;
    }
    //printf("%d \n", list_size(head));
    head = NULL;
    //printf("%d \n", list_size(head));
}

list_size 函数已被注释掉,因为它们不是必需的,但我使用它们来查看代码的输出。 printf 输出显示大小正在减小。围绕“head = NULL;”的两个printf语句都打印大小为零。 gdb 也证实了这一点。但是,当我有这段代码(以下)调用 list_destroy 时,传递的指针是不变的。

int main(){
    list_t *test = NULL;
    int a = 1;
    int b = 2;
    list_append(test,&a);
    list_append(test,&b);
    printf("%d \n", list_size(test));
    list_destroy(test);
    printf("%d \n", list_size(test));
}

我仍然得到 list_destroy 上方和下方的 printf 来输出 2。我没有在任何地方初始化新的 list_t,所以我看不到 list_destroy 之后的 printf 仍然会输出 2,(尤其是当 printf在 list_destroy 中表示传入的 list_t* 最后的大小为 0。

【问题讨论】:

  • 我不知道这是否是一个充分的解释(我没有详细查看您的代码)但释放内存并不会覆盖它。

标签: c singly-linked-list


【解决方案1】:

但是当方法返回时,传递的指针仍然指向一个完整的列表。

这是不正确的:当函数返回时,指针指向以前的完整列表。很有可能,您的系统会让您不间断地遍历整个列表。但是,在调用之后取消引用该指针是未定义的行为,因此相同的代码可能会在其他系统上崩溃。

这个问题有个名字——head 变成了一个悬空指针

解决问题很容易 - 将指针传递给指针,并在完成时将其设置为 NULL

void list_destroy(list_t **headPtr){
    list_t *head = *headPtr;
    list_t *destroy = head;
    while(head){
        head = head->next;
        free(destroy);
        destroy = head;
    }
    *headPtr = NULL;
}

【讨论】:

  • 这真的和我的不一样吗?您对 *headPtr 的使用相当于我的 list_t *head,不是吗?我有一行“head = NULL;”最后。所以指针不应该悬空。我的思维过程有问题吗?
  • @DrewKay 代码中的赋值head = NULL 对传递给list_destroy 的指针没有影响,因为指针是按值传递的。 list_destroymain 获取 test 的私有副本。可以随意分配它; main 函数中的 test 将保持不变。我的修改通过指针传递指针,让list_destroy 中的赋值从你的main 函数修改test 指针。
  • 啊,谢谢。这就说得通了。但是,这是一个班级项目,实现需要 list_destroy(list_t *head),所以我会发邮件给教授看看是否有错误。
  • @DrewKay 虽然将指向指针的指针传递给list_destroy 并不少见,但另一种解决方案是传递一个指针,并在函数返回后手动将NULL 分配给test。这很容易出错,但程序员还是会这样做。
  • 谢谢。它没有解决我的问题,但你确实告诉了我为什么我有问题,所以我把你标记为答案。
猜你喜欢
  • 1970-01-01
  • 2011-05-04
  • 2021-07-07
  • 2020-02-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-09
  • 2018-06-03
  • 1970-01-01
相关资源
最近更新 更多