Std::bad_alloc thrown in the middle of While Loop - c++

I'm writing a function that handles an order input file (csv) using a while loops to iterate though it.
762212,1,2020-03-15,10951-3,64612-2,57544-1,80145-1,27515-2,16736-1,79758-2,29286-2,51822-3,39096-1,32641-3,63725-3,64007-2,23022-1,16974-3,26860-2,75536-2,26461-1
1,373975319551257,12-2023
258572,2,2020-03-15,96497-1,70616-1,80237-2,22248-2,56107-1,59695-1,37948-3,21316-3,63498-1,18329-1,56833-1,66295-1,47680-3,30346-1
1,201741963232463,02-2022
857003,3,2020-03-15,16655-1,88019-3,75069-3,96017-2,46883-2,15138-1,77316-1,70063-3,54452-3,86429-2,15134-2,60176-1,12946-3
2,cfeeham3s
747893,4,2020-03-17,48520-1,93268-2,63636-1,23750-2,99771-3,83203-1,21316-3,89921-2,15134-3,82831-1,30346-2,54044-3,28561-1,14792-2,23523-3,56826-2
1,3571379825697064,04-2025
Every two lines represents an input. I have the following function that handles this input:
list<Order> orders;
void read_orders(string file_name) {
fstream read_file;
read_file.open(file_name, ios::in);
if (read_file.is_open()) {
string s;
int line_num = 1; // keeps track of line number in input file
int o_id;
string o_date;
int c_id;
vector<LineItem> itms;
while (getline(read_file, s)) {
cout << orders.size(); // shows that only two objects are added before failure
if (line_num % 2 == 1) { // handle odd numbered lines of input
auto data = split(s, ',');
int o_id = stoi(data[0]);
string o_date = data[1];
int c_id = stoi(data[2]);
vector<LineItem> itms;
// get line items
int n_line_items = data.size() - 3;
vector<string> end_data(data.end() - n_line_items, data.end());
for (string x: end_data) {
auto parts = split(x, '-');
LineItem* it = new LineItem(stoi(parts[0]), stoi(parts[1]));
itms.push_back(*it);
delete it;
}
} else { // handle even numbered lines of input
auto data = split(s, ',');
Credit* pay_credit = new Credit(0.0, data[1], data[2]); // initialize each type of payment
PayPal* pay_paypal = new PayPal(0.0, data[1]);
WireTransfer* pay_wire = new WireTransfer(0.0, data[1], data[2]);
if (data[0] == "1") {
Order* ordr = new Order(o_id, o_date, c_id, itms, *pay_credit);
orders.push_back(*ordr);
delete ordr;
} else if (data[0] == "2") {
Order* orr = new Order(o_id, o_date, c_id, itms, *pay_paypal);
orders.push_back(*orr);
delete orr;
} else if (data[0] == "3") {
Order* odr = new Order(o_id, o_date, c_id, itms, *pay_wire);
orders.push_back(*odr);
delete odr;
}
delete pay_credit; // trying to clean up memory
delete pay_paypal;
delete pay_wire;
}
line_num += 1;
}
read_file.close();
}
}
Because of my cout statement, I can tell that it only adds two items to the list before running into the std::bad_alloc error. It seems to happen when it switches from adding a Credit object to adding a PayPal object into the Order(...) when it's initialized. I did a lot of research into why this might happen, so I tried to clean up as much as I knew how to (I'm new to C++) but the same error kept popping up. Does the error happen when I'm adding things to the list or is it when I'm creating these new objects?/How could I fix something like that?
Here are my class definitions in case that's important:
class Payment {
public:
double amount;
string print_detail() {
return "hey";
};
};
class Credit: public Payment {
private:
string card_number;
string expiration;
public:
Credit(double amt, string cn, string exp) {
this->amount = amt;
this->card_number = cn;
this->expiration = exp;
}
string print_detail() {
return "Credit card " + this->card_number + ", exp. " + this->expiration;
}
};
class PayPal: public Payment {
private:
string paypal_id;
public:
PayPal(double amt, string pp_id) {
this->amount = amt;
this->paypal_id = pp_id;
}
virtual string print_detail() {
return "Paypal ID: " + this->paypal_id;
}
};
class WireTransfer: public Payment {
private:
string bank_id;
string account_id;
public:
WireTransfer(double amt, string b_id, string a_id) {
this->amount = amt;
this->bank_id = b_id;
this->account_id = a_id;
}
string print_detail() {
return "Wire transfer from Bank ID " + this->bank_id + ", Account# " + this->account_id;
}
};
class LineItem {
private:
int item_id;
int qty;
public:
LineItem(int i_id, int qt) {
this->item_id = i_id;
this->qty = qt;
}
double subtotal() {
double subtot = 0.0;
for (auto x: items) {
if (x.item_id == this->item_id) {
subtot += x.price * this->qty;
}
}
return subtot;
};
};
class Order {
private:
int order_id;
string order_date;
int cust_id;
vector<LineItem> line_items;
Payment payment;
public:
Order(int o_id, string o_date, int c_id, vector<LineItem> li, Payment pay) {
this->order_id = o_id;
this->order_date = o_date;
this->cust_id = c_id;
this->line_items = li;
this->payment = pay;
}
string pay_type = "";
double total() {
double result = 0.0;
for (auto li: line_items) {
result += li.subtotal();
}
return result;
}
string print_order() {
string text = "===========================\nOrder #";
text += to_string(this->order_id) + ", Date: " + this->order_date + "\nAmount: $";
text += to_string(this->total()) + ", Paid by ";
text += payment.print_detail();
return text;
}
};
And this was the error message showing that it did insert two items:
001122terminate called after throwing an instance of 'std::bad_alloc'
what(): std::bad_alloc
Process returned 3 (0x3)

