我明天要参加面向对象的考试,但我仍然被链表所困扰。出于某种原因,我不太明白它们是如何工作的,也不太明白如何正确实施它们。我看了很多视频和教程,但它仍然很复杂。我总是收到一个错误,它不会向控制台打印任何内容,只是一个空白的黑色页面。有人能告诉他们我做错了什么吗?非常感谢。
#include <iostream>
#include <string>
using namespace std;
struct node
{
string name;
int number;
node* next;
};
struct node* head = 0;
class Employees
{
private:
node* head, * tail;
public:
Employees()
{
head = NULL;
tail = NULL;
}
void addToList(string Name, int Num)
{
node* n = new node;
n->name = Name;
n->number = Num;
n->next = NULL;
if (head == NULL)
{
head = n;
tail = n;
}
else
{
tail->next = n;
tail = tail->next;
}
}
void PrintAll()
{
while (head != NULL)
{
node* current;
while (current != NULL)
{
cout << current->name << "t";
cout << current->number;
}
}
}
};
int main()
{
Employees a;
a.addToList("Robert", 54);
a.addToList("Manny", 77);
a.PrintAll();
}
您的有问题
PrintAll
,其中Head
不变并使其无限循环current
未初始化,作为指针访问它是UB
下面的片段应该解决你的问题,
void PrintAll()
{
node* temp = head;
while (temp != nullptr)
{
std::cout << temp ->name << "t";
std::cout << temp ->number;
temp = temp->next
}
}
对于初学者来说,这个声明在全局命名空间中
struct node
{
string name;
int number;
node* next;
};
struct node* head = 0;
^^^^^^^^^^^^^^^^^^^^^
是多余的,无处使用。移除它。
最好使结构节点成为Employees类的内部成员。例如
class Employees
{
private:
struct node
{
string name;
int number;
node* next;
} *head = nullptr, *tail = nullptr;
//...
构造函数没有做什么特别的事情。因此,它可以被定义为默认构造函数。
Employees() = default;
函数addToList
应通过常量引用接受第一个参数
void addToList( const string &Name, int Num )
^^^^^^^^^^^^^^^^^^
当指针头不是空指针时,函数PrintAll
具有无限循环
void PrintAll()
{
while (head != NULL)
{
//...
}
}
此外,它调用未定义的行为,因为使用的指针电流没有初始化
node* current;
while (current != NULL)
函数应该用限定符const声明,因为它不会更改列表本身。
此外,您还需要一个析构函数来为节点释放动态分配的内存。也可以取消复制构造和指定。
下面是一个演示程序,展示了如何实现类。
#include <iostream>
#include <string>
using namespace std;
class Employees
{
private:
struct node
{
string name;
int number;
node* next;
} *head = nullptr, *tail = nullptr;
public:
Employees() = default;
~Employees()
{
while ( head != nullptr )
{
node *tmp = head;
head = head->next;
delete tmp;
}
tail = nullptr;
}
Employees( const Employees & ) = delete;
Employees & operator =( const Employees & ) = delete;
void addToList( const string &Name, int Num )
{
node *n = new node { Name, Num, nullptr };
if ( head == nullptr )
{
head = n;
tail = n;
}
else
{
tail->next = n;
tail = tail->next;
}
}
void PrintAll() const
{
for ( node *current = head; current != nullptr; current = current->next )
{
cout << current->name << ' ';
cout << current->number << 't';
}
}
};
int main()
{
Employees a;
a.addToList( "Robert", 54 );
a.addToList( "Manny", 77 );
a.PrintAll();
cout << endl;
}
程序输出为
Robert 54 Manny 77
代码的主要问题是PrintAll
方法写得不正确,并且从未更新current
指针。也许您还没有学习过for
循环,但这是它们的理想情况:
for(node* current = head; current != NULL; current = current->next) {
cout << current->name << "t" << current->number;
}
for循环的第一部分初始化变量(您在代码中忽略了这一点(,下一部分是结束条件(正如您在while
循环中发现的那样(,第三部分在循环的每个循环中更新变量,从而从头到尾遍历循环。
您可以使用while
循环来完成所有这些操作,但它表达的意图不太清楚,因此应该首选for
循环。我也不确定为什么你有一个while
循环来检查head
是否为空?由于它在循环过程中不会改变,因此不需要重复检查它,而且在任何情况下,单独检查它都没有好处,而不是在current
初始化为head
后简单地检查它。
需要注意的是,如果您使用的是现代C++版本,nullptr
应该优先于NULL
。
三个问题:
while (head != NULL)
{
/*...*/
}
您没有在循环中修改head
(为什么要修改(,因此此循环将永远或永远运行。
第二:
node* current;
while (current != NULL)
current
未初始化。将其与NULL
进行比较会调用未定义的行为。始终初始化变量!
上一篇:
while (current != NULL)
{
cout << current->name << "t";
cout << current->number;
}
与第一个问题类似,循环条件是true
或false
,但它从未改变,即循环要么从不运行,要么无限运行。
由于这似乎是一个练习,我将由您来修复代码。