【问题标题】:Destroying a Linked list in C销毁 C 中的链表
【发布时间】:2013-10-21 08:33:38
【问题描述】:

这是我销毁链表的代码。

void destroy(node *h){
    if (h->next!=NULL){
        destroy(h->next);
    }
    free(h);
    h=NULL;

}

问题是打印还是输出一堆数字:

11, 2, 15, 3, 9, //销毁前

28495936, 28495968, 28496064, 28496096, 0, //销毁后

很遗憾,由于分配原因,我无法更改 void destroy(node *h) 参数。 我尝试过使用 while 循环方法,但仍然得到相同的结果。我也尝试过向左移动并从末尾删除,但我无法删除最后一个节点。

提前致谢。

--编辑-- 根据要求,这里是打印功能

void print(node* N){
        printf("%d, ", N->value);
    if (N->next)
        print_set(N->next);
    if (N == NULL)
        printf("Empty Set");
}

【问题讨论】:

  • 我们可以看到您用来打印列表的代码吗?
  • 你为什么要打印一份你销毁的清单?如果赋值是原型void destroy(node*),那么你不能在调用destroy()的函数中改变指针,所以你不能让指针变为空来阻止打印。
  • 我已经添加了打印代码。
  • 在打印任何内容之前进行 NULL 检查。例如, void print( node* N ) { if( N == NULL ) {printf("NULL\t"); return;} // 此处休息打印代码 }
  • @Abhineet 想法不错,但结果还是一样。它没有将 N 检测为 NULL

标签: c pointers linked-list


【解决方案1】:

您必须设置h->next = NULL。此外,在调用destroy 之后,请确保您不再使用该指针,因为它已被释放。所以,总是在destroy(n) 之后,确保你有n = NULL

更好的办法大概是把签名改成void destroy(node **h),所以代码就变成了:

void destroy(node **h){
    if ((*h)->next!=NULL){
        destroy(&h->next);
    }
    free(*h);
    *h=NULL;
}

然后你确保你以后不使用指针。

在您的print 函数中,您必须在开头添加此检查:

if(N == NULL) return;

【讨论】:

  • 这确实有帮助,但是当我打印时,我打印了一个数字:11, 2, 15, 3, 9, //after 11886656,
  • @PatrickBuhagiar:那是因为您的 print 函数包含错误。您必须在开头检查NULL(因为它是NULL,因此无法使用)。我扩展了我的答案。
  • @PatrickBuhagiar:你在哪个平台上,使用哪个编译器?
  • 由于赋值原因,我无法将(node **h)作为参数传递:(
  • @alk Ubuntu 13.04 和 Linux gcc
【解决方案2】:

如果 Albertsolution provided 由于某些规则而无法使用,则您作为相关来源的作者唯一的可能性是 记住列表的节点已被释放,因此包含对内存的无效引用,并且由于后者而编写的代码可能不会取消引用此类指针,也就是说它们可能不会被传递到打印函数,因为这会通过访问未/释放的内存来引发未定义的行为。

如果编写此类潜在的不安全代码,作为作者,您有责任谨慎使用它并为您离开项目后维护代码的其他程序员提供很好的文档。

【讨论】:

    【解决方案3】:

    这里的问题是你的函数中的h=null 没有做任何事情。您正在修改一个本地参数,因此它不会在函数之外产生任何影响。

    因此,您唯一要做的就是释放内存,但保持地址不变。你的列表仍然存在,指向随机内存位置(当然不是随机的:和以前一样,但是这个内存位置的值是随机的)

    当你打印你的列表之后(这很奇怪,因为你应该已经销毁它......你为什么要再次打印它?),你在内存中打印随机值。

    这是一个问题,因为您的程序也可能崩溃(您正在访问未分配的内存)。

    不幸的是,解决方案需要更改函数的签名:

    void destroy(node **h){
        if ((*h)->next!=NULL){
            destroy((*h)->next);
        }
        free(*h);
        *h=NULL;
    
    }
    

    如果不能,则必须在销毁后将指针设置为NULL,如下所示:

    void destroy(node *h){
        if (h->next!=NULL){
            destroy(h->next);
            h->next=NULL;
        }
        free(h);
    }
    

    在调用函数中:

    destroy(myList);
    myList=NULL;
    

    【讨论】:

    • 那行得通。我不确定我是否可以在我的主要方法中设置 myList=NULL 这就是问题所在..
    • 我看不到任何其他方法可以确保您不使用已销毁的列表。由于内存已释放,因此保持指针是无用的,并且不设置为 NULL 会导致稍后在代码中再次使用它的风险,这会导致您的应用程序崩溃(或类似于您在此问题中询问的行为) )。
    • 在这种情况下似乎没有其他办法。我会问我的讲师。谢谢你的帮助! :)
    【解决方案4】:

    问题可能出在您尚未发布的代码中!

    我假设您保留一个指向列表的“头”指针,您的代码如下所示。

    Node * myList;
    
    .. do stuff..
    
    destroy(myList);
    print(myList);
    

    问题是你没有在销毁之后设置myList = NULL

    destroy(myList);
    myList = NULL;
    print(myList);
    

    destroy() 中的 h=NULL 不执行任何操作,因为它正在修改本地参数。

    【讨论】:

    • 在这种情况下,您需要将 pointer 传递给 myList - 请参阅 @Albert 的解决方案(包括修复 print()。另请注意,递归不是遍历列表!
    【解决方案5】:

    我不知道你的结构是什么样的,但我猜是这样的:

    struct {
      int something;
      int* value;
      list* next;
    }
    

    问题在于,即使 h 是 NULL 指针,h->valueh->next 也不是。它们是NULL+1NULL+2中的指针,可能指向内存中的随机位置。

    【讨论】:

    • 我的结构由一个 int 值和一个 next 指针组成。我应该怎么做?我的意思是,我不能将 h->value 设置为 NULL..
    【解决方案6】:

    如果你正在处理单链表,试试这个代码

    void destroy(node *h){    
       node *n;    
       node *p; \\ variable to store previous term
       n=h;
       while(n->next!=NULL){
       p = n;
     }
      p->next=NULL;  
       free(n);
    

    }

    【讨论】:

    • 此代码是一次删除列表的一个术语(最后一个术语)。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-08-15
    • 2011-09-18
    • 1970-01-01
    • 2018-07-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多