Hash Tables seg fault - c++

So I'm really not sure what is causing the seg fault but I have a feeling that it has something to do with hashTables since the debugger shows it seg faults right at this line its involved with.
Here is the code that is causing the seg fault
//Constructor for hashtable
HashTable::HashTable()
{
for(int i = 0; i < 10; i++)
{
hashTable[i] = new Movie;
hashTable[i]->title = "empty";
hashTable[i]->year = 0;
hashTable[i]->next = NULL;
}
}
//destructor for hashtable
HashTable::~HashTable()
{
}
// this will take a string and convert the letters to hash numbers then add them all together and divide by the hash table size to get a index
int HashTable::initHash(std::string in_title)
{
int hashT = 0;
int index = 0;
for(int i = 0; i < in_title.length(); i++)
{
hashT = hashT + (int)in_title[i];
std::cout << "hash = " << hashT << std::endl;
}
index = hashT % 10;
std::cout << "index = " << index << std::endl;
return index;
}
//This is where we will be inserting a new Movie into the hashtable,
//it will first use initHash to find the number of where it should go in the hash and then from there add it to the hashtable
void HashTable::insertMovie(std::string in_title, int year)
{
int index = initHash(in_title);
std::cout << "index = " << index << std::endl;
if (hashTable[index]->title == "empty") // *** seg faults right here ***
{
hashTable[index]->title = in_title;
hashTable[index]->year = year;
}
else
{
Movie* Ptr = hashTable[index];
Movie* n = new Movie;
n->title = in_title;
n->year = year;
n->next = NULL;
while(Ptr->next != NULL)
{
Ptr = Ptr->next;
}
Ptr->next = n;
}
}
in each of my functions containing hashTables[index] it seg faults but I'm not exactly sure why, the index comes back with a number that should work. does anyone know why this would happen?
edit: Ok here is the two classes that matter from my header file
struct Movie{
std::string title;
int year;
Movie *next;
Movie(){};
Movie(std::string in_title, int in_year)
{
title = in_title;
year = in_year;
}
};
class HashTable
{
public:
HashTable();
~HashTable();
void insertMovie(std::string in_title, int year);
int initHash(std::string in_title);
int NumberofItemsInIndex(int index);
Movie* findMovie(std::string in_title/*, int *index*/);
void deleteMovie(std::string in_title);
void printInventory();
void PrintItemsInIndex(int index);
protected:
private:
Movie **hashTable;
};
edit 2: Here is the main() function
int main(int argc, char * argv[])
{
// Declarations
int input; // Declaring an input for the menu
bool quit = false; // Bool for the menu
//string title; // input value for certain actions
//int year; // input value for certain actions
HashTable *ht;
//int index;
//readFileIntoHash(ht, argv[1]);
while(quit != true)
{
displayMenu(); // Displays the main menu
cin >> input;
//clear out cin
cin.clear();
cin.ignore(10000, '\n');
switch (input)
{
// Insert a movie
case 1:
{
string in_title;
int year;
cout << "Enter Title:" << endl;
cin >> in_title;
cout << "Enter Year:" << endl;
cin >> year;
ht -> insertMovie(in_title, year);
break;
}
// Delete a movie
case 2:
{
string in_title2;
cout << "Enter Title:" << endl;
cin >> in_title2;
ht -> deleteMovie(in_title2);
break;
}
// Find a movie
case 3:
{
string in_title3;
cout << "Enter Title:" << endl;
cin >> in_title3;
ht -> findMovie(in_title3);
break;
}
// Print table contents
case 4:
ht -> printInventory();
break;
case 5:
cout << "Goodbye!" << endl;
quit = true;
break;
// invalid input
default:
cout << "Invalid Input" << endl;
cin.clear();
cin.ignore(10000,'\n');
break;
}
}
return 0;
}
void displayMenu()
{
cout << "======Main Menu=====" << endl;
cout << "1. Insert movie" << endl;
cout << "2. Delete movie" << endl;
cout << "3. Find movie" << endl;
cout << "4. Print table contents" << endl;
cout << "5. Quit" << endl;
return;
}
I added displayMenu() for clarity's sake.