std::bad_alloc is often thrown when there is not enough memory to be allocated. I can't say if this will solve the problem, but your repeated allocations and deallocations of objects are both unnecessary and harmful (causing memory fragmentation).
Instead of
LineItem* it = new LineItem(stoi(parts[0]), stoi(parts[1]));
itms.push_back(*it);
delete it;
you should do
itms.push_back(LineItem(stoi(parts[0]), stoi(parts[1]));
or
itms.emplace_back(stoi(parts[0]), stoi(parts[1]));
The same applies to every occurence of new in read_orders. You don't need any of them.
Another helpful thing you can do is to preallocate memory for std::vector. If you don't know how many items it will have, do an educated guess (100, 1000, 10000, etc.).
itms.reserve(1000); //before you start to push_back() to it
Also, make sure to std::move your vectors if you want to transfer the whole content of it and not make a copy.

Related

Print a string from a pointer to its member class

So I'm trying to print a string, but I get no output. However the other values in the class prints just fine.
In main I have a for loop that prints the the values for the Skill class. In Skill I have a pointer to the Ability class.
class Skill {
private:
Ability* ability;
public:
Ability* GetAbility() {
return ability;
};
}
It gets assigned in the constructor like this:
Skill::Skill(Ability* ability){
this->ability = ability;
}
The Ability class contains just a Name and a score.
class Ability {
private:
string name;
float score;
public:
Ability(string name, float score) {
this->name = name;
this->score = score;
};
string Name() { return name; }
float GetScore() { return score; }
};
Now in main I create a few skills and assign an ability to it. as is a container class that initializes a few ablities in a vector and I can get an ability based on its name.
Skill s* = new Skill[2]
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
And then we print
cout << s[i].GetAbility()->Name() << " " << s[i].GetAbility()->GetScore();
However the only output I get is the score. No name what so ever and I can't figure it out. I've tried a few things, but still noting is printing. I'm sure I'm missing something simple that will make me facepalm, but in my defense I haven't written C++ in over 10 years. Thanks in advance.
EDIT: as.GetAbility looks like this:
Ability AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return abilityScores[i];
}
}
return Ability();
}
abilityScores is a vector
Your AbilityScores::GetAbility() method is returning an Ability object by value, which means it returns a copy of the source Ability, and so your Skill objects will end up holding dangling pointers to temporary Ability objects that have been destroyed immediately after the Skill constructor exits. So your code has undefined behavior.
AbilityScores::GetAbility() needs to return the Ability object by reference instead:
Ability& AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return abilityScores[i];
}
}
throw ...; // there is nothing to return!
}
...
Skill s* = new Skill[2];
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
...
If you want to return a default Ability when the abilityName is not found, consider using std::map instead of std::vector:
private:
std::map<std::string, Ability> abilityScores;
AbilityScores::AbilityScores() {
abilityScores["Strength"] = Ability("Strength", ...);
abilityScores["Charisma"] = Ability("Charisma", ...);
...
}
Ability& AbilityScores::GetAbility(string abilityName) {
// if you don't mind Name() returning "" for unknown abilities...
return abilityScores[abilityName];
// otherwise...
auto iter = abilityScores.find(abilityName);
if (iter == abilityScores.end()) {
iter = abilityScores.emplace(abilityName, 0.0f).first;
}
return iter->second;
}
...
Skill s* = new Skill[2];
s[0] = Skill(&as.GetAbility("Strength"));
s[1] = Skill(&as.GetAbility("Charisma"));
...
Otherwise, return the Ability object by pointer instead:
Ability* AbilityScores::GetAbility(string abilityName) {
for (int i = 0; i < abilityScores.size(); i++) {
if (abilityScores[i].Name() == abilityName) {
return &abilityScores[i];
}
}
return nullptr;
// or:
abilityScores.emplace_back(abilityName, 0.0f);
return &(abilityScores.back());
}
...
Skill s* = new Skill[2];
s[0] = Skill(as.GetAbility("Strength"));
s[1] = Skill(as.GetAbility("Charisma"));
...

