Array of Linked List Homework - Runtime Error

2019-07-07 17:56发布

I've been doing this homework assignment and I feel like I've tried anything that I could do, but this is just so frustrating. Basically this program is supposed to simulate the admin console of someone who monitors computers labs. There are 3 options at the main menu, and I've got all of them to work except for the "logoff" function.

The big issue with this program is that the labs are supposed to be arrays and the ID Numbers that are located at a particular computer station are supposed to be stored in a linked list. The part that I am struggling the most with is the linked list.

When I run the program, simulate a login, and then try to logoff my program crashes. So I tried debugging it using Visual Studio, and it's telling me that there is an exception that is unhandled on line 121 (commented below it's located in the logoff function). I tried contacting my teacher multiple times, but he hasn't responded. It would be great if someone could point me in the right direction.

edit: I notice that the remove function could be causing issues. Although it seems to remove the node in the list it seems like there is some garbage data left in one node when I take a look at the debugger. Am I supposed to do some sort of initialization when I remove a node? Like setting variables to NULL or nullptr when I remove a node?

edit 2: I shortened the code. Here is the exception I'm getting: Unhandled exception thrown: read access violation.iter was 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条回答
不美不萌又怎样
2楼-- · 2019-07-07 18:16

This code is almost completely wrong. To fix your code, let's start by not asking for user input. Use predetermined values to make the program easier to debug. You can add user input after you get the basics.

Don't use the declaration typedef User* NodePtr There is nothing wrong with it, but it hides the pointer and it can be confusing at your level.

Linked list should initially be empty, as follows:

for(int i = 0; i < COMPUTER_LABS; i++)
    computerLabs[i] = NULL;

When removing a node, you need different conditions if the node is head or not. Here is a simple version:

#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;
}
查看更多
Juvenile、少年°
3楼-- · 2019-07-07 18:30

Every time you use a delete, you should set the pointer to NULL. You have

delete temp->link

Add

temp->link = NULL

Just after. Nulling deleted pointers is a reasonable precaution. Deleting frees the allocated memory but doesn’t necessarily clear the pointer or set it to NULL. You can check that in the debugger. Set a watch on the pointer. When it’s allocated and in use, you see all the fields. After it gets deleted, the fields will be nonsense because it points to unallocated memory.

查看更多
登录 后发表回答