Modify the class definition:
class HashTable
{
public:
HashTable();
~HashTable();
void insertMovie(std::string in_title, int year);
int initHash(std::string in_title);
int NumberofItemsInIndex(int index);
Movie* findMovie(std::string in_title/*, int *index*/);
void deleteMovie(std::string in_title);
void printInventory();
void PrintItemsInIndex(int index);
protected:
private:
Movie *hashTable[10]; /*<<-- since your size is fixed use an array*/
};
Also.. since you allocated Movies in the constructor, remember to deallocate them on destructor:
//destructor for hashtable
HashTable::~HashTable()
{
for(int i = 0; i < 10; i++)
{
delete hashTable[i];
}
}
Alternative, use dynamically allocated memory (with your same class definition)
HashTable::HashTable()
{
hashTable = new (Movie*) [10];
for(int i = 0; i < 10; i++)
{
hashTable[i] = new Movie;
hashTable[i]->title = "empty";
hashTable[i]->year = 0;
hashTable[i]->next = NULL;
}
}
and
HashTable::~HashTable()
{
for(int i = 0; i < 10; i++)
{
delete hashTable[i];
}
delete[] hashTable;
}
Additional fix:
modify main function:
int main(int argc, char * argv[])
{
// Declarations
int input; // Declaring an input for the menu
bool quit = false; // Bool for the menu
//string title; // input value for certain actions
//int year; // input value for certain actions
HashTable ht; // <<==== local variable, not a pointer!
... and then replace ht->xxxx(...) for ht.xxxx(...) elsewhere.

hashTable[i] = new Movie; there you allocate memory for Movie
but memory for Movie **hashTable; was not alllocated
try to add hashTable = new Movie *[100]; to constructor

This constructor perhaps:
HashTable::HashTable()
{
hashTable = new (Movie*) [10]; // Allocate memory on the heap for the array
for(int i = 0; i < 10; i++)
{
hashTable[i] = new Movie;
hashTable[i]->title = "empty";
hashTable[i]->year = 0;
hashTable[i]->next = NULL;
}
}
However, there is actually no need have an array of Movie pointers in your hashmap, you could simply have an array of Movie objects instead. Actually, you want a linked list so my bad. Also, I would not write 10 everywhere, rather use a constant so you could change the size later.
When you get this to work, you should write a destructor to avoid memory leaks. Hint: couple each call to new with a call to delete (and new[] with delete[]).

Related

Creating a vector in class then using class object in function not working

I have a class Employees. I'm trying to make the user insert and delete an employee but it's not working. The size of the vectors should be 500.
class Employees{
public:
int maxx = 500;
vector<string> Surname;
vector<string> FirstName;
vector<string> birthdate;
int vacation[500];
public:
Employees() : Surname(500) {}
};
This is the function that inserts, but printing elements of the vectors is not working at all:
void Process(Employees ZZ){
string dateyear;
string datemonth;
string dateday;
int dateyear1;
int datemonth1;
int dateday1;
int Realage;
int Vacationi = 0;
for(int i = 0; i < 500; i++) {
string s;
cin >> s;
string d;
cin >> d;
string c;
cin >> c;
ZZ.Surname.push_back(s);
ZZ.FirstName.push_back(d);
ZZ.birthdate.push_back(c);
cout << endl << ZZ.Surname[1] << endl;
}
Now the delete function, if I input a string then search for it in the vector then get his index then delete, but the vector doesn't update any values.
void DeleteEmployee(Employees ZZ){
cout<< endl << ZZ.Surname[1] << endl ;
for (int i = 0; i < ZZ.Surname.size(); i++){
cout << ZZ.Surname[i] ;
}
cout << " delete employee";
string delete1;
cin >> delete1;
auto it = std::find(ZZ.Surname.begin(), ZZ.Surname.end(), delete1);
if (it == ZZ.Surname.end())
{
cout<< " name not in vector " << endl;
}
else
{
//auto index = distance(Names.begin(), find(Names.begin(), Names.end(), old_name_)));
//ZZ.Surname.erase(ZZ.Surname.begin()+index) ;
}
}
This is the main function, also the values of the vector are not printing:
int main()
{
Employees ZZ;
Process(ZZ);
DeleteEmployee(ZZ);
cout << "fyccck";
for (int i = 0; i < ZZ.Surname.size(); i++){
cout << ZZ.Surname[i] ;
}
}
There are a lot of things wrong with this code. But the particular issue you are asking about is caused by your functions passing the Employees object by value, so a copy is made, and any changes you make to the copy are not reflected in the original object in main().
You need to change the parameters to pass the Employees object by reference instead:
void Process(Employees &ZZ)
void DeleteEmployee(Employees &ZZ)
That being said, the whole design of the code is not good in general. The vectors are not being kept in sync properly, and for that matter you are using more vectors then you actually need, 1 single vector will suffice. And Process() and DeleteEmployee() should be members of the Employees class, not separate functions. And they are both accessing out-of-bounds of the Surname vector.
I would suggest completely rewriting the code from scratch, for instance something more like this:
struct Employee{
string Surname;
string FirstName;
string BirthDate;
int Vacation;
string DisplayName() const { return Surname + ", " + FirstName; }
};
class Employees{
public:
static const int maxx = 500;
vector<Employee> employees;
Employees() { employees.reserve(maxx); }
bool Add(const Employee &e);
bool Delete(string Surname, string FirstName);
};
bool Employees::Add(const Employee &e) {
if (employees.size() < maxx) {
employees.push_back(e);
return true;
}
return false;
}
bool Employees::Delete(string Surname, string FirstName) {
auto it = std::find_if(employees.begin(), employees.end(),
[&](const Employee &e){
return e.Surname == Surname && e.FirstName == FirstName;
}
);
if (it != employees.end()) {
employees.erase(it);
return true;
}
return false;
}
int main()
{
Employees ZZ;
for(int i = 0; i < Employees::maxx; ++i) {
Employee e;
cin >> e.Surname;
cin >> e.FirstName;
cin >> e.BirthDate;
e.Vacation = 0;//cin >> e.Vacation;
ZZ.Add(e);
cout << endl << e.DisplayName() << endl;
}
cout << " delete employee";
string Surname, FirstName;
if (cin >> Surname >> FirstName) {
if (ZZ.Delete(Surname, FirstName)) {
cout << " name deleted from vector " << endl;
} else {
cout << " name not in vector " << endl;
}
}
cout << "fyccck";
for (auto &e : ZZ.employees) {
cout << e.DisplayName() << endl;
}
return 0;
}

Open address hashtable segmentation fault

Iam trying to create an open addressed hash table. The user has to be able to define the table's size. For my collision resolution I am using psuedo random probing -
http://algoviz.org/OpenDSA/Books/OpenDSA/html/HashCImproved.html#HashingPseudoRandomProbePRO
Anyway the hashing function(s) seem to work fine until I only have 1 more space to fill in the table. As soon as I input the final element of the table my program crashes and I get a segmentation fault. I've been pulling my hair out trying to find the problem for hours. Please help!
#include <iostream>
#include <string>
#include <sstream>
#include <algorithm>
#include <vector>
using namespace std;
class HashTable
{
string* hash;
bool* inTable;
vector<int> perm;
int table_size;
int permFunc(int, int);
void permutation();
int hashFunc(string);
public:
//constructor for a hashtable
HashTable(int);
//deconstructor for hashtable
~HashTable();
bool isFull();
//The prototype for the insert method
void insert(string);
//The prototype for the lookup method
bool lookup(string);
//The prototype for the remove method
void remove(string);
//The prototype for the size method
int size();
//The prototype for the print method
void print();
};
//constructor
HashTable::HashTable(int table_size)
{
this -> table_size = table_size;
hash = new string[table_size];
inTable = new bool[table_size];
for(int i=0; i<table_size; i++) perm.push_back(i);
permutation();
}
//deconstructor
HashTable::~HashTable()
{
delete [] hash;
delete [] inTable;
}
//creates a permutation of the perm vectors index elements
void HashTable::permutation()
{
random_shuffle ( perm.begin() + 1, perm.end() );
}
//Hash function method for strings
int HashTable::hashFunc(string str)
{
int key = 0;
for (int i=0; i < str.size(); i++)
{
key += static_cast<int>(str.at(i));
}
cout << "key is:" << key << endl;
return key%table_size;
}
int HashTable::permFunc(int index, int i)
{
int temp = index;
index += perm[i];
if(index > table_size){index = index - table_size;}
if(inTable[index] == false ){return index;}
index = temp;
i++;
permFunc(index, i);
}
bool HashTable::isFull()
{
int num=0;
for(int i=0;i<table_size; i++)
{
if(inTable[i] == true){num ++;}
if(num == table_size){
cout<<"FULL TABLE";
return true;}
}
return false;
}
//Method that inserts an integer into the hash table
void HashTable::insert(string str)
{
int i=1;
if(isFull()){return;}
int pos = hashFunc(str);
if(inTable[pos] == true)
{
int permPos = permFunc(pos, i);
hash[permPos] = str;
inTable[permPos] = true;
}
else
hash[pos] = str;
inTable[pos] = true;
}
//A function that prints out the menu
void menu()
{
cout << endl;
cout << "press i to insert an element into the hash table" << endl;
cout << "press d to inTableete an element from the hash table" << endl;
cout << "press l to look up an element" << endl;
cout << "press s to obtain the size of the table" << endl;
cout << "press p to print the current table" << endl;
return;
}
//The main method
//Implements all the input and output
int main(void)
{
int table_size;
cout << "Enter table size: ";
cin >> table_size;
HashTable h(table_size);
while(true)
{
char c;
string str;
menu();
getline(cin, str);
stringstream stream;
stream << str;
stream >> c;
switch(c)
{
case 'i':
getline(cin, str);
h.insert(str);
break;
case 'd':
getline(cin, str);
h.remove(str);
break;
case 'l':
getline(cin, str);
cout << h.lookup(str) << "\n";
break;
case 's':
cout << h.size() << "\n";
break;
case 'p':
h.print();
break;
default:
cout << "Don't understand '" << c << "'\n";
}
}
return 0;
}
I don't know if this is your problem but this line:
if(index > table_size){index = index - table_size;}
will leave index at table_size which is out of bounds for your array. Change the > to >=
If this isn't it, could you add an example crashing input to your post, for testing?

C++ - Vector Segmentation Error

I am currently working on a CMSC project called Blackjack for my college course. I have am trying to add a class called Card to a vector object in another class called Hand. The Hand class is stored as an object in another vector in a class called Player.
My issue is that I try to call the method OutputPlayerHand in a class called Blackjack but I get a segmentation error.
Here is my code for the Blackjack.cpp class.
#include "Blackjack.h"
#include <iostream>
Blackjack::Blackjack()
{
// Initialize the dealer
Player dealer((char *) "Dealer", 100);
m_dealer = dealer;
// Initialize a player 'Jane' with 100 funds
Player player((char *) "Jane", 100);
m_players.push_back(player);
}
Blackjack::Blackjack(char *names[], int numPlayers)
{
// Initialize the dealer
Player dealer((char *) "Dealer", 100);
m_dealer = dealer;
// Loop through all passed player names
for(int i = 0; i < numPlayers; i++)
{
// Initialize a player 'names[i]' with 100 funds
Player player(names[i], 100);
m_players.push_back(player);
}
}
int Blackjack::GetNumPlayers()
{
// Return the size of the players vector
return m_players.size();
}
char *Blackjack::GetPlayerName(int player)
{
// Return the requested player's name
return m_players[player].GetName();
}
int Blackjack::GetPlayerFunds(int player)
{
// Return the requested player's funds
return m_players[player].GetFunds();
}
void Blackjack::SetPlayerFunds(int player, int amt)
{
// Set the requested player's funds
m_players[player].SetFunds(amt);
}
bool Blackjack::SetPlayerBet(int player, int amt)
{
// If the player has insufficient funds
if(m_players[player].GetFunds() < amt)
{
// Return false
return false;
}
// Subtract the amount from the player funds
m_players[player].SetFunds(m_players[player].GetFunds() - amt);
// Add the amount to the player bet
m_players[player].SetBet(amt);
// Return true
return true;
}
void Blackjack::NewDeal()
{
// Create a new unsorted 52 card deck
Deck deck;
// Initialize m_deck to the new deck
m_deck = deck;
// Shuffle m_deck
m_deck.Shuffle();
// 2 cards for dealer, 2 cards for each player
int cardsToDeal = 2 + (2 * m_players.size());
// While we still have cards to deal
while(cardsToDeal > 0)
{
// Deal to each player
for(unsigned int i = 0; i < m_players.size(); i++)
{
std::cout << "Deal Player Card" << std::endl;
// Deal one card to the player
m_players[i].GetHand().AddCard(m_deck.DealCard());
// Decrement the number of cards to deal
cardsToDeal--;
}
std::cout << "Deal Dealer Card" << std::endl;
// Deal the dealer one card
m_dealer.GetHand().AddCard(m_deck.DealCard());
// Decrement the number of cards to deal
cardsToDeal--;
}
}
void Blackjack::OutputPlayerHand(int player)
{
std::cout << "Player Output Card." << std::endl;
m_players[player].GetHand().GetCard(0).OutputCard();
}
void Blackjack::OutputDealerHand()
{
// TODO: Code Method
}
bool Blackjack::HitPlayer(int player)
{
// TODO: Code Method
return false;
}
void Blackjack::DealerPlay()
{
// TODO: Code Method
}
int Blackjack::SettlePlayerBet(int player)
{
// TODO: Code Method
return -1;
}
Here is my code for the Player.cpp class.
#include "Player.h"
Player::Player()
{
m_name = (char *) "Jane";
m_funds = 100;
m_bet = 0;
}
Player::Player(char *name, int funds)
{
m_name = name;
m_funds = funds;
m_bet = 0;
}
char *Player::GetName()
{
return m_name;
}
void Player::SetName(char *name)
{
m_name = name;
}
int Player::GetFunds()
{
return m_funds;
}
void Player::SetFunds(int funds)
{
m_funds = funds;
}
int Player::GetBet()
{
return m_bet;
}
void Player::SetBet(int bet)
{
m_bet = bet;
}
Hand Player::GetHand()
{
return m_hand;
}
Here is my code for the Hand.cpp class.
#include "Hand.h"
void Hand::AddCard(Card card)
{
m_cards.push_back(card);
}
Card Hand::GetCard(int card)
{
return m_cards[card];
}
int Hand::Size()
{
return m_cards.size();
}
void Hand::Clear()
{
m_cards.clear();
}
Here is my code for the main class Proj2.cpp.
/*
* CHANGES TO Blackjack.h SPEC:
* added new member funcs:
* char *GetPlayerName(int)
* int GetNumPlayers()
* void OutputDealerHand()
*
* HitPlayer() should print out the card that was dealt.
*/
#include <cstdlib>
#include <iostream>
#include "Blackjack.h"
using namespace std;
Blackjack *CreateGame(int argc, char *argv[]);
int ProcessArgs(int argCnt, char *args[], char **&names, int *&funds);
void DoNewDeal(Blackjack &game);
void ProcAllBets(Blackjack &game);
void DoAllPlays(Blackjack &game);
void PlayOnePlayer(Blackjack &game, int player);
void SettleAllPlayers(Blackjack &game);
void ShowAllPlayerFunds(Blackjack &game);
bool QueryAnotherRound();
int main(int argc, char *argv[]) {
Blackjack *game;
int round;
cout << "Welcome to CMSC 202 Blackjack!\n";
game = CreateGame(argc, argv);
round = 0;
do {
cout << "\nRound " << ++round << ":\n";
ProcAllBets(*game);
DoNewDeal(*game);
DoAllPlays(*game);
SettleAllPlayers(*game);
ShowAllPlayerFunds(*game);
} while (QueryAnotherRound());
cout << "\nGoodbye!\n";
return 0;
}
Blackjack *CreateGame(int argc, char *argv[]) {
char **names;
int *funds;
int numPlayers;
Blackjack *game;
numPlayers = ProcessArgs(argc - 1, &argv[1], names, funds);
game = new Blackjack(names, numPlayers);
for (int p = 0; p < numPlayers; p++) {
game->SetPlayerFunds(p, funds[p]);
}
return game;
}
int ProcessArgs(int argCnt, char *args[], char **&names, int *&funds) {
int i, p;
int numRecs = argCnt / 2;
names = static_cast<char **>(calloc(numRecs, sizeof(char *)));
funds = static_cast<int *>(calloc(numRecs, sizeof(int)));
for (p = 0, i = 0; p < numRecs; p++) {
names[p] = args[i++];
funds[p] = atoi(args[i++]);
}
return p;
}
void ProcAllBets(Blackjack &game) {
int numPlayers = game.GetNumPlayers();
int bet;
for (int p = 0; p < numPlayers; p++) {
cout << "How much does " << game.GetPlayerName(p) << " bet? ";
cin >> bet;
cout << endl; // For neat scripting
if (!game.SetPlayerBet(p, bet)) {
cout << "Illegal bet--changing to $0\n";
game.SetPlayerBet(p, 0);
}
}
}
void DoNewDeal(Blackjack &game) {
int numPlayers = game.GetNumPlayers();
game.NewDeal();
cout << "The players' hands:\n";
for (int p = 0; p < numPlayers; p++) {
cout << game.GetPlayerName(p) << ": ";
game.OutputPlayerHand(p);
cout << endl;
}
cout << "Dealer: ";
game.OutputDealerHand(); // This hides dealer's hole card
cout << "\n\n";
}
void DoAllPlays(Blackjack &game) {
int numPlayers = game.GetNumPlayers();
int p;
for (p = 0; p < numPlayers; p++) {
PlayOnePlayer(game, p);
}
game.DealerPlay();
}
void PlayOnePlayer(Blackjack &game, int player) {
char *name = game.GetPlayerName(player);
string answer;
bool hit, busted;
cout << ">>" << name << "'s turn:\n";
busted = false;
do {
cout << "Hand: ";
game.OutputPlayerHand(player);
cout << endl;
cout << name << "'s play: ";
cin >> answer;
cout << endl; // For neat scripting
answer[0] == 'y' || answer[0] == 'Y';
hit = (answer[0] == 'h' || answer[0] == 'H');
if (hit) {
busted = game.HitPlayer(player);
}
} while (hit && !busted);
if (busted) {
cout << "Busted!\n";
}
cout << endl;
}
void SettleAllPlayers(Blackjack &game) {
int numPlayers = game.GetNumPlayers();
int p;
for (p = 0; p < numPlayers; p++) {
game.SettlePlayerBet(p);
// Above should print out:
// Joe has busted--Dealer wins", or "Sally has 15--Dealer loses"
}
cout << endl;
}
void ShowAllPlayerFunds(Blackjack &game) {
int numPlayers = game.GetNumPlayers();
int p;
for (p = 0; p < numPlayers; p++) {
cout << game.GetPlayerName(p) << " now has $"
<< game.GetPlayerFunds(p) << endl;
}
cout << endl;
}
bool QueryAnotherRound() {
string answer;
cout << "Another round? ";
cin >> answer;
cout << endl; // For neat scripting
return answer[0] == 'y' || answer[0] == 'Y';
}
Can anyone tell me what I am doing wrong? I am not allowed to edit the Proj2.cpp class in any way. If you need more information please do not hesitate to ask. If you need to see the project in it's entirety here is a link to the Github repository for the entire project so far. If you need to see my project rules and clarifications, here is a link to my courses project description website.
Any help is greatly appreciated on this matter, thank you in advance for your time.
The Hand is empty.
This line: m_players[i].GetHand().AddCard(m_deck.DealCard()) adds a card to a temporary copy only
Make GetHand() return a reference and your players will actually get cards.
Also, you should not include executables like Prog2.out in repositories.

Inserting an object into a C++ Sequential list

For a school programming assignment I built an application that stores a list of objects in a sequential list object. The sequential list class has a method to insert a new object into the list, it checks first to see if the list already has the maximum number of entries allowed and if it does returns an error. For some reason I'm unable to insert a new object into the list (I keep getting the "Max list size exceeded" error) even though there aren't any entries in it to start.
I ran it with a breakpoint to see if the size data member was increasing somehow but that doesn't seem to be the case here.
Please ignore the poor code quality, still just learning... Feel free to make any recommendations :)
Here's the main program:
#include<iostream>
#include<string>
#include "aseqlist.h"
using namespace std;
void PrintByGender (const SeqList& L, char gender)
{
int size = L.ListSize();
int count = 0;
while (count < size)
{
if (gender == L.GetData(count).getGender())
{
L.GetData(count).PrintEmployee();
}
count++;
}
}
int InList (const SeqList& L, char *lname, Employee& Emp)
{
int found = 0;
Emp.setLast(lname);
if (L.Find(Emp) == 1)
{
found = 1;
Emp.PrintEmployee();
}
return found;
}
int main()
{
SeqList obj1;
bool close = false;
string choice = "";
do
{
cout << "Please choose what you would like to do: " << "\n";
cout << "N = New record, D = Delete record, P = Print by gender, S = Search and E = Exit" << "\n";
cin >> choice;
cin.ignore();
if (choice == "n" || choice == "N")
{
string first, last;
int age;
char gen;
double empNum;
cout << "First name: ";
cin >> first;
cout << "Last name: ";
cin >> last;
cout << "Age: ";
cin >> age;
cout << "Gender ('M' Or 'F'): ";
cin >> gen;
cout << "Employee Number: ";
cin >> empNum;
Employee newEmp;
newEmp.ReadEmployee(first, last, age, gen, empNum);
obj1.Insert(newEmp);
}
if (choice == "e" || choice == "E")
{
close = true;
}
if (choice == "p" || choice == "P")
{
char genderSearch;
cout << "Male = M, Female = F";
cin >> genderSearch;
cin.ignore();
PrintByGender(obj1, genderSearch);
}
if (choice == "d" || choice == "D")
{
string last;
cout << "Which employee? (Enter Last Name): ";
cin >> last;
cin.ignore();
Employee emp;
emp.setLast(last);
obj1.Delete(emp);
cout << "Deleted";
}
if (choice == "s" || choice == "S")
{
char lnameSearch;
cout << "Last Name?: ";
cin >> lnameSearch;
cin.ignore();
Employee emp;
char *ptrSearch;
ptrSearch = &lnameSearch;
InList(obj1, ptrSearch, emp);
if (emp.getFirst() != "")
{
emp.PrintEmployee();
}
}
}
while (close != true);
};
And here's the header file for the class declarations:
#include <iostream>
using namespace std;
const int MaxListSize = 6;
// You will need to change the typedef in the following line
// from the data type int to Employee
class Employee
{
public:
Employee();
Employee(string firstName, string lastName, int age, char gender, double employeeNumber);
void ReadEmployee(string firstName, string lastName, int age, char gender, double employeeNumber);
char getGender();
string getFirst();
void Employee::setLast(string lname);
string getLast();
void PrintEmployee();
private:
string LastName;
string FirstName;
int Age;
char Gender;
double EmployeeNumber;
};
typedef Employee DataType;
class SeqList
{
private:
// list storage array and number of current list elements
DataType listitem[MaxListSize];
int size;
public:
// constructor
SeqList(void);
// list access methods
int ListSize(void) const;
int ListEmpty(void) const;
int Find (DataType& item) const;
DataType GetData(int pos) const;
// list modification methods
void Insert(const DataType& item);
void Delete(const DataType& item);
DataType DeleteFront(void);
void ClearList(void);
};
// Class Definition:
// constructor. set size to 0
SeqList::SeqList (void): size(6)
{}
// return number of elements in list
int SeqList::ListSize(void) const
{
return size;
}
// tests for an empty list
int SeqList::ListEmpty(void) const
{
return size == 0;
}
// clears list by setting size to 0
void SeqList::ClearList(void)
{
size = 0;
}
// Take item as key and search the list. return True if item
// is in the list and False otherwise. if found,
// assign the list element to the reference parameter item
bool operator==(Employee A, Employee B)
{
bool isequal = false;
if (A.getLast() == B.getLast())
isequal = true;
return isequal;
}
int SeqList::Find(DataType& item) const
{
int i = 0;
if (ListEmpty())
return 0; // return False when list empty
while (i < size && !(item == listitem[i]))
i++;
if (i < size)
{
item = listitem[i]; // assign list element to item
return 1; // return True
}
else
return 0; // return False
}
// insert item at the rear of the list. terminate the program
// if the list size would exceed MaxListSize.
void SeqList::Insert(const DataType& item)
{
// will an insertion exceed maximum list size allowed?
if (size+1 > MaxListSize)
{
cout << "Maximum list size exceeded" << endl;
exit(1);
}
// index of rear is current value of size. insert at rear
listitem[size] = item;
size++; // increment list size
}
// search for item in the list and delete it if found
void SeqList::Delete(const DataType& item)
{
int i = 0;
// search for item
while (i < size && !(item == listitem[i]))
i++;
if (i < size) // successful if i < size
{
// shift the tail of the list to the left one position
while (i < size-1)
{
listitem[i] = listitem[i+1];
i++;
}
size--; // decrement size
}
}
// delete element at front of list and return its value.
// terminate the program with an error message if the list is empty.
DataType SeqList::DeleteFront(void)
{
DataType frontItem;
// list is empty if size == 0
if (size == 0)
{
cout << "Attempt to delete the front of an empty list!" << endl;
exit(1);
}
frontItem = listitem[0]; // get value from position 0.
Delete(frontItem); // delete the first item and shift terms
return frontItem; // return the original value
}
// return value at position pos in list. if pos is not valid
// list position, teminate program with an error message.
DataType SeqList::GetData(int pos) const
{
// terminate program if pos out of range
if (pos < 0 || pos >= size)
{
cout << "pos is out of range!" << endl;
exit(1);
}
return listitem[pos];
}
Employee::Employee()
{
FirstName = "";
LastName = "";
Age = 0;
/*Gender = "";*/
EmployeeNumber = 0;
};
Employee::Employee(string firstName, string lastName, int age, char gender, double employeeNumber)
{
FirstName = firstName;
LastName = lastName;
Age = age;
Gender = gender;
EmployeeNumber = employeeNumber;
};
void Employee::PrintEmployee()
{
cout << "First Name: " << FirstName << "\n";
cout << "Last Name: " << LastName << "\n";
cout << "Age: " << Age << "\n";
cout << "Gender: " << Gender << "\n";
cout << "Employee Number :" << EmployeeNumber << "\n" << "\n";
};
void Employee::ReadEmployee(string firstName, string lastName, int age, char gender, double employeeNumber)
{
FirstName = firstName;
LastName = lastName;
Age = age;
Gender = gender;
EmployeeNumber = employeeNumber;
};
char Employee::getGender()
{
return Gender;
}
string Employee::getFirst()
{
return FirstName;
}
string Employee::getLast()
{
return LastName;
}
void Employee::setLast(string lname)
{
LastName = lname;
}
Problem in the constructor:
SeqList::SeqList (void): size(6)
size is being initialized as 6.
Other suggestions. Don't put using namespace std; in a header file. Better yet, don't put using namespace std; anywhere.
Why is "using namespace std" considered bad practice?
// constructor. set size to 0
SeqList::SeqList (void): size(6)
{}
This is wrong. Should be so:
// constructor. set size to 0
SeqList::SeqList (void): size(0)
{}

C++ - pointer being freed was not allocated error

malloc: *** error for object 0x10ee008c0: pointer being freed was not allocated
*** set a breakpoint in malloc_error_break to debug
Abort trap: 6
Or I get this when I try and print everything
Segmentation fault: 11
I'm doing some homework for an OOP class and I've been stuck for a good hour now. I'm getting this error once I've used keyboard input enough. I am not someone who gets frustrated at all, and here I am getting very frustrated with this. Here are the files:
This is the book class. I'm pretty sure this is very solid. But just for reference:
//--------------- BOOK.CPP ---------------
// The class definition for Book.
//
#include <iostream>
#include "book.h"
using namespace std;
Book::Book()
//
{
strcpy(title, " ");
strcpy(author, " ");
type = FICTION;
price = 0;
}
void Book::Set(const char* t, const char* a, Genre g, double p)
{
strcpy(title, t);
strcpy(author, a);
type = g;
price = p;
}
const char* Book::GetTitle() const
{
return title;
}
const char* Book::GetAuthor() const
{
return author;
}
double Book::GetPrice() const
{
return price;
}
Genre Book::GetGenre() const
{
return type;
}
void Book::Display() const
{
int i;
cout << GetTitle();
for (i = strlen(title) + 1; i < 32; i++)
cout << (' ');
cout << GetAuthor();
for (i = strlen(author) + 1; i < 22; i++)
cout << (' ');
switch (GetGenre())
{
case FICTION:
cout << "Fiction ";
break;
case MYSTERY:
cout << "Mystery ";
break;
case SCIFI:
cout << "SciFi ";
break;
case COMPUTER:
cout << "Computer ";
break;
}
cout << "$";
if (GetPrice() < 1000)
cout << " ";
if (GetPrice() < 100)
cout << " ";
if (GetPrice() < 10)
cout << " ";
/* printf("%.2f", GetPrice());*/
cout << '\n';
}
This is the store class that deals with the array and dynamic allocation. This was working well without input commands, but just using its functions it was working like a champ.
//--------------- STORE.CPP ---------------
// The class definition for Store.
//
#include <iostream>
#include <cstring> // for strcmp
#include "store.h"
using namespace std;
Store::Store()
{
maxSize = 5;
currentSize = 0;
bookList = new Book[maxSize];
}
Store::~Store()
// This destructor function for class Store
// deallocates the Store's list of Books
{
delete [] bookList;
}
void Store::Insert(const char* t, const char* a, Genre g, double p)
// Insert a new entry into the direrctory.
{
if (currentSize == maxSize)// If the directory is full, grow it.
Grow();
bookList[currentSize++].Set(t, a, g, p);
}
void Store::Sell(const char* t)
// Sell a book from the store.
{
char name[31];
strcpy(name, t);
int thisEntry = FindBook(name);// Locate the name in the directory.
if (thisEntry == -1)
cout << *name << " not found in directory";
else
{
cashRegister = cashRegister + bookList[thisEntry].GetPrice();
// Shift each succeding element "down" one position in the
// Entry array, thereby deleting the desired entry.
for (int j = thisEntry + 1; j < currentSize; j++)
bookList[j - 1] = bookList[j];
currentSize--;// Decrement the current number of entries.
cout << "Entry removed.\n";
if (currentSize < maxSize - 5)// If the directory is too big, shrink it.
Shrink();
}
}
void Store::Find(const char* x) const
// Display the Store's matches for a title or author.
{
// Prompt the user for a name to be looked up
char name[31];
strcpy(name, x);
int thisBook = FindBook(name);
if (thisBook != -1)
bookList[thisBook].Display();
int thisAuthor = FindAuthor(name, true);
if ((thisBook == -1) && (thisAuthor == -1))
cout << name << " not found in current directory\n";
}
void Store::DisplayGenre(const Genre g) const
{
double genrePrice = 0;
int genreCount = 0;
for (int i = 0; i < currentSize; i++)// Look at each entry.
{
if (bookList[i].GetGenre() == g)
{
bookList[i].Display();
genrePrice = genrePrice + bookList[i].GetPrice();
genreCount++;
}
}
cout << "Number of books in this genre: " << genreCount
<< " " << "Total: $";
if (genrePrice < 1000)
cout << " ";
if (genrePrice < 100)
cout << " ";
if (genrePrice < 10)
cout << " ";
printf("%.2f", genrePrice);
}
void Store::DisplayStore() const
{
if (currentSize >= 1)
{
cout << "**Title**\t\t"
<< "**Author**\t"
<< "**Genre**\t"
<< "**Price**\n\n";
for (int i = 0; i < currentSize; i++)
bookList[i].Display();
}
else
cout << "No books currently in inventory\n\n";
cout << "Total Books = " << currentSize
<< "\nMoney in the register = $";
if (cashRegister < 1000)
cout << " ";
if (cashRegister < 100)
cout << " ";
if (cashRegister < 10)
cout << " ";
printf("%.2f", cashRegister);
cout << '\n';
}
void Store::Sort(char type)
{
Book temp;
for(int i = 0; i <= currentSize; i++)
{
for (int j = i+1; j < currentSize; j++)
{
if (type == 'A')
{
if (strcmp(bookList[i].GetTitle(), bookList[j].GetTitle()) > 0)
{
temp = bookList[i];
bookList[i] = bookList[j];
bookList[j] = temp;
}
}
if (type == 'T')
{
if (strcmp(bookList[i].GetAuthor(), bookList[j].GetAuthor()) > 0)
{
temp = bookList[i];
bookList[i] = bookList[j];
bookList[j] = temp;
}
}
}
}
}
void Store::SetCashRegister(double x)
// Set value of cash register
{
cashRegister = x;
}
void Store::Grow()
// Double the size of the Store's bookList
// by creating a new, larger array of books
// and changing the store's pointer to refer to
// this new array.
{
maxSize = currentSize + 5;// Determine a new size.
cout << "** Array being resized to " << maxSize
<< " allocated slots" << '\n';
Book* newList = new Book[maxSize];// Allocate a new array.
for (int i = 0; i < currentSize; i++)// Copy each entry into
newList[i] = bookList[i];// the new array.
delete [] bookList;// Remove the old array
bookList = newList;// Point old name to new array.
}
void Store::Shrink()
// Divide the size of the Store's bookList in
// half by creating a new, smaller array of books
// and changing the store's pointer to refer to
// this new array.
{
maxSize = maxSize - 5;// Determine a new size.
cout << "** Array being resized to " << maxSize
<< " allocated slots" << '\n';
Book* newList = new Book[maxSize];// Allocate a new array.
for (int i = 0; i < currentSize; i++)// Copy each entry into
newList[i] = bookList[i];// the new array.
delete [] bookList;// Remove the old array
bookList = newList;// Point old name to new array.
}
int Store::FindBook(char* name) const
// Locate a name in the directory. Returns the
// position of the entry list as an integer if found.
// and returns -1 if the entry is not found in the directory.
{
for (int i = 0; i < currentSize; i++)// Look at each entry.
if (strcmp(bookList[i].GetTitle(), name) == 0)
return i;// If found, return position and exit.
return -1;// Return -1 if never found.
}
int Store::FindAuthor(char* name, const bool print) const
// Locate a name in the directory. Returns the
// position of the entry list as an integer if found.
// and returns -1 if the entry is not found in the directory.
{
int returnValue;
for (int i = 0; i < currentSize; i++)// Look at each entry.
if (strcmp(bookList[i].GetAuthor(), name) == 0)
{
if (print == true)
bookList[i].Display();
returnValue = i;// If found, return position and exit.
}
else
returnValue = -1;// Return -1 if never found.
return returnValue;
}
Now this is the guy who needs some work. There may be some stuff blank so ignore that. This one controls all the input, which is the problem I believe.
#include <iostream>
#include "store.h"
using namespace std;
void ShowMenu()
// Display the main program menu.
{
cout << "\n\t\t*** BOOKSTORE MENU ***";
cout << "\n\tA \tAdd a Book to Inventory";
cout << "\n\tF \tFind a book from Inventory";
cout << "\n\tS \tSell a book";
cout << "\n\tD \tDisplay the inventory list";
cout << "\n\tG \tGenre summary";
cout << "\n\tO \tSort inventory list";
cout << "\n\tM \tShow this Menu";
cout << "\n\tX \teXit Program";
}
char GetAChar(const char* promptString)
// Prompt the user and get a single character,
// discarding the Return character.
// Used in GetCommand.
{
char response;// the char to be returned
cout << promptString;// Prompt the user
cin >> response;// Get a char,
response = toupper(response);// and convert it to uppercase
cin.get();// Discard newline char from input.
return response;
}
char Legal(char c)
// Determine if a particular character, c, corresponds
// to a legal menu command. Returns 1 if legal, 0 if not.
// Used in GetCommand.
{
return((c == 'A') || (c == 'F') || (c == 'S') ||
(c == 'D') || (c == 'G') || (c == 'O') ||
(c == 'M') || (c == 'X'));
}
char GetCommand()
// Prompts the user for a menu command until a legal
// command character is entered. Return the command character.
// Calls GetAChar, Legal, ShowMenu.
{
char cmd = GetAChar("\n\n>");// Get a command character.
while (!Legal(cmd))// As long as it's not a legal command,
{// display menu and try again.
cout << "\nIllegal command, please try again . . .";
ShowMenu();
cmd = GetAChar("\n\n>");
}
return cmd;
}
void Add(Store s)
{
char aTitle[31];
char aAuthor[21];
Genre aGenre = FICTION;
double aPrice = 10.00;
cout << "Enter title: ";
cin.getline(aTitle, 30);
cout << "Enter author: ";
cin.getline(aAuthor, 20);
/*
cout << aTitle << " " << aAuthor << "\n";
cout << aGenre << " " << aPrice << '\n';
*/
s.Insert(aTitle, aAuthor, aGenre, aPrice);
}
void Find()
{
}
void Sell()
{
}
void ViewGenre(Store s)
{
char c;
Genre result;
do
c = GetAChar("Enter Genre - (F)iction, (M)ystery, (S)ci-Fi, or (C)omputer: ");
while ((c != 'F') && (c != 'M') && (c != 'S') && (c != 'C'));
switch (result)
{
case 'F': s.DisplayGenre(FICTION); break;
case 'M': s.DisplayGenre(MYSTERY); break;
case 'S': s.DisplayGenre(SCIFI); break;
case 'C': s.DisplayGenre(COMPUTER); break;
}
}
void Sort(Store s)
{
char c;
Genre result;
do
c = GetAChar("Enter Genre - (F)iction, (M)ystery, (S)ci-Fi, or (C)omputer: ");
while ((c != 'A') && (c != 'T'));
s.Sort(c);
}
void Intro(Store s)
{
double amount;
cout << "*** Welcome to Bookstore Inventory Manager ***\n"
<< "Please input the starting money in the cash register: ";
/* cin >> amount;
s.SetCashRegister(amount);*/
}
int main()
{
Store mainStore;// Create and initialize a Store.
Intro(mainStore);//Display intro & set Cash Regsiter
ShowMenu();// Display the menu.
/*mainStore.Insert("A Clockwork Orange", "Anthony Burgess", SCIFI, 30.25);
mainStore.Insert("X-Factor", "Anthony Burgess", SCIFI, 30.25);*/
char command;// menu command entered by user
do
{
command = GetCommand();// Retrieve a command.
switch (command)
{
case 'A': Add(mainStore); break;
case 'F': Find(); break;
case 'S': Sell(); break;
case 'D': mainStore.DisplayStore(); break;
case 'G': ViewGenre(mainStore); break;
case 'O': Sort(mainStore); break;
case 'M': ShowMenu(); break;
case 'X': break;
}
} while ((command != 'X'));
return 0;
}
Please, any and all help you can offer is amazing.
Thank you.
Welcome to the exciting world of C++!
Short answer: you're passing Store as a value. All your menu functions should take a Store& or Store* instead.
When you're passing Store as a value then an implicit copy is done (so the mainStore variable is never actually modified). When you return from the function the Store::~Store is called to clean up the copied data. This frees mainStore.bookList without changing the actual pointer value.
Further menu manipulation will corrupt memory and do many double frees.
HINT: If you're on linux you can run your program under valgrind and it will point out most simple memory errors.
Your Store contains dynamically-allocated data, but does not have an assignment operator. You have violated the Rule of Three.
I don't see the Store class being instantiated anywhere by a call to new Store() which means the booklist array has not been created but when the program exits and calls the destructor, it tries to remove the array that was never allocated and hence that's why i think you are getting this error. Either, modify the destructor to have a null check or instantiate the class by a call to the constructor. Your code shouldn't still be working anywhere you are trying to use a Store object.
Hope this helps