The following pertains to homework. Restraunt pet project type thing, task is to update it to use vectors. The issue I'm having is this:
This winds up causing a core segmentation fault, yet is able to retrieve all the information appropriately when I use valgrind.
void Table::partyCheckout(void)
{
if(status == SERVED)
{
cout << " ---------------- " << endl;
cout <<"Table: " << tableId << "\nParty Size: " << numPeople << "\nWaiter: " << waiter->getName() << "\nSummary: " <<endl;
order->requestSummary();
cout << "Total: " << endl;
order->requestTotal();
cout << " ---------------- " << endl;
status = IDLE;
}
else
{
cout << "Error: " << tableId << " ";
if(numPeople == 0)
{
cout << "No one is at this table." << endl;
}
else
{
cout << "This party hasn't been served." << endl;
}
}
}
Setup: I'm storing the waiters and the orders in vectors.At runtime: when it does the waiter->getName() it complains that it's an invalid read, and that the memory location has been free'd by vector via a deallocater. My logic on the matter: It looks ahead and sees that the vector itself is not accessed again and so deallocates it. Since I do no more writing after this point, the memory location remains intact. When it tries to read the location it sees it has been free'd, hence invalid read but it still gets the appropriate data. So my question then, I suppose is two fold:Does this logic sound right? What should I do to fix it?
#ifndef HW3_H
#define HW3_H
#include <vector>
#include "Table.h"
#include "Waiter.h"
class hw3
{
private:
vector<Table> tables;
vector<Waiter> waiters;
vector<Order> orders;
public:
void begin();
};
#endif
.cpp file, most of the allocation:
ifstream configFile("config.txt"); //This guy is for initializing things
string line;
Menu theMenu;
getline(configFile, line);
stringstream intMaker;
int t1;
int t2;
string temp;
string temp2;
string temp3;
while (true)
{
getline(configFile, line);
Tokenizer str(line, " \n");
if(line =="")
{
break;
}
else
{
temp = str.next();
temp2 = str.next();
intMaker << temp;
intMaker >> t1;
intMaker.str("");
intMaker.clear();
intMaker << temp2;
intMaker >> t2;
intMaker.str("");
intMaker.clear();
tables.push_back(*(new Table(t1,t2)));
}
}
getline(configFile, line);
while (true)
{
getline(configFile, line);
Tokenizer name(line, " ");
string tabl = "";
//Siphon off the name and the tables.
temp = name.next();
tabl = name.next();
Tokenizer strink(tabl, ",\n");
int numTables = (int) tables.size();
Table * tabs[numTables];
t1 = 0;
int keepinTabs = 0;
while(true)
{
string temp2 = strink.next();
if (temp2 == "")
{
break;
}
else
{
intMaker << temp2;
intMaker >> t1;
intMaker.str("");
intMaker.clear();
for(int i = 0; i < numTables; i++)
{
if(tables.at(i).getTableId() == t1)
{
tabs[keepinTabs] = &tables.at(i);
}
}
keepinTabs++;
}
}
waiters.push_back(*(new Waiter(temp, tabl, *tabs))); //Waiter(name, list of tables, and an array of table numbers.
for(int j = 0; j < keepinTabs; j++)
{
for(int i = 0; i < tables.size(); i++)
{
if(tabs[j]->getTableId() == tables[i].getTableId())
{
tables.at(i).assignWaiter(&(waiters.back()));
}
}
}
if(line == "")
{
break;
}
}
Multiple issues I can see:
tables.push_back(*(new Table(t1,t2)));
This code dynamically allocates an object of type Table, then pushes a copy of this object into tables, and then forgets the address of the dynamically allocated object - you're leaking memory.
waiters.push_back(*(new Waiter(temp, tabl, *tabs)));
As above, with Waiter this time.
tabs[keepinTabs] = &tables.at(i);
This takes the address of an object inside the vector. While legal, it's extremely fragile. std::vector can move its contents around in memory when it resizes (e.g. when you push into it).
This (or similar code elsewhere) might be the cause of your segfault. Seeing as you're allocating the objects dynamically, maybe you should declare your vectors to hold just pointers:
vector<Table*> tables;
vector<Waiter*> waiters;
vector<Order*> orders;
You would then do e.g. tables.push_back(new Table(t1, t2));. Of course, you have to make sure to delete the dynamically allocated objects when you remove them from the vectors. An alternative would be to use smart pointers, e.g.:
vector<std::shared_ptr<Table> > tables;
vector<std::shared_ptr<Waiter> > waiters;
vector<std::shared_ptr<Order> > orders;
Related
Here I am using Data Structure Queues to change cards places using strings. User picks the top card than put it at last of the deck. The problem is that I need to return updated string to main. What it is returning is junk Values. I also tried to copy the string array and than returning that arraybut didn't work. Can anyone help?
#include<iostream>
#include<string>
using namespace std;
string CommunityChest(string Cards[]){
struct Que{
string cards[6];
int front =0;
int back=-1;
}ComQ;
string temp;
for(int i=0; i<5;i++)
{//Enqueue(Cards)
ComQ.back++;
if(ComQ.back<=5)
{
ComQ.cards[ComQ.back]=Cards[i];
}
else{
cout<<"Overflow";
}
}
//Display
for(int i=ComQ.front; i<=ComQ.back; i++)
{
cout<<ComQ.cards[i]<<endl;
}
//Del()
if(ComQ.front>=0)
{
temp=ComQ.cards[ComQ.front];
ComQ.front++;
}
cout<<endl<<"Pick the top Card"<<endl;
cout<<temp<<endl;
//EnQ the picked card
ComQ.back++;
if(ComQ.back<=5)
{
ComQ.cards[ComQ.back]=temp;
}
else{
cout<<"Overflow";
}
cout<<endl<<"After Inserting top card:"<<endl;
//Display
string newQ1[5];
for (int i=ComQ.front; i<=ComQ.back; i++) //Making an alternate array to copy Comq.cards array data
{
newQ1[i]=ComQ.cards[i];
}
for(int i=0; i<5; i++)
{
return newQ1[i]; //trying to return string array
//cout<< newQ1<<endl;
}
}
int main(){
string cards[5]{ "1 Advance ........",
"2. It is your ...........",
"3. You have won .............",//Cards as strings
"4. From sale of..............",
"5. Pay Hospital............"};
string newQ1=CommunityChest(cards);
for(int i=0; i<5; i++)
cout << newQ1[i] << endl;
return 0;
}
There are some issues with this code as mentioned in the comments, you are trying to do a return in a loop, this may look okay but it's wrong since a return can get you out of the function. But it seems like you want to return an array of strings.
A fix for this function would be like this:
#include <iostream>
std::string* CommunityChest(std::string Cards[]) {
struct Que {
std::string cards[6];
int front = 0;
int back = -1;
} ComQ;
std::string temp;
for (int i = 0; i < 5; i++) { // Enqueue(Cards)
ComQ.back++;
if (ComQ.back <= 5) {
ComQ.cards[ComQ.back] = Cards[i];
}
else {
std::cout << "Overflow";
}
}
// Display
for (int i = ComQ.front; i <= ComQ.back; i++) {
std::cout << ComQ.cards[i] << std::endl;
}
// Del()
if (ComQ.front >= 0) {
temp = ComQ.cards[ComQ.front];
ComQ.front++;
}
std::cout << std::endl
<< "Pick the top Card" << std::endl;
std::cout << temp << std::endl;
// EnQ the picked card
ComQ.back++;
if (ComQ.back <= 5) {
ComQ.cards[ComQ.back] = temp;
}
else {
std::cout << "Overflow";
}
std::cout << std::endl
<< "After Inserting top card:" << std::endl;
// Display
// Creating a dynamic array to store the values
std::string* newQ1 = new std::string[5];
for (int i = ComQ.front, j = 0; i <= ComQ.back && j < 5; i++, j++) {// Making an alternate array to copy Comq.cards array data
newQ1[j] = ComQ.cards[i];
}
return newQ1; // Returning the dynamic array
}
int main()
{
std::string cards[5]{
"1 Advance ........",
"2. It is your ...........",
"3. You have won .............", // Cards as strings
"4. From sale of..............",
"5. Pay Hospital............"
};
std::string* newQ1 = CommunityChest(cards);
for(int i = 0; i < 5; i++) {
std::cout << newQ1[i] << std::endl;
}
delete[] newQ1; // Deleting the array
return 0;
}
The output will be:
1 Advance ........
2. It is your ...........
3. You have won .............
4. From sale of..............
5. Pay Hospital............
Pick the top Card
1 Advance ........
After Inserting top card:
2. It is your ...........
3. You have won .............
4. From sale of..............
5. Pay Hospital............
1 Advance ........
In this fix, I'm returning a dynamically allocated array of strings because a static array will be destroyed once the scope ends, it would be better sometimes to use other ways to allocate memory such as std::unique_ptr<> or std::shared_ptr<>, but I'd suggest you learn how to do it yourself first then use those when needed.
EDIT:
You can also return an std::array<>, I suggest you to read about it as C-Style arrays cannot be returned in you way that you tried and can't be returned without using dynamic allocation, so an std::array<> can be a good replacement over std::string* in this case
I am writing a program that takes some contact information from user and grows the array dynamically when it gets full. But when I am trying to run the program I get Write access violation popping up a line from "iosfwd standard header". I don't know where I went wrong. Please do help.
My code looks like this:
# include "pch.h"
# include <iostream>
# include <string>
using namespace std;
struct Contact {
string name;
string number;
string address;
string exit;
};
void userPrompt(Contact &contact) {
cout << "Name: ";
getline(cin, contact.name);
cout << "Phone number: ";
getline(cin, contact.number);
cout << "Address: ";
getline(cin, contact.address);
cout << "Exit? (y/n): ";
getline(cin, contact.exit);
}
void printContact(Contact &contact) {
cout << "Name: " << contact.name << endl;
cout << "Phone number: " << contact.number << endl;
cout << "Address: " << contact.address << "\n" << endl;
}
void growArray(int ¤tLength, Contact *contacts) {
int multiplyer = 2;
Contact *new_array = new Contact[currentLength * multiplyer];
for (int i = 0; i < currentLength; i++) {
new_array[i] = contacts[i];
}
delete[] contacts;
contacts = new_array;
currentLength *= multiplyer;
}
void showAllContacts(Contact *contacts, int length) {
for (int i = 0; i < length; i++) {
if (contacts[i].name.length() != 0) {
printContact(contacts[i]);
}
}
}
int main() {
// Prompt the user to fill in the address book.
// If the array gets full, make it bigger.
Contact *contacts = new Contact[1];
int currentLength = 1;
int i = 0;
while (true) {
userPrompt(contacts[i]);
if (contacts[i].exit == "y" or contacts[i].exit == "Y") {
break;
}
i++;
if (i == currentLength) {
growArray(currentLength, contacts);
}
}
// Show the address book
showAllContacts(contacts, currentLength);
}
But when I am running the code it throws exception like this:
enter image description here
"Write Access Violation"
I think the bug is in the growArray function. But I can't fugure out where did I screw up. Please do help.
In
growArray(currentLength, contacts);
a copy of the pointer contacts is modified inside the function; but outside, the pointer's value stays the same. After growArray returns, contacts points to deleted memory, hence UB, hence the crash.
==> Full program demonstration of the issue <==
There are basically two solutions: the bad one and the good one. The bad one is to change the signature of growArray to take a reference to the pointer:
void growArray(int ¤tLength, Contact *&contacts)
The good one is to stop this manually allocated memory non-sense and use a std::vector<Contact>!
Before my program can free up memory and end it crashes. Crashes seem to happen on transition from the function UserDataCollection and back to main. This is only my second program using pointers so I'm still quite the newbie considering the whole point of c++ is to use pointers.
Here is the aforementioned code:
#include <iostream>
//Prototypes
void UserDataCollection(int * &movieData_ptr, int &numSurveyed); // Movie Statistics
void DisplayOutput(int *movieData_ptr, int numSurveyed); //Mean, Median, Mode (Display To Console)
//Global Constants
int main()
{
//Variables
int numSurveyed = 0;
//Pointers
int * movieData_ptr = nullptr;
movieData_ptr = new int[numSurveyed];
//"Program Start"
std::cout << "Program start...\n\n";
UserDataCollection(movieData_ptr, numSurveyed);
DisplayOutput(movieData_ptr, numSurveyed);
//Release Memory
delete[] movieData_ptr;
std::cout << "Memory Cleared.";
return 0;
}
void UserDataCollection(int * &movieData_ptr, int &numSurveyed)
{
//Get Number of Students Surveyed
std::cout << "How many students were surveyed: ";
std::cin >> numSurveyed;
//Student Data Input Loop
for (int i = 0; i < numSurveyed; i++)
{
//Get Student Data
std::cout << "Enter How many movies student " << i + 1 << " has seen in ONE month: ";
std::cin >> *(movieData_ptr + i);
//Validation Check
while (*(movieData_ptr + i) >= 337)
{
std::cout << "\nImpossible value!" << std::endl
<< "Hours in a month: 730. Average movie length: 130 minutes."
<< "Total Possible movies: 337";
std::cout << "\n\nEnter How many movies student " << i + 1 << " has seen in ONE month: ";
std::cin >> *(movieData_ptr + i);
} //end while (Validation Check)
} // end for (Data Input)
}
void DisplayOutput(int *movieData_ptr, int numSurveyed)
{
//Display loop for pointer array
for (int i = 0; i < numSurveyed; i++)
{
std::cout << *(movieData_ptr + i) << " ";
}
//End Message
std::cout << "\n\nProgram end.";
}
You never allocated any memory.
int numSurveyed = 0;
//Pointers
int * movieData_ptr = nullptr;
movieData_ptr = new int[numSurveyed];
This is the equivalent of
int *movieData_ptr = new int[0];
You are allocating size of 0 ints. This is undefined behaviour. You can't do anything useful with that pointer without a segmentation fault. You need to either pre-allocate a certain amount, and make sure you don't overflow, or dynamically allocate every time you plan to add data.
Since this is C++, it's probably better not to use raw pointers, but use vector or something instead.
Sorry:
From 5.3.4/7
When the value of the expression in a direct-new-declarator is zero, the allocation function is called to allocate an array with no elements.
From 3.7.3.1/2
The effect of dereferencing a pointer returned as a request for zero size is undefined.
I'm writing a code to index the skills available to a user in a game, constructed as a linked list. I've throughly tested the function that populates the list and it seems to be working correctly (so the head pointer for the list shouldn't be null). When I attempt to traverse the list to set values in the skill, before any of the code which writes to memory within the list gets to execute the program is crashing when I initialise the temp pointer within the search function of the list to the head pointer.
What makes this additionally weird to me is that it worked fine (and I had tested this fairly thuroughly) until I added in a list to store a list of available items, and may just be missing an odd interaction between the two when I populate them.
The specific error is that the pointer is supposedly accessing memory index 0x000000c to write to, but I don't see how the code at that point is dealing with a null pointer at all (since after 10 runs of the program the OS shouldn't be allocating that block of memory to the temp pointer every time and nothing else should be null.
I'm probably just ramblind at this point so here's the code:
The function that causes the error according to the debugger:
void Mechanics::setSkillValue(int index, int value)
{
Skill *temp = FirstSkill; // << The error is happening on this line //
while((temp != NULL)&&(temp->index != index))
{
temp = temp->next;
}
if (temp == NULL)
{
cout << "%";
}
else temp->setValue(value);
// cout << temp->returnValue(); //This was a test check, not needed for anything
}
The Function that's supposed to populate the skill and item lists.
void Mechanics::Populate()
{
ifstream skillstream("Skills.txt");
if(skillstream.is_open())
{
while(skillstream.good())
{
Skill *newskill;
int indexval;
string skillindex;
string skillname;
string skilldescription;
cout << "TP4" << endl; //TEST POINT
getline(skillstream, skillindex);
cout << skillindex;
getline(skillstream, skillname);
cout << skillname;
getline(skillstream, skilldescription);
cout << skilldescription; cout << endl;
indexval = atoi(skillindex.c_str());
newskill = new Skill(skillname, skilldescription,indexval);
//cout << "TP5" << endl; //TEST POINT
if(newskill == NULL) cout << "NULL!!!";
addSkill(newskill);
}
}
ifstream itemstream("Items.txt");
if(itemstream.is_open())
{
while(itemstream.good())
{
Item *newitem;
int indexval;
string skillindex;
string skillname;
string skilldescription;
string abilitydescription;
string valueSTR;
string typeSTR;
int value;
int type;
int numeric[5];
// cout << "TP4" << endl; //TEST POINT
getline(itemstream, skillindex);
// cout << skillindex;
getline(itemstream, skillname);
// cout << skillname;
getline(itemstream, skilldescription);
// cout << skilldescription;
getline(itemstream, abilitydescription);
getline(itemstream, valueSTR);
value = atoi(valueSTR.c_str());
getline(itemstream,typeSTR);
type = atoi(typeSTR.c_str());
for (int i=0; i < 5; i++)
{
string numericSTR;
getline(itemstream,numericSTR);
numeric[i]=atoi(numericSTR.c_str());
}
indexval = atoi(skillindex.c_str());
newitem = new Item(indexval, skilldescription, skillname, abilitydescription, value, type, numeric);
//cout << "TP5" << endl; //TEST POINT
// if(newskill == NULL) cout << "NULL!!!";
addItem(newitem);
}
}
The function that's supposed to actually add a skill to the skill list:
void Mechanics::addSkill(Skill *nskill)
{
Skill *temp = FirstSkill;
if(FirstSkill == NULL)
{
FirstSkill = nskill;
//cout << "TP1" << endl; //TEST POINT
//FirstSkill->printname();
}
else
{
while((temp->next != NULL))
{
temp = temp-> next;
//cout << "TP2" << endl; //TEST POINT
//temp->printname(); cout << endl;
}
if (FirstSkill != NULL)
{
temp->next = nskill;
nskill->next = NULL;
}
}
}
The code that I have is somewhat extensive so I'm only going to include the blocks which are potentially interacting with the function that's throwing up the error.
Thanks in advance for reading through this, and any assistance you're able to offfer, I've been banging my head against this for about 6 hours now and I've lost the perspective to actually track this one down.
Im having trouble accessing the following vector. Im new to vectors so this is probably a small syntactical thing i've done wrong. here is the code....
void spellCheck(vector<string> * fileRead)
{
string fileName = "/usr/dict/words";
vector<string> dict; // Stores file
// Open the words text file
cout << "Opening: "<< fileName << " for read" << endl;
ifstream fin;
fin.open(fileName.c_str());
if(!fin.good())
{
cerr << "Error: File could not be opened" << endl;
exit(1);
}
// Reads all words into a vector
while(!fin.eof())
{
string temp;
fin >> temp;
dict.push_back(temp);
}
cout << "Making comparisons…" << endl;
// Go through each word in vector
for(int i=0; i < fileRead->size(); i++)
{
bool found = false;
// Go through and match it with a dictionary word
for(int j= 0; j < dict.size(); j++)
{
if(WordCmp(fileRead[i]->c_str(), dict[j].c_str()) != 0)
{
found = true;
}
}
if(found == false)
{
cout << fileRead[i] << "Not found" << endl;
}
}
}
int WordCmp(char* Word1, char* Word2)
{
if(!strcmp(Word1,Word2))
return 0;
if(Word1[0] != Word2[0])
return 100;
float AveWordLen = ((strlen(Word1) + strlen(Word2)) / 2.0);
return int(NumUniqueChars(Word1,Word2)/ AveWordLen * 100);
}
The error is in the lines
if(WordCmp(fileRead[i]->c_str(), dict[j].c_str()) != 0)
and
cout << fileRead[i] << "Not found" << endl;
the problem seems to be, because its in the form of a pointer the current syntax im using to access it is made invalid.
Using [] on a pointer to a vector will not call std::vector::operator[]. To call std::vector::operator[] as you want, you must have a vector, not a vector pointer.
The syntax to access the n-th element of a vector with a pointer to the vector would be: (*fileRead)[n].c_str().
However, you should just pass a reference to the vector:
void spellCheck(vector<string>& fileRead)
Then it's just:
fileRead[n].c_str()
You can use the unary * to get a vector& from a vector*:
cout << (*fileRead)[i] << "Not found" << endl;
Two options to access:
(*fileRead)[i]
fileRead->operator[](i)
One option to improve the method
pass by reference
You can either pass fileRead by reference like this:
void spellCheck(vector<string> & fileRead)
Or add a dereferece when you use it like this:
if(WordCmp( (*fileRead)[i]->c_str(), dict[j].c_str()) != 0)