Я работаю над заданием на 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;
}
Вот изображение для справки:
Если кто-нибудь мог бы предложить некоторое представление о том, чтопроблема может быть, я очень признателен.
Спасибо