EXC_BAD_ACCESS при работе со связанными списками - PullRequest
0 голосов
/ 12 октября 2019

Я работаю над заданием на C ++, особенно работаю со связанными списками и динамическим распределением памяти. Я пытаюсь указать следующую переменную узла для нового узла (сотрудника), который я только что создал .. другими словами, добавить нового сотрудника в связанный список. Когда я запускаю проект, все работает нормально, пока я не введу имя сотрудника, которого я хотел бы создать;Я получаю следующую ошибку:

Thread 1: EXC_BAD_ACCESS (code=1, address=0x20)

Из проведенного мной исследования это означает, что я пытался получить доступ к еще не выделенному адресу памяти или пытался записать в статически выделенную память... но я новичок в этом динамическом распределении памяти и немного запутался.

Вот мой заголовочный файл:

//  mainmenu.h
//  Lab05
//
//  Created by Carson Clark on 2019-10-10.
//  Copyright © 2019 Carson Clark. All rights reserved.
//

ifndef mainmenu_h
define mainmenu_h
// The MainMenu (.h & .cpp) file contains the function declarations used to
// present a main menu which allows a user to view, add, and remove employees.
// The list of employees is implemented with a linked list, and most of the
// processing functions get passed a pointer to the first element of the
// list (Employee* pHead).
#include <string>

// a struct to represent an Employee (each instance forms a node of a linked list
// used to store employees.
struct Employee {
    int id;
    std::string fname;
    Employee* next;
};

// A struct used to return multiple return values from the getNodeInfo() function.
struct NodeInfo {
    Employee* node;    // a pointer to an employee node.
    Employee* parent;    // a pointer to the node prior to the employee node (nullptr if node is at the front)
};

// display the main menu
void displayMainMenu();

// fetch and return an integer from user input
int getInt();

// output a list of all employees to the console
void viewEmployees(Employee* pHead);

// creates a new employee by allocating one from the heap and returning a pointer to it.
Employee* createEmployee(const std::string& fName);

// responsible for creating a new employee node, and adding it to the list
void addNewEmployee(Employee*& pHead, const std::string& fName);

// Searches through the list for a node with the given id.  Returns a nodeInfo struct pointing to the node and its parent.
NodeInfo getNodeInfo(Employee* pHead, int id);

// Removes an employee node with the given id from the list.
void removeEmployee(Employee*& pHead, int id);

// Given an int representing a menu choice, this will determine what should be done for each choice.
bool handleMenuInput(Employee*& pHead, int menuItemSelected);


endif /* mainmenu_h */

Вот mainmenu.cpp (где происходит ошибка)

//
//  mainmenu.cpp
//  Lab05
//
//  Created by Carson Clark on 2019-10-10.
//  Copyright © 2019 Carson Clark. All rights reserved.
//

#include <stdio.h>
// See comments in MainMenu.h for general details on what each functin does.
#include <iostream>
#include "mainmenu.h"

// output the menu choices to the console.
void displayMainMenu()
{
    std::cout << "\n";
    std::cout << "--- MENU ---\n";
    std::cout << "1) View Employees\n";
    std::cout << "2) Add Employee\n";
    std::cout << "3) Remove Employee\n";
    std::cout << "0) Exit\n";
    std::cout << "-------------\n";
    std::cout << "Select:";
}


// Attempt to read an int from cin.
// Check if there was a failure, if so, return -1.
int getInt() {
    int x;
    std::cin >> x;
    if (std::cin.fail()) {
        std::cin.clear();
        std::cin.ignore(32767, '\n');
        x = -1;
    }
    return x;
}


// if pHead is a nullptr:
//    - print a "empty list" message to the user
// if pHead not a nullptr,
//        - create a pCurr variable to point to pHead,
//        - while pCurr is not a nullptr,
//                - print the id and name out to the console
//                - set pCurr to point to the next node.
void viewEmployees(Employee* pHead) {
    // TODO
    if (pHead == nullptr) {
        std::cout << "\n empty list \n";
    } else {
        Employee* pCurr = pHead;
        while (pCurr != nullptr) {
            std::cout << pCurr->id << pCurr->fname << std::endl;
            pCurr = pCurr->next;
        }
    }
}


// Use a static variable to generate unique employee id's with (initialize it &
// increment it every time this function is called).
// Dynamically allocate memory for an employee struct from the heap.
//         Initialize it with :
//                -the unique id,
//                -the fName passed in as a paramter,
//                -nullptr.
// Return the pointer to the new dynamically allocated Employee.
Employee* createEmployee(const std::string& fName) {
    // TODO
    static int uniqueID = 0;
    uniqueID++;
    Employee* pEmp = new Employee{uniqueID, fName, nullptr};

    return pEmp;  // replace this, it is only here to allow this to compile
}


