你能告诉我,为什么下一个代码的实现会导致错误:
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;
}
答案 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);
temp
和head
指向同一节点,然后该节点被删除并变为无效。但是在最后一行用
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.
等..................
因此,当最后一个节点出现时,next
为NULL
,因此递归停止,节点从最后一次呼叫到第一个呼叫方式删除,换言之,从最后一个节点向第一个节点删除。所以这里没有像第一种情况那样造成伤害。