【问题标题】:Deleting nodes in a doubly linked list (C++)删除双向链表中的节点 (C++)
【发布时间】:2011-03-12 11:28:58
【问题描述】:

我无法理解为什么当我创建两个或更多节点(如下所示)时,函数void del_end()只会删除char name[20]而不是整个节点。如何在不发生内存泄漏的情况下解决此问题?

#include <iostream>
using namespace std;

struct node
{
    char name[20];
    char profession[20];
    int age;
    node *nxt;
    node *prv;
};

node *start_ptr = NULL;

void del_end()
{
    node *temp, *temp2;
    temp = start_ptr;
    if (start_ptr == NULL)
        cout << "Can't delete: there are no nodes" << endl;
    else if (start_ptr != NULL && start_ptr->nxt == NULL)
    {start_ptr=NULL;}
    else
    {
    while (temp->nxt != NULL)
    {
        temp = temp->nxt;
    }
    temp2=temp->prv;
    delete temp;
    temp->nxt= NULL;
    }
}

【问题讨论】:

  • 我认为这是家庭作业?如果是这种情况,请添加作业标签。

标签: c++ linked-list destructor


【解决方案1】:

您的代码有一些问题,最糟糕的是:

temp2=temp->prv;
delete temp2;
temp->nxt= NULL;

您正在删除倒数第二个节点,使指向它的任何指针悬空,并丢失最后一个节点。

但如果你发布更多真实代码,我们可以告诉你更多。

编辑:
这是del_end 的稍微清理过的版本(还有很大的改进空间)。

void del_end()
{
  if (start_ptr == NULL)
  {
    cout << "Can't delete: there are no nodes" << endl;
    return;
  }

  if (start_ptr->nxt == NULL)
  {
    delete start_ptr;
    start_ptr = NULL;
    return;
  }

  node *nextToLast = start_ptr;
  node *last = start_ptr->nxt;

  while(last->nxt != NULL)
  {
    nextToLast = last;
    last = last->nxt;
  }

  delete last;
  nextToLast->nxt = NULL;

  return;
}

请注意,这假定prev 链接是正确的,这在这里看起来很谨慎。

【讨论】:

  • 我的代码真的很长,每行加4个空格是很多人工的。有没有办法只在帖子上放一个文件?
  • @danutenshu:如果有的话,这仍然不是一个好主意——帖子应该简短。尝试输入足够的代码来重现问题(例如,输入一个main,它构造一个小列表,然后调用del_end)。同时,我将发布del_end的修改版本。
  • 所以我意识到我需要一个析构函数,但是temp=NULL 会导致任何内存泄漏吗?
  • @danutenshu: 1) 析构函数很方便,但并非绝对必要,2) 内存泄漏已经存在于您的代码中,temp=NULL 不会修复它。
  • 我打算自己解决,但我尝试插入你的代码,但问题是它只是删除了node-&gt;name,所以我正在制作void destructor(node obj),它将删除数据,制作指针 nxtprv NULL。
【解决方案2】:
delete temp2;

将删除整个节点。

【讨论】:

  • 节点被删除了,但是如果在堆上声明了节点指向的内存,我认为不会被删除。您能否提供解释我的错误的原始来源?哎呀!我不知何故忽略了两个 char 数组在堆栈上声明的事实!
【解决方案3】:

问题是您似乎试图删除最后一个节点,但实际上您正在删除它之前的那个。

while (temp->nxt != NULL) 
{ 
    temp = temp->nxt; 
} 
temp2=temp->prv; 
delete temp2; 
temp->nxt= NULL; 

这是你的问题。改成这样:

while (temp->nxt != NULL) 
{ 
    temp = temp->nxt; 
} 
temp2=temp->prv; 
delete temp; 
temp2->nxt= NULL;

而且我相信它会按预期工作。这将保存倒数第二个节点,删除末尾,然后将倒数第二个节点的 nxt 指针设置为空,使其成为最后一个。

【讨论】:

    【解决方案4】:

    如果您担心内存,我强烈建议您学习使用 Valgrind http://valgrind.org/。这是一个很棒的工具。 Valgrind 将内存泄漏分为 3 类:

    • “肯定丢失” - 指向动态分配内存的指针丢失,无法恢复
    • “可能丢失” - 指向动态分配内存的指针指向块的内部,可能不相关
    • “仍然可达” - 指向动态分配内存的指针仍然存在,但在程序执行结束时从未释放内存

    运行 Valgrind 也很简单。这是用户手册http://valgrind.org/docs/manual/manual.html 的链接。运行 valgrind 时的一些有用标志:

    • --leak-check=&lt;no|summary|yes|full&gt;
    • --show-reachable=&lt;no|yes&gt;

    现在,我要删除双向链表中的节点的方法是:

    // if the node to be removed is the head node
    if (nodeToRemove->prev == NULL) {
        // reassign the head node pointer
        start_ptr = nodeToRemove->next;
    } else {
        // correct previous node pointer
        nodeToRemove->prev->next = nodeToRemove->next;
    }
    
    // if the node to be removed node is the tail node
    if (nodeToRemove->next == NULL) {
        // reassign the tail node pointer
        end_ptr = nodeToRemove->prev;
    } else {
        // correct next node pointer
        nodeToRemove->next->prev = nodeToRemove->prev;
    }
    
    // deallocate memory
    delete(nodeToRemove);
    nodeToRemove = NULL;
    

    只需在声明 start_ptr 之后声明 node *end_ptr = NULL; 并在将节点附加到列表时,请确保 end_ptr 始终指向列表的末尾...如果您要添加到列表的末尾列表,很简单……只需将 end_ptr 指向要添加的节点。

    如果你总是要删除最后一个节点,你最好保留一个尾指针。所以一旦你有了要删除的节点,我只需检查它是否是头/尾节点,重新分配下一个/上一个指针,然后释放内存。

    顺便说一句...我从我的 C 实现中获取了这个,所以如果语法不正确我很抱歉...但是逻辑就在那里。

    希望对您有所帮助。

    【讨论】:

    • 没问题。如果这是与学校相关的任务,我很惊讶他们没有让你使用 Valgrind。
    猜你喜欢
    • 1970-01-01
    • 2013-09-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-10-09
    • 1970-01-01
    相关资源
    最近更新 更多