// First Create a new employee (by calling createEmployee())
// Insert the new employee at the front of the linked list
//        - point the new employee's next pointer to the existing head.
//        - point the existing head at the new employee
void addNewEmployee(Employee*& pHead, const std::string& fName) {
    // TODO
    Employee* pNewEmp = createEmployee(fName);
    // Inserting new employee at the front of the linked list
    // connect new node to existing node (pointing new next to old)
    pNewEmp->next = pHead;
    // connect head to new node by pointing head next to new emp
    pHead->next = pNewEmp;
}


// Search through the linked list for a node whose id matches the id parameter
// Return a NodeInfo struct to tell the calling function details about your findings.
// Start by initializing its members to nullptr.
// Use an Employee* pCurr var to iterate through the linked list (while pCurr->id != id)
//
// If you find a match,
//        set your nodeInfo.node to the node you matched.
//        set your nodeInfo.parent to the parent of the node you matched *.
//        return nodeInfo
// If no match found simply return nodeInfo as is. (The calling function (removeEmployee())
// should interpret the nullptr vars to mean not found)
//
//        (* To track the parent, create a local Employee* pLast, set it to nullptr,
//        then update it to point to pCurr right before you move pCurr to point to the
//    next node. If you find a match, pLast will then be pointing to the parent.)
NodeInfo getNodeInfo(Employee* pHead, int id) {
    // TODO
    return NodeInfo{ nullptr, nullptr };    // temporary return value so that the project will compile
}


// If pHead is a nullptr, then there are no employees to remove, output an error message and return
// Try to find a node with the given id (use getNodeInfo()).
// If not found, output an error message and return
// If found:
//        If pHead is the same as the node we found for the id, (it means the node we found is
//    the first one in the list). This is a special case:
//            -Set the pHead to node->next (The first param is a reference so that we can,
//               change the address that pHead points to and have it affect the caller).
//            -Return the memory of the node we want to delete to the heap
//        otherwise
//            (the node we found isn't the first one - it should theoretically have a parent)
//            -If the parent is a nullptr, print an error message (this should never happen, but we should check)
//            -If the parent is not a nullptr
//                -Set the parent's next pointer to the next pointer of the node we want to delete
//                -Output a "removed id: #" message to the console
//                -Deallocate memory from node back to the heap.
void removeEmployee(Employee*& pHead, int id) {
    // TODO
}


// This function is called when a user picks a selection from the menu.
// It determines what action to take depending on the menuItemSelected, and calls
// the appropriate function.
// Returns true the selection was a request to exit menu, false otherwise.
bool handleMenuInput(Employee*& pHead, int menuItemSelected)
{
    bool exitRequest{ false };

    switch (menuItemSelected)
    {
    case 1:
        std::cout << ">> View Employees:\n";
        viewEmployees(pHead);
        break;
    case 2:
    {
        std::cout << ">> Add Employee:\n";
        std::cout << "Enter first name:";
        std::string fName;
        std::cin >> fName;
        addNewEmployee(pHead, fName);
    }
    break;
    case 3:
        std::cout << ">> Remove Employee:\n";
        std::cout << "Enter id:";
        int id;
        std::cin >> id;
        removeEmployee(pHead, id);
        break;
    case 0:
        std::cout << "Exiting\n";
        exitRequest = true;
        break;
    default:
        std::cout << "Invalid input.\n";
        break;
    }
    return exitRequest;
}

Вот main.cpp

//
//  main.cpp
//  Lab05
//
//  Created by Carson Clark on 2019-10-10.
//  Copyright © 2019 Carson Clark. All rights reserved.
//

#include <iostream>
#include "mainmenu.h"



// Set up a pointer for tracking a linked list of Employees
// Display a menu allowing a user various choices, and process those choices
// Clean up any dynamically allocated memory before finishing
int main()
{
    // a pointer to our linked list of employees.
    Employee* pEmployees = nullptr;

    bool exitMainMenu{ false };    // init to default value
    int menuChoice{ -1 };            // init to a known starting value

    // display the main menu, allow the user to make choices, and handle the input
    do {
        displayMainMenu();
        int menuChoice{ getInt() };
        while (menuChoice == -1) {
            std::cout << "Invalid input.\n";
            displayMainMenu();
            menuChoice = getInt();
        }
        // handle the input, determine if we have an exit condition
        exitMainMenu = handleMenuInput(pEmployees, menuChoice);
    } while (!exitMainMenu);

    // cleanup! - deallocate any employees in our linked list before setting the list to nullptr;
    // TODO



    return 0;
}

Вот изображение для справки: Error

Если кто-нибудь мог бы предложить некоторое представление о том, чтопроблема может быть, я очень признателен.

Спасибо

...