链接列表作业数组 - 运行时错误

时间:2018-02-03 19:09:45

标签: c++ pointers exception-handling nullpointerexception linked-list

我一直在做这个家庭作业,我觉得我已经尝试过任何我能做的事,但这真是令人沮丧。基本上这个程序应该模拟监视计算机实验室的人的管理控制台。主菜单有3个选项,除了"注销"以外,我已经完成了所有选项。功能

这个程序的一个大问题是实验室应该是数组,并且位于特定计算机站的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;
}

2 个答案:

答案 0 :(得分:3)

这段代码几乎完全错误。要修复代码,请首先不要求用户输入。使用预定值使程序更容易调试。获得基础知识后,您可以添加用户输入。

不要使用声明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;
}

答案 1 :(得分:2)

每次使用删除时,都应将指针设置为NULL。

delete temp->link

添加

temp->link = NULL

刚刚过去。删除已删除的指针是一种合理的预防措施。 删除释放已分配的内存,但不一定清除指针或将其设置为NULL。您可以在调试器中检查它。在指针上设置手表。当它被分配和使用时,您会看到所有字段。删除后,字段将是无意义的,因为它指向未分配的内存。