Losing a data member of a base class after the constructor is called

I have been working on a project and had no problems until today where I lost a class data member after the constructor is called. I could not pinpoint where the change happens. I have several classes for cars. The classes related to the cars are in the code block below. After all the cars are created in the class RegistrationSystem they are stored in an array. however, while calling a display function in RegistrationSystem the first car loses the color value. In the class RegistrationSystem the first Pickup in the class stores the value until the constructor is complete. After the constructor ends, the color value string shows " " in the debugger.
class Car {
protected:
string color;
public:
Car(string c) { color = c; };
string getColor(void) { return color; }
friend ostream& operator<<(ostream& outStream, const Car& car) {
cout << car.color;
return outStream;
}
};
class Pickup : public Car {
public:
Seat *frontSeat = new Seat(FRONT_SEAT_CREDIT);
Pickup(string c) : Car(c) {}
};
class Compact : public Car {
public:
Seat *frontSeat = new Seat(FRONT_SEAT_CREDIT);
Seat *sideBackLeftSeat = new Seat(BACK_SEAT_COMPACT_CREDIT);
Seat *sideBackRightSeat = new Seat(BACK_SEAT_COMPACT_CREDIT);
Compact(string c) : Car(c) {}
};
class Sedan : public Car {
public:
Seat *frontSeat = new Seat(FRONT_SEAT_CREDIT);
Seat *sideBackLeftSeat = new Seat(SIDE_BACK_SEDAN_CREDIT);
Seat *sideBackRightSeat = new Seat(SIDE_BACK_SEDAN_CREDIT);
Seat *middleBackSeat = new Seat(MID_BACK_SEDAN_CREDIT);
Sedan(string c) : Car(c) {}
};
class RegistrationSystem {
private:
string file_name;
int menu_response;
Reservation *reservations[24] = { NULL };
Passenger *rowers[24];
Pickup *pickup_cars[3];
Compact *compact_cars[3];
Sedan *sedan_cars[3];
// Displays the Layouts
void displaySeatArrangements(void);
// Saves the information in the file
void saveToFile(void);
// Find the rower in array rowers
Passenger* findRower(string);
// Displays the menu for the seat choice of a car type
bool displayCarSeatingChoiceMenu(string);
// Make a reservation in the system
bool makeReservation(string, string, int, Passenger&);
// Delete a reservation
bool deleteReservation(int);
// Print Reservations
void saveReservationsToFile(void);
// Sub functions for makeReservation()
bool makePickupReservation(Pickup*, Passenger, int&, string, string);
bool makeCompactReservation(Compact*, Passenger, int&, string, string);
bool makeSedanReservation(Sedan*, Passenger, int&, string, string);
public:
RegistrationSystem(void);
void chooseOperation(void);
Passenger* getPassengers(void) { return *rowers; }
friend ostream& operator<<(ostream&, const RegistrationSystem&);
friend istream& operator>>(istream&, RegistrationSystem&);
};
The display function has a line:
<< setw(8) << *(pickup_cars[index]) << setw(8) << *(compact_cars[index]) << setw(11) << *(sedan_cars[index]) << endl
where the *(pickup_cars[index]) is set to " " and the seat value gives error = read memory from 0x6 failed (0 of 4 bytes read). That is also set to NULL.
Here is the code of the RegistrationSystem constructor:
RegistrationSystem::RegistrationSystem(void) {
file_name = "seat_credits.txt";
menu_response = 0;
ifstream inFile(file_name);
if(!inFile.is_open()) {
cout << "Error opening file. Terminating...";
exit(1);
}
// Read file to set passengers and their credits in rowers array
int count = 0;
while(!inFile.eof() && count < 24) {
string first, last;
int credits;
inFile >> first >> last >> credits;
string fullName = first + ' ' + last;
rowers[count] = new Passenger(fullName, credits);
count++;
}
// Assign all the cars to the arrays
pickup_cars[0] = new Pickup("PURPLE");
pickup_cars[1] = new Pickup("YELLOW");
pickup_cars[2] = new Pickup("RED");
compact_cars[0] = new Compact("GREEN");
compact_cars[1] = new Compact("BLUE");
compact_cars[2] = new Compact("YELLOW");
sedan_cars[0] = new Sedan("RED");
sedan_cars[1] = new Sedan("GREEN");
sedan_cars[2] = new Sedan("BLUE");
inFile.close();
}
The problem occurred when the input file stream was still open and I was creating new instances and assigning their addresses to pointers before I closed the file. After I switched the order and closed the file, then assigned pointers the addresses of the new objects the problem went away.
These operations were happening inside of the constructor of the RegistrationSystem class. Here is the new code:
RegistrationSystem::RegistrationSystem(void) {
file_name = "seat_credits.txt";
menu_response = 0;
ifstream inFile(file_name);
if(!inFile.is_open()) {
cout << "Error opening file. Terminating...";
exit(1);
}
// Read file to set passengers and their credits in rowers array
int count = 0;
while(!inFile.eof() && count < 24) {
string first, last;
int credits;
inFile >> first >> last >> credits;
string fullName = first + ' ' + last;
rowers[count] = new Passenger(fullName, credits);
count++;
}
inFile.close();
// Assign all the cars to the arrays
pickup_cars[0] = new Pickup("PURPLE");
pickup_cars[1] = new Pickup("YELLOW");
pickup_cars[2] = new Pickup("RED");
compact_cars[0] = new Compact("GREEN");
compact_cars[1] = new Compact("BLUE");
compact_cars[2] = new Compact("YELLOW");
sedan_cars[0] = new Sedan("RED");
sedan_cars[1] = new Sedan("GREEN");
sedan_cars[2] = new Sedan("BLUE");
}
The line inFile.close() was placed after all the array assignments. Moving it above them solved the problem of losing the first data member of my Pickup object.

