为什么这段代码不能用于删除链表中的节点?
Why doesn't this code work for deleting nodes in a linked list?
我一直在学习链表的工作原理,并开始用 C++ 构建一个实现来强化这些概念。一切顺利,直到我创建了一个删除所有节点的功能。我想出了一个解决方案(这是注释代码),但我似乎无法弄清楚为什么其他代码不起作用。
Node 对象是使用 'new' 创建的 class 的一个实例。因此 'delete' 习惯了,嗯,删除它。
我认为可能与删除对象和重用指针变量有关。然后我遇到了这个:What happens to a pointer itself after delete?
我已经盯着它看了一段时间,试图弄清楚它可能是什么,但我研究过的任何东西似乎都无法提供答案。
到目前为止,我不认为这与我的实施有关,因为当用解决方案代码替换代码时,程序按预期工作。
代码输出了每个地址,但似乎并没有真正删除对象。如果我运行 Windows 中的程序,程序实际上会锁定并且永远不会离开while 循环。不是无限循环,它只是卡住了,函数永远不会完成。如果我在 C4Droid 上 运行 程序不会锁定,但函数退出后节点仍然存在。
所以我的问题是,为什么当前代码不起作用? (忽略注释代码。这是一个可行的解决方案。)是否有一些我忽略了指针变量的简单内容?先感谢您。
void LinkedList::deleteAll() {
Node *pCurrent = pHead;
while(pCurrent){
Node *pNext = pCurrent->pNext;
std::cout << pCurrent << std::endl;
delete pCurrent;
pCurrent = nullptr;
pCurrent = pNext;
// pHead = pHead->pNext;
// delete pCurrent;
// pCurrent = pHead;
}
}
节点class
class Node{
public:
Node(string content):data(content){}
string getData(){
return data;
}
Node *pNext = nullptr;
private:
string data;
};
LinkedList.h
/*
* LinkedList.h
*
* Created on: Oct 3, 2015
* Author: Anthony
*/
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
#include<string>
using std::string;
class LinkedList {
public:
LinkedList();
virtual ~LinkedList();
int length();
void addNode(string nodeContent);
void deleteNode(string nodeContent);
void deleteAll();
private:
class Node{
public:
Node(string content):data(content){}
string getData(){
return data;
}
Node *pNext = nullptr;
private:
string data;
};
Node *pHead = nullptr;
};
#endif /* LINKEDLIST_H_ */
LinkedList.cpp
/*
* LinkedList.cpp
*
* Created on: Oct 3, 2015
* Author: Anthony
*/
#include "LinkedList.h"
#include <iostream>
LinkedList::LinkedList() {
// TODO Auto-generated constructor stub
}
LinkedList::~LinkedList() {
// TODO Auto-generated destructor stub
}
int LinkedList::length() {
Node *current = pHead;
int count = 0;
while(current){
count++;
current = current->pNext;
}
return count;
}
void LinkedList::addNode(std::string nodeContent) {
Node *newNode = new Node(nodeContent);
newNode->pNext = pHead;
pHead = newNode;
}
void LinkedList::deleteNode(std::string nodeContent) {
}
void LinkedList::deleteAll() {
Node *pCurrent = pHead;
while(pCurrent){
Node *pNext = pCurrent->pNext;
std::cout << pCurrent->pNext << std::endl;
delete pCurrent;
pCurrent = nullptr;
pCurrent = pNext;
// pHead = pHead->pNext;
// delete pCurrent;
// pCurrent = pHead;
}
}
main.cpp
/*
* main.cpp
*
* Created on: Oct 3, 2015
* Author: Anthony
*/
#include<iostream>
#include "LinkedList.h"
int main(int argc, char **argv){
using namespace std;
LinkedList list = LinkedList();
list.addNode(string("Test"));
list.addNode(string("Test1"));
list.deleteAll();
cout << list.length() << endl;
return 0;
}
当您使用 "new" 关键字创建对象时,涉及两个主要的内存区域,"call stack," 跟踪局部变量和调用了哪些函数,"heap," 旨在以牺牲速度为代价来保存大量数据。
当您声明局部变量 pCurrent 时,会在 "call stack," 上创建一个指针,就像局部整型变量会通过声明 "int a;" 放在堆栈上一样,局部变量,变量在堆栈,不需要删除。
所有使用 "new" 创建的对象都需要删除,因为它们是在堆上创建的。
正如 PaulMcKenzie 所写,确保将头指针也设置为 null。
void LinkedList::deleteAll() {
Node *pCurrent = pHead;
while(pCurrent){
Node *pNext = pCurrent->pNext;
std::cout << pCurrent << std::end;
delete pCurrent;
pCurrent = pNext;
}
pHead = nullptr;
}
假设(这是一个很大的假设)你的链表被正确地放在一起,为什么注释代码有效而新代码无效的问题就很简单了。
pHead = pHead->pNext;
delete pCurrent;
pCurrent = pHead;
在上面的代码中,您在循环时将 pHead
指针移动到列表中。当循环结束时,pHead
指针是 nullptr
,这是正确的,因为列表现在是空的。
Node *pNext = pCurrent->pNext;
std::cout << pCurrent << std::endl;
delete pCurrent;
pCurrent = nullptr;
pCurrent = pNext;
对于新的、未注释的代码,您没有在循环结束后设置 pHead
指针,因此它指向垃圾。之后任何链表的使用都将失效。
所以不是函数没有删除所有节点,而是删除节点后,链表有一个野pHead
指针,并使用链表的pHead
节点在任何后续功能中变得不稳定。
尝试以下操作:
void LinkedList::deleteAll() {
Node *pCurrent = pHead;
while(pCurrent){
Node *pNext = pCurrent->pNext;
delete pCurrent;
pCurrent = nullptr;
pCurrent = pNext;
}
pHead = nullptr; // Sets the head pointer to nullptr, denoting that the list is empty.
我一直在学习链表的工作原理,并开始用 C++ 构建一个实现来强化这些概念。一切顺利,直到我创建了一个删除所有节点的功能。我想出了一个解决方案(这是注释代码),但我似乎无法弄清楚为什么其他代码不起作用。
Node 对象是使用 'new' 创建的 class 的一个实例。因此 'delete' 习惯了,嗯,删除它。
我认为可能与删除对象和重用指针变量有关。然后我遇到了这个:What happens to a pointer itself after delete? 我已经盯着它看了一段时间,试图弄清楚它可能是什么,但我研究过的任何东西似乎都无法提供答案。
到目前为止,我不认为这与我的实施有关,因为当用解决方案代码替换代码时,程序按预期工作。
代码输出了每个地址,但似乎并没有真正删除对象。如果我运行 Windows 中的程序,程序实际上会锁定并且永远不会离开while 循环。不是无限循环,它只是卡住了,函数永远不会完成。如果我在 C4Droid 上 运行 程序不会锁定,但函数退出后节点仍然存在。
所以我的问题是,为什么当前代码不起作用? (忽略注释代码。这是一个可行的解决方案。)是否有一些我忽略了指针变量的简单内容?先感谢您。
void LinkedList::deleteAll() {
Node *pCurrent = pHead;
while(pCurrent){
Node *pNext = pCurrent->pNext;
std::cout << pCurrent << std::endl;
delete pCurrent;
pCurrent = nullptr;
pCurrent = pNext;
// pHead = pHead->pNext;
// delete pCurrent;
// pCurrent = pHead;
}
}
节点class
class Node{
public:
Node(string content):data(content){}
string getData(){
return data;
}
Node *pNext = nullptr;
private:
string data;
};
LinkedList.h
/*
* LinkedList.h
*
* Created on: Oct 3, 2015
* Author: Anthony
*/
#ifndef LINKEDLIST_H_
#define LINKEDLIST_H_
#include<string>
using std::string;
class LinkedList {
public:
LinkedList();
virtual ~LinkedList();
int length();
void addNode(string nodeContent);
void deleteNode(string nodeContent);
void deleteAll();
private:
class Node{
public:
Node(string content):data(content){}
string getData(){
return data;
}
Node *pNext = nullptr;
private:
string data;
};
Node *pHead = nullptr;
};
#endif /* LINKEDLIST_H_ */
LinkedList.cpp
/*
* LinkedList.cpp
*
* Created on: Oct 3, 2015
* Author: Anthony
*/
#include "LinkedList.h"
#include <iostream>
LinkedList::LinkedList() {
// TODO Auto-generated constructor stub
}
LinkedList::~LinkedList() {
// TODO Auto-generated destructor stub
}
int LinkedList::length() {
Node *current = pHead;
int count = 0;
while(current){
count++;
current = current->pNext;
}
return count;
}
void LinkedList::addNode(std::string nodeContent) {
Node *newNode = new Node(nodeContent);
newNode->pNext = pHead;
pHead = newNode;
}
void LinkedList::deleteNode(std::string nodeContent) {
}
void LinkedList::deleteAll() {
Node *pCurrent = pHead;
while(pCurrent){
Node *pNext = pCurrent->pNext;
std::cout << pCurrent->pNext << std::endl;
delete pCurrent;
pCurrent = nullptr;
pCurrent = pNext;
// pHead = pHead->pNext;
// delete pCurrent;
// pCurrent = pHead;
}
}
main.cpp
/*
* main.cpp
*
* Created on: Oct 3, 2015
* Author: Anthony
*/
#include<iostream>
#include "LinkedList.h"
int main(int argc, char **argv){
using namespace std;
LinkedList list = LinkedList();
list.addNode(string("Test"));
list.addNode(string("Test1"));
list.deleteAll();
cout << list.length() << endl;
return 0;
}
当您使用 "new" 关键字创建对象时,涉及两个主要的内存区域,"call stack," 跟踪局部变量和调用了哪些函数,"heap," 旨在以牺牲速度为代价来保存大量数据。
当您声明局部变量 pCurrent 时,会在 "call stack," 上创建一个指针,就像局部整型变量会通过声明 "int a;" 放在堆栈上一样,局部变量,变量在堆栈,不需要删除。
所有使用 "new" 创建的对象都需要删除,因为它们是在堆上创建的。
正如 PaulMcKenzie 所写,确保将头指针也设置为 null。
void LinkedList::deleteAll() {
Node *pCurrent = pHead;
while(pCurrent){
Node *pNext = pCurrent->pNext;
std::cout << pCurrent << std::end;
delete pCurrent;
pCurrent = pNext;
}
pHead = nullptr;
}
假设(这是一个很大的假设)你的链表被正确地放在一起,为什么注释代码有效而新代码无效的问题就很简单了。
pHead = pHead->pNext;
delete pCurrent;
pCurrent = pHead;
在上面的代码中,您在循环时将 pHead
指针移动到列表中。当循环结束时,pHead
指针是 nullptr
,这是正确的,因为列表现在是空的。
Node *pNext = pCurrent->pNext;
std::cout << pCurrent << std::endl;
delete pCurrent;
pCurrent = nullptr;
pCurrent = pNext;
对于新的、未注释的代码,您没有在循环结束后设置 pHead
指针,因此它指向垃圾。之后任何链表的使用都将失效。
所以不是函数没有删除所有节点,而是删除节点后,链表有一个野pHead
指针,并使用链表的pHead
节点在任何后续功能中变得不稳定。
尝试以下操作:
void LinkedList::deleteAll() {
Node *pCurrent = pHead;
while(pCurrent){
Node *pNext = pCurrent->pNext;
delete pCurrent;
pCurrent = nullptr;
pCurrent = pNext;
}
pHead = nullptr; // Sets the head pointer to nullptr, denoting that the list is empty.