递归删除链表c ++

时间:2015-02-25 16:30:19

标签: c++ list

你能告诉我,为什么下一个代码的实现会导致错误:

void del (num*&head) {
    num*temp = 0;
    if (head!=0) {
        temp = head;
        delete temp;
        del (head->next);
    }
    else return;
}

错误:

Access violation reading location 0xcdcdcdc1.

下一代码正常运行:

void del (num*&head) {
    if (head!=0) {
        del (head->next);
        delete head;
    }
    else return;
}

5 个答案:

答案 0 :(得分:1)

删除temp会使head无效,因为它们都指向同一个对象。 head->next尝试访问已删除的对象,提供未定义的行为。您应该存储head->next,这样您就不必访问已删除的对象:

if (head) {
    num * temp = head->next;
    delete head;
    del (temp);
}

您正在运行调试版本,因此删除的内存有助于设置为垃圾,而不是留下旧内容。这意味着尝试使用从中读取的值作为指针将快速触发访问冲突,帮助您找到问题的根源。

第二个版本会等到你完成对象之后再删除它,所以没有未定义的行为。

但是,递归是一个坏主意,因为如果列表太长,它可能会导致堆栈溢出。迭代会更安全:

while (head) {
    num * temp = head->next;
    delete head;
    head = temp;
}

答案 1 :(得分:1)

您正在访问head->next,而实际上您之前已删除了head该行。

另一种方法是:

void del (num*&head) {
    if (head!=0) {
        num* temp = head->next;
        delete head;
        del (temp);
    }
    else return;
}

答案 2 :(得分:1)

在第一个版本中,

    temp = head;
    delete temp;
    del (head->next);

temphead指向同一节点,然后该节点被删除并变为无效。但是在最后一行用

访问它
    del (head->next);

第二个版本没有这个问题。

答案 3 :(得分:1)

    temp = head;
    delete temp; // head is dead too!
    del (head->next); // dereferencing disposed pointer

只要您使用指向同一内存的指针进行操作,删除任何指针都会删除内存。所以,即使你没有删除其他指针,他们指向一块垃圾(甚至是另一个人拥有的内存)

答案 4 :(得分:1)

以这种方式思考: -

完成后

 temp = head;// it means temp and head are talking about the same person,i.e, the same memory location.
 delete temp; //the person(memory location) to which the both of them are pointing is dead;
 del (head->next); //Now you trying to kill the "ghost" of the person means you are trying to delete already deleted node.

但在第二种情况下,递归调用就在

之上
delete head;

所以递归调用首先进行到最后,然后从结尾向开始删除节点,如下所示: -

如果您有n个节点,递归调用的摘要可以被视为: -

 del (list); // call from main.
 del (list->head); //recursive call.
 del (list->head->head);//recursive call.
 del (list->head->head->head);//recursive call.

等..................

因此,当最后一个节点出现时,nextNULL,因此递归停止,节点从最后一次呼叫到第一个呼叫方式删除,换言之,从最后一个节点向第一个节点删除。所以这里没有像第一种情况那样造成伤害。