Segmentation fault error with structures

I have no idea where the segmentation error is coming from ... Any ideas?
I am working with structures for an assignment
TestResult testResultFactory(std::string name, double mark)
{
//creating an object of TestResult
TestResult car;
car.name = name;
car.mark = mark;
return car;
}
Student studentFactrory(std::string name)
{
//Creating an object of student
Student house;
house.name = name;
house.testResults = 0;
house.numTestResults = 0;
return house;
}
void addTestResult(Student * student, std::string testName, double testMark)
{
//First we need to create a new array
(student->numTestResults)+=1;
TestResult *newTestArray = new TestResult[(student->numTestResults)];
//Now we loop through the old array and add it to the new one
int index = (student->numTestResults);
for (size_t i = 0; i < (index-1); i++)
{
newTestArray[i] = testResultFactory((student->testResults[i].name),(student->testResults[i].mark));
}
//Now we need to add the new student to the end of the array
newTestArray[index] = testResultFactory(testName, testMark);
(student->testResults) = newTestArray;
}
string studentBest(Student const * student)
{
//create variables as temps
string highestName;
double highestMark;
int index = (student->numTestResults);
//Setting the two variables to the first value
highestName = (student->testResults[0].name);
highestMark = (student->testResults[0].mark);
//Using a while loop to compare and get the best
for (size_t i = 0; i < index; i++)
{
if((student->testResults[i].mark)> highestMark)
{
highestMark = (student->testResults[i].mark);
highestName = (student->testResults[i].name);
}
}
//returning the string they want
string send = (highestName)+ " "+ doubleToString(highestMark)+ "%";
return send;
}
double studentAverage(Student const * student)
{
//Variables used as temps
double average = 0;
double counter = 0.0;
double running = 0;
int index = (student->numTestResults);
//Now we need to loop through each one and add to running and counter
for (size_t i = 0; i < index; i++)
{
counter++;
running += (student->testResults[i].mark);
}
//calculating the average;
average = (running)/counter;
return average;
}
void destroyStudent(Student * student)
{
delete [] (student->testResults);
(student->testResults)=0;
}
Subject subjectFactory(std::string name)
{
//Creating an object to use in subject factory
Subject lamp;
lamp.name = name;
lamp.numStudents = 0;
lamp.studentsAllocated = 0;
lamp.students = 0;
return lamp;
}
MY guess is that the error occurs because of an out of bounds array or an pointer not worked with correctly .
int getStudentIndex(Subject const * subject, std::string studentName)
{
int index;
int count = (subject->numStudents);
//loop to find the names and set index
for (size_t i = 0; i < count; i++)
{
if(studentName == ((subject->students[i].name)))
{
index = i;
}
else index = -1;
}
return index;
}
void addStudent(Subject * subject, std::string studentName)
{
//Variables as temps
Student *pointer =0;
int index = getStudentIndex(subject,studentName);
if(index != -1)
{
//Now we need to see if they are large enough
if((subject->studentsAllocated)==0)
{
//Set the allocated to 2
(subject->studentsAllocated) = 2;
pointer = new Student[2];
//Figure this out later
pointer[1] = studentFactrory(studentName);
(subject->students) = pointer;
}
else
{
//increase SA with 1.5
(subject->studentsAllocated) = (subject->studentsAllocated) * 1.5;
pointer = new Student[(subject->studentsAllocated)+1];
int count = (subject->studentsAllocated);
//Now we need to put all the other students in
for (size_t i = 0; i < count-1; i++)
{
pointer[i] = (subject->students[i]);
}
pointer[(subject->studentsAllocated)+1] = studentFactrory(studentName);
(subject->studentsAllocated) += 1 ;
}
//Once done just seet one equal to
(subject->students) = pointer;
}
else return;
}
void removeStudent(Subject * subject, std::string studentName)
{
//First get temps
int index = getStudentIndex(subject ,studentName);
int number = (subject->studentsAllocated);
int i = index;
//delete student
if(index == -1) return;
destroyStudent(&(subject->students)[index]);
//loop to shift the things
while (i<(number -1))
{
(subject->students)[i] = (subject-> students[i+1]);
}
//Removing the last one
(subject->numStudents) -= 1;
}
bool addTestResult(Subject * subject, std::string studentName, std::string testName, double testMark)
{
int index = getStudentIndex(subject ,studentName);
if(index != -1)
{
addTestResult(&(subject->students [index]),testName,testMark);
return true;
}
else
return false;
}
void printSubjectSummary(Subject const * subject)
{
cout<<(subject->name)<< ": with "<<(subject->numStudents)<<" students"<<endl;
//Variables to use in the loop
size_t indexLoop = subject->numStudents;
int i=0;
while (i< indexLoop)
{
cout<<(subject->students[i].name)<<" Average: "<<studentAverage(&(subject->students[i]))<<", Best: "<<studentBest(&(subject->students[i]))<<endl;
}
}
void destroySubject(Subject * subject)
{
//Variables
size_t indexLoop = subject->numStudents;
for (size_t i = 0; i < indexLoop; i++)
{
destroyStudent(&(subject->students[i]));
}
delete [] subject->students;
subject->students =0;
}
I can not seem to find where the segmentation error is coming from. Even restarted the whole assignment from scratch and still seem to get errors.
Can someone please help or indicate where the fault could be coming from.
Over here we have the structs.h file that is included in my code above
#ifndef STRUCTS_H
#define STRUCTS_H
struct TestResult{
double mark;//the test mark as a percentage
std::string name;//the test name
};
struct Student{
std::string name;
TestResult * testResults;//an arry of TestResults
size_t numTestResults;//the number of results for this student (also the size of the array)
};
struct Subject{
std::string name;
Student * students;//an array of Students
size_t numStudents;//the number of students added to the subject
size_t studentsAllocated;//the size of the Student arry(must never be smaller that numStudents)
};
#endif
There are so many logical errors in there that the root cause (or causes; there are quite a few candidates) could be pretty much anywhere.
getStudentIndex returns -1 unless the student is the last one in the array, and an indeterminate value for the first one you add, so adding the first student to a subject is undefined.
addStudent only adds a student if they're already taking the subject.
It also (for some inexplicable reason) allocates an array of two Students, leaving the first element uninitialised.
Using this first element is, of course, undefined.
In the other branch, it first claims that the number of allocated students is * 1.5, but then only allocates + 1.
This will undoubtedly lead to problems.
There is a recursion in addTestResult that will never terminate.
There are most likely other problems as well – this was just a quick glance.
Start with fixing these.
And do learn about constructors and destructors so you can get rid of those "factory" and "destroy" functions.

