链表数组作业——运行时错误
Array of Linked List Homework - Runtime Error
我一直在做这个家庭作业,我觉得我已经尝试了我能做的任何事情,但这太令人沮丧了。基本上这个程序应该模拟监控计算机实验室的人的管理控制台。主菜单中有 3 个选项,除了 "logoff" 功能外,我都可以使用它们。
这个程序的大问题是实验室应该是数组,位于特定计算机站的 ID 号应该存储在链表中。我最费劲的部分是链表。
当我运行程序模拟登录,然后尝试注销时我的程序崩溃了。所以我尝试使用 Visual Studio 调试它,它告诉我第 121 行有一个未处理的异常(下面注释它位于注销函数中)。我多次尝试联系我的老师,但他没有回应。如果有人能指出正确的方向,那就太好了。
编辑:我注意到删除功能可能会导致问题。虽然它似乎删除了列表中的节点,但当我查看调试器时,似乎在一个节点中留下了一些垃圾数据。删除节点时是否应该进行某种初始化?就像在删除节点时将变量设置为 NULL 或 nullptr 一样?
编辑 2:我缩短了代码。这是我得到的异常:
抛出未处理的异常:读取访问冲突。iter 是 nullptr。
#include <iostream>
using namespace std;
struct User
{
int IDNumber;
int stationNumber;
User *link;
};
typedef User* NodePtr;
const int COMPUTER_LABS = 4;
const int COMPUTERLAB_SIZES[] = { 5, 6, 4, 3 }; number of labs
void head_insert(NodePtr& head, int IDNum, int stationNum)
{
NodePtr temp_ptr;
temp_ptr = new User;
temp_ptr->IDNumber = IDNum;
temp_ptr->stationNumber = stationNum;
temp_ptr->link = head;
head = temp_ptr;
}
void remove(NodePtr& head, int position)
{
if (head == NULL)
return;
NodePtr temp = head;
if (position == 0)
{
head = temp->link;
delete temp;
return;
}
for (int i = 0; temp != NULL && i<position - 1; i++)
temp = temp->link;
if (temp == NULL || temp->link == NULL)
return;
NodePtr next = temp->link->link;
delete temp->link;
temp->link = next;
}
//This function will take in our multidimensional array and prompt the user for data on simulating a login
//At the end, the spot will be assigned a number
void login(NodePtr labs[])
{
int IDNum, labNum, stationNum;
cout << "Enter the 5 digit ID number of the user logging in: " << endl;
cin >> IDNum;
cout << "Enter the lab number the user is logging in from (1-4): " << endl;
cin >> labNum;
cout << "Enter computer station number the user is logging in to (1-6): " << endl;
cin >> stationNum;
if (labs[labNum - 1]->link == NULL && labs[labNum - 1]->stationNumber == NULL)
{
labs[labNum - 1]->stationNumber = stationNum;
labs[labNum - 1]->IDNumber = IDNum;
}
else
head_insert(labs[labNum - 1], IDNum, stationNum);
}
void showLabs(NodePtr labs[])
{
for (int i = 0; i < COMPUTER_LABS; i++)
{
cout << i + 1 << ": ";
for (int j = 0; j<COMPUTERLAB_SIZES[i]; j++)
{
for (NodePtr iter = labs[i]; iter != NULL; iter = iter->link)
{
if (iter->stationNumber == (j + 1))
{
cout << j + 1 << ": " << (iter->IDNumber) << " ";
break;
}
else if ((iter->link) == NULL && (iter->stationNumber) != (j + 1))
cout << j + 1 << ": empty ";
}
}
cout << endl;
}
}
//This function will simulate a logoff by looking for the ID number that was typed in
//It will then clear that computer station and log the user off
void logoff(NodePtr labs[])
{
int IDNumber;
bool isBreak = false;
cout << "Enter 5 digit ID number of the user to find: " << endl;
cin >> IDNumber;
for (int i = 0; i < COMPUTER_LABS; i++)
{
int j = 0;
for (NodePtr iter = labs[i]; iter != NULL; iter = iter->link, j++) //This is where it says exception unhandled
{
if (iter->IDNumber == IDNumber)
remove(iter, j);
}
}
cout << "User " << IDNumber << " is logged off." << endl << endl;
}
int main()
{
NodePtr computerLabs[COMPUTER_LABS];
for (int i = 0; i < COMPUTER_LABS; i++)//Initialize nodes in array so that we don't get any undefined behavior from not initializing
{
computerLabs[i] = new User;
computerLabs[i]->stationNumber = NULL;
computerLabs[i]->IDNumber = NULL;
computerLabs[i]->link = NULL;
}
int userChoice; //This is for making a choice at the main menu
do
{
cout << "LAB STATUS" << endl;
cout << "Lab # Computer Stations" << endl;
showLabs(computerLabs); //Show the current computer labs and their statuses
cout << endl << "MAIN MENU" << endl;
cout << "0) Quit" << endl;
cout << "1) Simulate login" << endl;
cout << "2) Simulate logoff" << endl;
cin >> userChoice; // ask user for choice
if (userChoice == 1)
login(computerLabs);
else if (userChoice == 2)
logoff(computerLabs);
} while (userChoice != 0);
return 0;
}
每次使用删除时,都应该将指针设置为NULL。你有
delete temp->link
添加
temp->link = NULL
就在这之后。清空已删除的指针是一种合理的预防措施。
删除会释放分配的内存,但不一定会清除指针或将其设置为 NULL。您可以在调试器中进行检查。将手表放在指针上。当它被分配和使用时,你会看到所有的字段。删除后,这些字段将是无意义的,因为它指向未分配的内存。
这段代码几乎完全错误。要修复您的代码,让我们从不要求用户输入开始。使用预先确定的值使程序更易于调试。您可以在掌握基础知识后添加用户输入。
不要使用声明typedef User* NodePtr
它没有任何问题,但它隐藏了指针,在您的水平上可能会造成混淆。
链表最初应该是空的,如下:
for(int i = 0; i < COMPUTER_LABS; i++)
computerLabs[i] = NULL;
删除节点时,节点是否head
需要不同的条件。这是一个简单的版本:
#include <iostream>
using namespace std;
struct User
{
int id;
User *next;
};
const int COMPUTER_LABS = 4;
void login(User *labs[], int lab, int id)
{
User *p = new User;
p->id = id;
p->next = labs[lab];
labs[lab] = p;
}
void logoff(User *labs[], int lab, int id)
{
User *prev = nullptr;
User* walk = labs[lab];
while(walk)
{
if(walk->id == id)
{
User *next = walk->next;
delete walk;
if(prev)
prev->next = next;
else
labs[lab] = next;
break;
}
prev = walk;
walk = walk->next;
}
}
void showLabs(User *labs[])
{
for(int i = 0; i < COMPUTER_LABS; i++)
{
cout << "Lab number " << i << ": ";
User* walk = labs[i];
while(walk)
{
cout << "id: " << walk->id << ", ";
walk = walk->next;
}
cout << endl;
}
}
int main()
{
User *labs[COMPUTER_LABS];
for(int i = 0; i < COMPUTER_LABS; i++)
{
//linked list is initially empty, this is "head"
labs[i] = NULL;
}
login(labs, 0, 100);
login(labs, 0, 101);
login(labs, 1, 200);
login(labs, 1, 201);
showLabs(labs);
logoff(labs, 0, 100);
showLabs(labs);
return 0;
}
我一直在做这个家庭作业,我觉得我已经尝试了我能做的任何事情,但这太令人沮丧了。基本上这个程序应该模拟监控计算机实验室的人的管理控制台。主菜单中有 3 个选项,除了 "logoff" 功能外,我都可以使用它们。
这个程序的大问题是实验室应该是数组,位于特定计算机站的 ID 号应该存储在链表中。我最费劲的部分是链表。
当我运行程序模拟登录,然后尝试注销时我的程序崩溃了。所以我尝试使用 Visual Studio 调试它,它告诉我第 121 行有一个未处理的异常(下面注释它位于注销函数中)。我多次尝试联系我的老师,但他没有回应。如果有人能指出正确的方向,那就太好了。
编辑:我注意到删除功能可能会导致问题。虽然它似乎删除了列表中的节点,但当我查看调试器时,似乎在一个节点中留下了一些垃圾数据。删除节点时是否应该进行某种初始化?就像在删除节点时将变量设置为 NULL 或 nullptr 一样?
编辑 2:我缩短了代码。这是我得到的异常: 抛出未处理的异常:读取访问冲突。iter 是 nullptr。
#include <iostream>
using namespace std;
struct User
{
int IDNumber;
int stationNumber;
User *link;
};
typedef User* NodePtr;
const int COMPUTER_LABS = 4;
const int COMPUTERLAB_SIZES[] = { 5, 6, 4, 3 }; number of labs
void head_insert(NodePtr& head, int IDNum, int stationNum)
{
NodePtr temp_ptr;
temp_ptr = new User;
temp_ptr->IDNumber = IDNum;
temp_ptr->stationNumber = stationNum;
temp_ptr->link = head;
head = temp_ptr;
}
void remove(NodePtr& head, int position)
{
if (head == NULL)
return;
NodePtr temp = head;
if (position == 0)
{
head = temp->link;
delete temp;
return;
}
for (int i = 0; temp != NULL && i<position - 1; i++)
temp = temp->link;
if (temp == NULL || temp->link == NULL)
return;
NodePtr next = temp->link->link;
delete temp->link;
temp->link = next;
}
//This function will take in our multidimensional array and prompt the user for data on simulating a login
//At the end, the spot will be assigned a number
void login(NodePtr labs[])
{
int IDNum, labNum, stationNum;
cout << "Enter the 5 digit ID number of the user logging in: " << endl;
cin >> IDNum;
cout << "Enter the lab number the user is logging in from (1-4): " << endl;
cin >> labNum;
cout << "Enter computer station number the user is logging in to (1-6): " << endl;
cin >> stationNum;
if (labs[labNum - 1]->link == NULL && labs[labNum - 1]->stationNumber == NULL)
{
labs[labNum - 1]->stationNumber = stationNum;
labs[labNum - 1]->IDNumber = IDNum;
}
else
head_insert(labs[labNum - 1], IDNum, stationNum);
}
void showLabs(NodePtr labs[])
{
for (int i = 0; i < COMPUTER_LABS; i++)
{
cout << i + 1 << ": ";
for (int j = 0; j<COMPUTERLAB_SIZES[i]; j++)
{
for (NodePtr iter = labs[i]; iter != NULL; iter = iter->link)
{
if (iter->stationNumber == (j + 1))
{
cout << j + 1 << ": " << (iter->IDNumber) << " ";
break;
}
else if ((iter->link) == NULL && (iter->stationNumber) != (j + 1))
cout << j + 1 << ": empty ";
}
}
cout << endl;
}
}
//This function will simulate a logoff by looking for the ID number that was typed in
//It will then clear that computer station and log the user off
void logoff(NodePtr labs[])
{
int IDNumber;
bool isBreak = false;
cout << "Enter 5 digit ID number of the user to find: " << endl;
cin >> IDNumber;
for (int i = 0; i < COMPUTER_LABS; i++)
{
int j = 0;
for (NodePtr iter = labs[i]; iter != NULL; iter = iter->link, j++) //This is where it says exception unhandled
{
if (iter->IDNumber == IDNumber)
remove(iter, j);
}
}
cout << "User " << IDNumber << " is logged off." << endl << endl;
}
int main()
{
NodePtr computerLabs[COMPUTER_LABS];
for (int i = 0; i < COMPUTER_LABS; i++)//Initialize nodes in array so that we don't get any undefined behavior from not initializing
{
computerLabs[i] = new User;
computerLabs[i]->stationNumber = NULL;
computerLabs[i]->IDNumber = NULL;
computerLabs[i]->link = NULL;
}
int userChoice; //This is for making a choice at the main menu
do
{
cout << "LAB STATUS" << endl;
cout << "Lab # Computer Stations" << endl;
showLabs(computerLabs); //Show the current computer labs and their statuses
cout << endl << "MAIN MENU" << endl;
cout << "0) Quit" << endl;
cout << "1) Simulate login" << endl;
cout << "2) Simulate logoff" << endl;
cin >> userChoice; // ask user for choice
if (userChoice == 1)
login(computerLabs);
else if (userChoice == 2)
logoff(computerLabs);
} while (userChoice != 0);
return 0;
}
每次使用删除时,都应该将指针设置为NULL。你有
delete temp->link
添加
temp->link = NULL
就在这之后。清空已删除的指针是一种合理的预防措施。 删除会释放分配的内存,但不一定会清除指针或将其设置为 NULL。您可以在调试器中进行检查。将手表放在指针上。当它被分配和使用时,你会看到所有的字段。删除后,这些字段将是无意义的,因为它指向未分配的内存。
这段代码几乎完全错误。要修复您的代码,让我们从不要求用户输入开始。使用预先确定的值使程序更易于调试。您可以在掌握基础知识后添加用户输入。
不要使用声明typedef User* NodePtr
它没有任何问题,但它隐藏了指针,在您的水平上可能会造成混淆。
链表最初应该是空的,如下:
for(int i = 0; i < COMPUTER_LABS; i++)
computerLabs[i] = NULL;
删除节点时,节点是否head
需要不同的条件。这是一个简单的版本:
#include <iostream>
using namespace std;
struct User
{
int id;
User *next;
};
const int COMPUTER_LABS = 4;
void login(User *labs[], int lab, int id)
{
User *p = new User;
p->id = id;
p->next = labs[lab];
labs[lab] = p;
}
void logoff(User *labs[], int lab, int id)
{
User *prev = nullptr;
User* walk = labs[lab];
while(walk)
{
if(walk->id == id)
{
User *next = walk->next;
delete walk;
if(prev)
prev->next = next;
else
labs[lab] = next;
break;
}
prev = walk;
walk = walk->next;
}
}
void showLabs(User *labs[])
{
for(int i = 0; i < COMPUTER_LABS; i++)
{
cout << "Lab number " << i << ": ";
User* walk = labs[i];
while(walk)
{
cout << "id: " << walk->id << ", ";
walk = walk->next;
}
cout << endl;
}
}
int main()
{
User *labs[COMPUTER_LABS];
for(int i = 0; i < COMPUTER_LABS; i++)
{
//linked list is initially empty, this is "head"
labs[i] = NULL;
}
login(labs, 0, 100);
login(labs, 0, 101);
login(labs, 1, 200);
login(labs, 1, 201);
showLabs(labs);
logoff(labs, 0, 100);
showLabs(labs);
return 0;
}