Getline() and cin manipulate dynamic array

I'm totally lost and confused and could use some help.
I'm currently working on a small command line-based game. For this I wrote a class Inventory, dynamically creating an array of invSpace-objects, each space representing a pair of a pointer to an Item (another class of mine) and a integer, depicting a quantity. Here's the code:
class invSpace {
public:
Item *item;
int quantity;
invSpace() {
item = NULL;
quantity = 0;
}
};
class Inventory {
private:
invSpace* spaces = NULL;
size_t size;
public:
int free_space() {
int free = 0;
for (int i = 0; i < size; i++) {
if (spaces[i].item == NULL) {
free++;
}
}
return free;
}
Inventory() {}
Inventory(size_t new_size) {
size = new_size;
spaces = new invSpace[size];
for (int i = 0; i < size; i++) { //I know this is obsolete because
spaces[i].item = NULL; //of the invSpace constructor, I
spaces[i].quantity = 0; //just did this for testing
}
~Inventory() {
delete[] spaces;
}
invSpace& operator[](int index) {
return spaces[index];
}
};
There are some more methods in this class, like for adding, deleting and searching for items, but those don't matter now. So this is basically just a simple array within one object, dynamically allocating memory in the constructor and with some extra methods. After being created, the array contains zero elements, or Items, so the free_space() method should return the size of the array. But it doesn't. It returns about half of the size.
My first thought was that something went wrong with the allocation. But at a second glance I noticed that the Inventory is totally fine directly after being created; with exactly as many spaces as requested, all of them set to item=NULL/quantity=0. But after a call of getline() at the start of main() that scans user input and saves it to a string for further analyzing, some spaces get filled with random addresses and integers.
Even stranger, with each new call of getline() some spaces are freed, some others filled. As far as my debugging, experimenting and testing goes, none of these addresses belong to any variable in my program, they are just plain random. Also, at no point is there be any interference with the Inventory and the getline() function or the string it returns. In fact, after being created, no part of this object is used anywhere in the code beside the free_space() method. What's even stranger is that spaces in the Inventory class is marked private, so a method is required to meddle with this pointer/array (or so I would expect).
This problem occurs with getline() and cin but not with any of C's <stdio.h> input stream functions. Using malloc() instead of new[] makes no difference. Of course, I could use something like scanf() for the reading from the console. Still, I just want to know why all these things happen. I have absolutely no idea.
Thanks in advance for every answer!
EDIT:
I narrowed the whole code so that it still produces the same error, also changed free_space() so that it prints adress and integer if present:
#include <iostream>
#include <string>
#include <map>
using namespace std;
class Item {
public:
static map<string, Item*> itemlist;
string name;
string description;
Item() {}
Item(const string new_name, const string new_description) {
name = new_name;
description = new_description;
itemlist.insert(pair<string, Item*> (name, this));
}
};
map<string, Item*> Item::itemlist;
/*The more Items are declared, the more random adresses appear in the
inventory*/
Item item01("sword", "A sharp and deadly weapon.");
Item item02("shield", "This will protect you. To a certain extent.");
Item item03("stick", "What is this for exactly?");
Item item04("bottle of water", "A bottle full of refreshing spring water.");
class invSpace {
public:
Item *item;
int quantity;
invSpace() {
item = NULL;
quantity = 0;
}
};
class Inventory {
private:
invSpace* spaces = NULL;
size_t size;
public:
int free_space() {
int free = 0;
for (int i = 0; i < size; i++) {
if (spaces[i].item == NULL) {
free++;
cout << i << " = free" << endl;
}
else {
cout << spaces[i].item << " / " << spaces[i].quantity << endl;
}
}
return free;
}
Inventory() {}
Inventory(size_t new_size) {
size = new_size;
spaces = new invSpace[size];
for (int i = 0; i < size; i++) {
spaces[i].item = NULL;
spaces[i].quantity = 0;
}
}
~Inventory() {
delete[] spaces;
}
};
class Player {
public:
string name;
Inventory inventory;
Player(const string new_name) {
inventory = Inventory(40);
name = new_name;
}
};
Player player("Me");
int main() {
string input;
//Inventory inventory(40); //no error when declared outside the Player class
while (1) {
cout << "\n>> ";
getline(cin, input);
if (input == "x") {
break;
}
else {
player.inventory.free_space();
}
}
}
Some things I noticed: No error occurs if the inventory isn't part of a Player-object. If it is but no Items are declared only the first inventory space receives a random adress (and int value) after the first call of getline().
The more Items there are, the more random adresses I get, it seems...

access violation reading location c++

I'm writing a program that print the full english name of the number inputted by the user. it's not a complete program but i keep getting an error:
First-chance exception at 0x00b02c76 in Programming Challenge 14.1.exe: 0xC0000005: Access violation reading location 0xcccccd80.
Unhandled exception at 0x00b02c76 in Programming Challenge 14.1.exe: 0xC0000005: Access violation reading location 0xcccccd80.
I've tried looking around and couldn't find anything of use to me. here this the program:
header file:
#ifndef NUMBERS_H
#define NUMBERS_H
#include <string>
using namespace std;
const int SIZE1 = 18;
const int SIZE2 = 8;
class Numbers
{
private:
int number;
string hundred;
string thousand;
string * one;
string * ten;
public:
Numbers(int num)
{
number = num;
hundred = "hundred";
thousand = "thousand";
string * one = new string[SIZE1];
string * ten = new string[SIZE2];
}
void initializeArray()
{
// Intialize array "one"
one[0] = "zero";
one[1] = "one";
one[2] = "two";
one[3] = "three";
one[4] = "four";
one[5] = "five";
one[6] = "six";
one[7] = "seven";
one[8] = "eight";
one[9] = "nine";
one[10] = "eleven";
one[11] = "twelve";
one[12] = "thirteen";
one[13] = "fourteen";
one[14] = "fifteen";
one[15] = "sixteen";
one[16] = "seventeen";
one[17] = "eighteen";
one[18] = "nineteen";
// Initialize the ten array
ten[0] = "ten";
ten[1] = "twenty";
ten[2] = "thirty";
ten[3] = "forty";
ten[4] = "fifty";
ten[5] = "sixty";
ten[6] = "seventy";
ten[7] = "eighty";
ten[8] = "ninety";
}
string determine()
{
string name = "";
for (int i = 0; i <= number; i++)
{
if (number == i)
{
name = one[i];
}
}
return name;
}
~Numbers()
{
delete [] one;
delete [] ten;
}
};
#endif
and this is the main program, im just using a constructor to assign a value to number to make debugging a little faster
#include <iostream>
#include "Numbers.h"
using namespace std;
int main()
{
Numbers n(5);
string name = n.determine();
cout << "The number is " << name << endl;
cin.ignore();
cin.get();
return 0;
}
by the way this is vc++ for the compiler
ill answer any questions as this isnt really too organized
const int SIZE1 = 18;
Valid array index for the array of SIZE1 are 0 to 17. In general, valid indexes for an array of size N are 0 to N-1.
I recommend using std::vector<std::string>.
one holds 18 elements, but you put 19 elements in there.
Two things here:
You are not calling "initializeArray()" at all. So when you are trying to access the array there is nothing there. I would recommend calling it in the constructor. Like this:
Numbers(int num)
{
number = num;
hundred = "hundred";
thousand = "thousand";
one = new string[SIZE1];
ten = new string[SIZE2];
initializeArray();
}
Second, is what the guys above said. You have an incorrect value for the size of your array since you are trying to assign 19 values to an array of size 18. Just to be really sure lets make the size bigger than we expect and you can adjust later:
const int SIZE1 = 20;
const int SIZE2 = 20;
Additionally, See your determine()? instead of using a for loop why don't you go:
string name = one[number];
EDIT: Wow there was another thing I missed...you have declared your array pointer variable twice and so it's actually going out of scope thinking you want to make some local versions. Look at my adjusted implementation of your constructor above again. See how I've removed the "String *" from before the variable names.
The variable "one" and "ten" have been changed from string pointers to vectors holding strings. Called the initializeArray within the constructor. Changed the way the name string was being assigned the new string. Here is the working code.
class Numbers
{
private:
int number;
string hundred;
string thousand;
vector<string> one;
vector<string> ten;
public:
Numbers(int num)
{
number = num;
hundred = "hundred";
thousand = "thousand";
initializeArray();
}
void initializeArray()
{
one.push_back("zero");
one.push_back("one");
one.push_back( "two");
one.push_back("three");
one.push_back("four");
one.push_back("five");
one.push_back("six");
one.push_back("seven");
one.push_back("eight");
one.push_back("nine");
one.push_back("eleven");
one.push_back("twelve");
one.push_back("thirteen");
one.push_back("fourteen");
one.push_back("fifteen");
one.push_back("sixteen");
one.push_back("seventeen");
one.push_back("eighteen");
one.push_back("nineteen");
// Initialize the ten array
ten.push_back("ten");
ten.push_back("twenty");
ten.push_back("thirty");
ten.push_back("forty");
ten.push_back("fifty");
ten.push_back("sixty");
ten.push_back("seventy");
ten.push_back("eighty");
ten.push_back("ninety");
}
string determine()
{
string name("");
for (int i = 0; i <= number; i++)
{
if (number == i)
{
auto iter = one.begin();
iter += i;
name.assign(*iter);
}
}
return name;
}
~Numbers()
{
}
};
int main()
{
Numbers n(5);
string name = n.determine();
cout << "The number is " << name << endl;
cin.ignore();
cin.get();
return 0;
}