Currently, I'm trying to make a function that sorts a vector full of fighters in the function sortFighters in the Fighter.cpp file. It all seems to compile correctly; However, when it does run, I get a fatal error in one of the lines of the aformentioned .cpp file. I know exactly what the problem is, and put a comment there accordingly.
So, what I'm asking here, is what I might do to fix this problem without adding any other functions and such.
Here's my Fighter.h file:
#ifndef FIGHTER_H
#define FIGHTER_H
#include <iostream>
#include <ctime>
#include <string>
#include <cstdlib>
#include <fstream>
#include <vector>
class Fighter
{
protected:
std::string name;
int health, level;
//int damage;
public:
int getHealth(int);
void getEnemies(std::vector<Fighter> &);
void printFighter(std::vector<Fighter> &);
void sortFighters(std::vector<Fighter> &);
//friend std::istream & operator >> (std::istream & strm, Fighter & x);
//friend std::ostream & operator << (std::ostream & strm, const Fighter & f);
//void attack();
Fighter();
~Fighter();
};
class Player : public Fighter
{
private:
int experience;
public:
int getHealth(int);
void pri`enter code here`ntFighter();
void getExperience(int);
void playerAttack();
Player();
~Player();
};
//class FightPub
//{
// private:
// Player player;
// Fighter enemy;
// public:
// //void fight();
// //void getStats();
//};
#endif
My Fighter.cpp file:
//dynamically locate an array that holds the number of fighters, and for each fighter in the array, assign from the .txt
//file the name and level from the fighter.
#include "Fighter.h"
#pragma region getEnemies
void Fighter::getEnemies(std::vector<Fighter> &baddie)
{
Fighter x;
std::ifstream inputFile;
inputFile.open("EnemyFighters.txt");
if(!inputFile)
{
std::cout << "error!" << std::endl;
}
else
{
while(!inputFile.eof())
{
std::string line;
inputFile >> line;
if (line == "<fighter>")
{
do
{
inputFile >> line;
x.name = line;
inputFile >> line;
x.level = atoi(line.c_str());
inputFile >> line;
x.health = getHealth(this->level);
baddie.push_back(x);
inputFile >> line;
}while(line != "</fighter>");
}
}
inputFile.close();
}
}
#pragma endregion
#pragma region getHealth
int Fighter::getHealth(int lv)
{
if(lv >= 6)
{
std::cout << "\nHealth Bonus!";
this->health = lv * 2;
}
/*else if (lv > 1)
for (int i = 1; i < lv; i++)
{this->health += 2;}*/
return health;
}
#pragma endregion
#pragma region attack
//void Fighter::attack()
//{
// int randomAttack = rand() % 4 + 1;
//
// switch (randomAttack)
// case 1:
// {
// std::cout << "Enemy uses critical attack!"
// }
//}
#pragma endregion
#pragma region printFighter
void Fighter::printFighter(std::vector<Fighter> &baddie)
{
//std::cout << this;
for (int i=0; i<baddie.size(); i++)
{
std::cout << "\nName: " << baddie[i].name << std::endl
<< "Level: " << baddie[i].level << std::endl
<< "Health: " << baddie[i].health << std::endl;
}
}
#pragma endregion
void Fighter::sortFighters(std::vector<Fighter> &x)
{
Fighter * temp = new Fighter;
bool swap;
do
{
swap = false;
std::cout << x.size() << std::endl;
for (int i=0; i<=(x.size()); i++)
{
//if the level in the first is greater than the level in the next
if(x[i].level > x[i+1].level)//I get a fatal error here when it tries to compare
//the iterator with 1 that's outside its range
{
//assign the stats from the first to temp
temp->name = x[i].name;
temp->health = x[i].health;
temp->level = x[i].level;
//assign the stats from the next to the first
x[i].name = x[i+1].name;
x[i].health = x[i+1].health;
x[i].level = x[i+1].level;
//assign the ones in temp(the first) to the next
x[i+1].name = temp->name;
x[i+1].health = temp->health;
x[i+1].level = temp->level;
swap = true;
}
else if(x[i].level >= x[i+1].level)
{
temp->name = x[i].name;
temp->health = x[i].health;
temp->level = x[i].level;
x[i].name = x[i+1].name;
x[i].health = x[i+1].health;
x[i].level = x[i+1].level;
x[i+1].name = temp->name;
x[i+1].health = temp->health;
x[i+1].level = temp->level;
swap = true;
}
else if (x[i].level < x[i+1].level)
{
//temp->name = x[i].name;
//temp->health = x[i].health;
//temp->level = x[i].level;
//x[i].name = x[i+1].name;
//x[i].health = x[i+1].health;
//x[i].level = x[i+1].level;
//x[i+1].name = temp->name;
//x[i+1].health = temp->health;
//x[i+1].level = temp->level;
swap = false;
}
else if(x[i].level <= x[i+1].level)
{
/*temp->name = x[i].name;
temp->health = x[i].health;
temp->level = x[i].level;
x[i].name = x[i+1].name;
x[i].health = x[i+1].health;
x[i].level = x[i+1].level;
x[i+1].name = temp->name;
x[i+1].health = temp->health;
x[i+1].level = temp->level;*/
swap = false;
}
}
}while (swap);
delete temp;
}
//std::istream & operator >>(std::istream & strm, Fighter x)
//{
// //x.name += strm.c_str();
// //x.level += atoi(strm.c_str());
// strm >> x.name;
// strm >> x.level;
// return strm;
//}
//std::ostream & operator << (std::ostream & strm, const Fighter f)
//{
// strm << "Name: " << f.name << std::endl;
// strm << "Level: " << f.level << std::endl;
// strm << "Health: " << f.health << std::endl;
// return strm;
//}
#pragma region Fighter C&D
Fighter::Fighter()
{
level = 1;
health = 10;
}
Fighter::~Fighter()
{
}
#pragma endregion
//void operator <()
//{
//}
//
//void operator >()
//{
//}
//
//void operator <=()
//{
//}
//
//void operator >=()
//{
//}
//
//
//
int Player::getHealth(int lv)
{
if(lv >= 6)
{
std::cout << "\nHealth Bonus!";
this->health = lv * 2;
}
/*else if (lv > 1)
for (int i = 1; i < lv; i++)
{this->health += 2;}*/
return health;
}
void Player::printFighter()
{
//std::cout << this;
std::cout << "\nPlayer's stats: \n"
<< "Level: " << this->level << std::endl
<< "Health: " << this->health << std::endl
<< "Experience: " << this->experience <<std::endl;
}
void Player::getExperience(int dmg)
{
experience += dmg;
if (experience >= (level * 10))
{
std::cout << "Congratulations, Player! You're up a level!\n";
level ++;
}
}
#pragma region Player C&D
Player::Player()
{
level = 1;
health = getHealth(level);
experience = 0;
}
Player::~Player()
{
}
#pragma endregion
//Player::printFighter()
//{
//
//}
And here's main.cpp:
#include "Fighter.h"
int main()
{
unsigned seed = time(0);
srand(seed);
std::vector<Fighter> baddie;
Fighter * enemy = new Fighter;
Player * me = new Player;
enemy->getEnemies(baddie);
enemy->sortFighters(baddie);
enemy->printFighter(baddie);
me->printFighter();
delete enemy;
delete me;
return 0;
}
for (int i=0; i<=(x.size()); i++)
{
if(x[i].level > x[i+1].level)
{
um.. Size() counts from 1. Indexes count from 0. So you'll want to make that i < x.size(), not <=. But, in the very next line, you say x[i+1], so i can't even reach the last item, it has to stop one before that:
for (int i=0; i < x.size()-1; i++)
You've gotten some advice about how to fix that loop. My advice would be to eliminate it and use std::sort instead.
While we're dealing with loops that don't terminate correctly, however, it's probably also worth mentioning one other (in getEnemies()):
while(!inputFile.eof())
{
std::string line;
inputFile >> line;
if (line == "<fighter>")
{
// ...
This is broken as well. For the loop to terminate correctly, you need to read the data, and then check whether the read succeeded:
std::string line;
while (inputFile >> line) {
if (line == "<fighter>") {
// ...
It's probably also worth noting that this code is pretty fragile -- just for one example, something like: <fighter>fighter1</fighter> will not be read correctly (it requires at least one whitespace before and after <fighter> to read it as a single string).
Try Changing your for loop to this
for (int i=0; i < x.size() - 1; i++) {
... your original content...
}
This way x[i+1] never goes out of bounds
You were trying to access memory that has not been allocated.
Your problem is with this loop:
for (int i=0; i<=(x.size()); i++){
if(x[i].level > x[i+1].level){ //Fatal Error Here
// Do some stuff
}
// Do some more stuff
}
Your condition for terminating the outer loop is i<=(x.size()) this means that when you do the comparision ( x[i+1].level ) that breaks the program, you are comparing outside the bounds of x. Because if i == x.size() then x[i+1] > x.size()
I reccomend changing your loop to terminate at i<(x.size())-1; rather than i<=(x.size());
The problem, as others have said, is this section of code:
for (int i=0; i<=(x.size()); i++)
{
//if the level in the first is greater than the level in the next
if(x[i].level > x[i+1].level)//I get a fatal error here when it tries to compare
//the iterator with 1 that's outside its range
A std::vector can be indexed by values 0 through size() - 1, inclusive. So, for a basic vector loop, you should instead do
for (int i = 0; i < x.size(); i++) {
BUT, in the next line of code, you check element i + 1, so you should instead do
for (int i = 0; i < x.size() - 1; i++) {
BUT, because x.size() is unsigned, if x is empty, then x.size() - 1 will be a very large number (2^32 - 1 on a 32-bit machine). So you should adjust the logic for this. Also, comparing signed values (like int i against unsigned values (like x.size() - 1) may generate compiler warnings (you should turn all such compiler warnings on, if you haven't already done so), so change i to unsigned or size_t:
for (size_t i = 0; i + 1 < x.size(); i++) {
Finally, rather than coding your own bubble sort, it's better to use std::sort. std::sort is faster and more familiar to other C++ developers. Here's an (untested) example of using std::sort:
bool CompareByLevel(const Fighter& a, const Fighter& b) {
return a.level < b.level;
}
sort(x.begin(), x.end(), CompareByLevel);
Other comments: If you're interested in learning more about C++, here are a few other comments that might help.
inputFile >> line;
This statement actually reads a single whitespace- or newline-separated word into line. If that's what you're trying to do, then your choice of variable name (line) doesn't communicate that. And you may want to be able to use whitespace in fighters' names. To read an entire line, use this: (See here for reference.)
getline(inputFile, line);
getEnemies, printFighter, and sortFighters should be static methods, since they don't need a particular instance of a Fighter to operate on. (Right now, because they're not static methods, you have to create an enemy instance of Fighter in order to call those methods, even though none of those methods do anything with enemy.)
C++ lets you create variables on the stack, instead of dynamically allocating them. In other words, instead of saying
Fighter * temp = new Fighter;
just say
Fighter temp;
This is faster and simpler, if you don't need dynamic allocation.
Finally, C++ will create assignment operators for you that copy all of a class's members. So you could simply write
temp = x[i];
instead of manually assigning each of x's members to temp. Using the assignment operator is more robust, since it will continue to work in the future if you later add members to Fighter.
Hope this helps.
Related
I keep getting an error of bad memory allocation. I've spent the whole night trying to find where I went wrong but I can't figure out what.
I've combed through every line but still nothing. Could it be that my program/laptop just isn't strong enough?
Any help would be extremely helpful. My head is ringing and I need some rest.
Here's my code:
#include <iostream>
#include <fstream>
#include <cstdlib>
#include <vector>
#include <string>
#include <sstream>
using namespace std;
// struct to store word + count combinations
struct wordItem{
string word;
int count;
};
void getStopWords(char *ignoreWordFileName, vector<string>& _vecIgnoreWords);
bool isCommonWord(string word, vector<string>& _vecIgnoreWords);
void printTopN(wordItem wordItemList[], int topN);
void doubleArray(wordItem wordItemList[], int size);
int getTotalNumberNonCommonWords(wordItem wordItemList[], int size, int wordCount);
const int STOPWORD_LIST_SIZE = 50;
// ./a.out 10 HW1-HungerGames_edit.txt HW1-ignoreWords.txt
int main(int argc, char* argv[]){
vector<string> vecIgnoreWords(STOPWORD_LIST_SIZE);
// verify we have the correct # of parameters, else throw error msg & return
if (argc != 4){
cout << "Usage: ";
cout << argv[0] << " <number of words> <filename.txt> <ignorefilename.txt>"<< endl;
return 0;
}
//Set vector with stop words
getStopWords(argv[3], vecIgnoreWords);
//initialize struct array
int aSize = 100;
wordItem *theStructArray = new wordItem[aSize];
int counter = 0;
int doubleCount = 0;
//read main txt file
ifstream inFile(argv[1]);
if(inFile.is_open()){
string line;
string theWord;
//extract words from file
while(getline(inFile, line)){
istringstream iss(line);
//extract and analyze word
while(iss >> theWord){
if(!(isCommonWord(theWord, vecIgnoreWords))){
bool inStructArray = false;
int inStructPosition;
//search for word in Struct array
while (inStructArray == false){
for(int i=0; i<aSize; i++){
if (theWord == theStructArray[i].word){
inStructArray = true;
inStructPosition = i;
}
}
break;
}
//if word is in struct array
if (inStructArray == true){
theStructArray[inStructPosition].count++;
}
//else if it isn't
else{
//create new wordItem and add into struct
wordItem newWord;
newWord.word = theWord;
newWord.count = 1;
theStructArray[counter+(100*doubleCount)] = newWord;
counter++;
}
//if struct array hits maximum amount of elements,
if (counter == (aSize-1)){
doubleArray(theStructArray, aSize);
counter = 0;
doubleCount++;
aSize +=100;
}
}
}
}
inFile.close();
}
//Bubble sort masterArray
int bI, bJ, flag = 1;
wordItem bTemp;
for(bI=1; (bI <= aSize && flag); bI++){
flag = 0;
for(bJ=0; bJ<aSize; bJ++){
if(theStructArray[bJ+1].count > theStructArray[bJ].count){
bTemp = theStructArray[bJ];
theStructArray[bJ] = theStructArray[bJ+1];
theStructArray[bJ+1] = bTemp;
flag = 1;
}
}
}
//Print topN words
printTopN(theStructArray, atoi(argv[1]));
//print others
cout << "#" << endl;
cout << "Array doubled: " << doubleCount << endl;
cout <<"#" << endl;
cout << "Unique non-common words: "<< (aSize-100+counter)<<endl;
cout << "#"<<endl;
cout <<"Total non-common words: "<< getTotalNumberNonCommonWords(theStructArray, aSize, counter)<<endl;
return 0;
}
void getStopWords(char *ignoreWordFileName, vector<string>& _vecIgnoreWords){
ifstream inFile(ignoreWordFileName);
if(inFile.is_open()){
int a = 0;
string line;
while(getline(inFile, line)){
_vecIgnoreWords.insert(_vecIgnoreWords.begin() + a, line);
}
inFile.close();
}
return;
}
bool isCommonWord(string word, vector<string>& _vecIgnoreWords){
for(int i=0; i<STOPWORD_LIST_SIZE; i++){
if(word == _vecIgnoreWords.at(i)){
return true;
}
}
return false;
}
void printTopN(wordItem wordItemList[], int topN){
cout << endl;
for(int i=0; i<topN; i++){
cout<< wordItemList[i].count << '-' << wordItemList[i].word << endl;
}
return;
}
void doubleArray(wordItem wordItemList[], int size){
wordItem *tempArray = new wordItem[size+100];
for(int i=0; i<size; i++){
tempArray[i] = wordItemList[i];
}
delete [] wordItemList;
wordItemList = tempArray;
}
int getTotalNumberNonCommonWords(wordItem wordItemList[], int size, int wordCount){
int total = 0;
for(int i=0; i<(size-100+wordCount); i++){
total+=wordItemList[i].count;
}
return total;
}
You are doing very bad things in void doubleArray(wordItem wordItemList[], int size)
you can call delete [] on the array if you pass an array, but you cannot change its value, so doubleArray(theStructArray, aSize); will cause theStructArray to be deleted but not assigned to the memory you allocated. You are just assigning the local variable in the function doubleArray
It is similar to:
void doubleit(int x)
{
x *= 2;
}
int y=3;
doubleit(y);
here x was momentarily doubled to 6, but y never changed.
you need to use references, or better make theStructArray a std::vector and be done with it.
I have a member function that prints a snapshot of a boost::fibonacci_heap
virtual void printSnapshot(std::ostream& ss) {
Heap heap(this->heap);
double prev_price = DBL_MAX;
while(heap.size() > 0) {
const Order& order = heap.top();
if(order.price != prev_price) {
if(prev_price != DBL_MAX) ss << std::endl;
ss << order.price << " | ";
}
ss << order.quantity << " ";
prev_price = order.price;
heap.pop();
}
ss << std::endl;
}
I call this member function in another member function, which does
while(std::getline(stream, line)) {
... // do something on this->heap.
this->printSnapshot(std::cout);
}
Since the heap is created through a copy constructor at the beginning of "printSnapshot", then "printSnapshot" should change this->heap. However, this program leads to segment fault, while the following does not:
while(std::getline(stream, line)) {
... // do something on this->heap.
// this->printSnapshot(std::cout);
}
Now, if we add a const keyword to the definition of printSnapshot, i.e.
virtual void printSnapshot(std::ostream& ss) const {
Heap heap(this->heap);
double prev_price = DBL_MAX;
while(heap.size() > 0) {
const Order& order = heap.top();
if(order.price != prev_price) {
if(prev_price != DBL_MAX) ss << std::endl;
ss << order.price << " | ";
}
ss << order.quantity << " ";
prev_price = order.price;
heap.pop();
}
ss << std::endl;
}
The segment fault disappears. How could this be explained?
The constructor of fibonacci_heap that takes a lvalue reference (non-const) apparently doesn't do the right things.
It's not documented what it should do: http://www.boost.org/doc/libs/1_55_0/doc/html/boost/heap/fibonacci_heap.html#idp21129704-bb
I assume this might be a reportable bug. I'll look into this a bit.
UPDATE Surprisingly the behaviour of this constructor is apparently equivalent to move-construction:
#ifndef BOOST_NO_CXX11_RVALUE_REFERENCES
/// \copydoc boost::heap::priority_queue::priority_queue(priority_queue &&)
fibonacci_heap(fibonacci_heap && rhs):
super_t(std::move(rhs)), top_element(rhs.top_element)
{
roots.splice(roots.begin(), rhs.roots);
rhs.top_element = NULL;
}
fibonacci_heap(fibonacci_heap & rhs):
super_t(rhs), top_element(rhs.top_element)
{
roots.splice(roots.begin(), rhs.roots);
rhs.top_element = NULL;
}
The latter has the weird side-effect of simply removing all roots from the original (intrusive) list. This looks like a clear-cut bug.
Simply removing this constructor makes the code work.
The essential workaround is to avoid the lvalue-ref constructor:
Heap cloned(static_cast<Heap const&>(this->heap));
Meanwhile here's a self-contained reproducer:
#include <boost/heap/fibonacci_heap.hpp>
#include <iostream>
#include <random>
namespace {
#undef DBL_MAX
static double DBL_MAX = std::numeric_limits<double>::max();
std::mt19937 rng;
//std::uniform_real_distribution<double> dist(100, 4000);
std::discrete_distribution<int> dist({1,1,1,1,1,1});
static auto price_gen = [&] {
static double values[] = {52.40, 12.30, 87.10, 388., 0.10, 23.40};
return values[dist(rng)];
};
}
struct Order {
double price = price_gen();
unsigned quantity = rand() % 4 + 1;
double subtotal() const { return price * quantity; }
bool operator<(Order const& other) const { return subtotal() < other.subtotal(); }
};
using Heap = boost::heap::fibonacci_heap<Order>;
struct Y {
virtual void printSnapshot(std::ostream &ss) {
//Heap cloned(static_cast<Heap const&>(this->heap));
Heap cloned(this->heap);
double prev_price = DBL_MAX;
while (cloned.size() > 0) {
const Order &order = cloned.top();
if (order.price != prev_price) {
if (prev_price != DBL_MAX)
ss << std::endl;
ss << order.price << " | ";
}
ss << order.quantity << " ";
prev_price = order.price;
cloned.pop();
}
ss << std::endl;
}
void generateOrders() {
for (int i=0; i<3; ++i) {
heap.push({});
}
}
Heap heap;
};
int main() {
Y y;
for(int i=0; i<10; ++i) {
y.generateOrders();
y.printSnapshot(std::cout);
}
}
I've got a problem with creating an array of strings inside the object. I don't know how to patch it around so I'm asking for help. Here lies the problem:
main.h:
#pragma once
#include <iostream>
#include <conio.h>
#include <string>
class tab2D {
protected:
int width;
int height;
string **sTab;
int **iTab;
public:
tab2D();
tab2D(int x, int y, char c);
~tab2D();
tab2D(tab2D&t);
};
class chess: public tab2D {
public:
chess(int x, int y);
~chess();
chess(chess&c);
void init();
bool ifMove();
void show();
};
class matrix: public tab2D {
public:
matrix(int x, int y);
~matrix();
matrix(matrix&m);
};
The compiler says: syntax error : missing ';' before '*' about the line
string **sTab;
I assume that I can't make the dynamic array of strings and it makes further problems with processing this array.. Can you help me? :)
*UPDATE 1*Thanks, I forgot to add line
using namespace std;
Now it works, but I've got another problem.
#include "main.h"
using namespace std;
////// Konstruktor, konstruktor kopiujący oraz destruktor //////
chess::chess(int x = 8, int y = 8) : tab2D(x, y, 'c') {
init();
};
chess::chess(chess&c) {
chess(c.width, c.height);
};
chess::~chess() {
};
////// Metody //////
////// Uzupełnianie kolorów pól oraz rozstawianie figur i pionków //////
void chess::init() {
/// kolory pól: 0 - biały, 1 - czarny///
int last = 0;
for(int i = 0; i < this->height; ++i) {
for(int j=0; j < this->width; ++j) {
if(last = 0) {
this->sTab[i][j] = "1";
last = 1;
}
else if(last = 1) {
this->sTab[i][j] = "0";
last = 0;
}
}
if(last = 0)
last = 1;
else if(last = 1)
last = 0;
};
/// rozstawienie pionków ///
for(int i = 0; i < this->width; ++i) {
sTab[1][i] = sTab[1][i] + "0";
sTab[6][i] = sTab[6][i] + "a";
};
};
////// Wyświetlenie szachownicy //////
void chess::show() {
for(int i = 0; i < (this->height + 1); ++i) {
for(int j=0; j < (this->width + 1); ++j) {
if(i == 0 && j == 0)
cout << " ";
else if (i != 0 && j == 0) {
switch (i) {
case 1:
cout << "A ";
break;
case 2:
cout << "B ";
break;
case 3:
cout << "C ";
break;
case 4:
cout << "D ";
break;
case 5:
cout << "E ";
break;
case 6:
cout << "F ";
break;
case 7:
cout << "G ";
break;
case 8:
cout << "H ";
break;
default:
break;
}
}
else if (i == 0 && j != 0) {
cout << j << " ";
}
else {
cout << this->sTab[i-1][j-1] << " ";
}
}
cout << endl;
};
};
When I run the program, there is a breakpoint in the line
this->sTab[i][j] = "0";
I assume there is something wrong with making the array of strings but I don't understand why exactly there is a breakpoint and can't debug it.
UPDATE 2
Here is the code for tab.cpp:
#include "main.h"
using namespace std;
////// Konstruktor domyślny, konstruktor, konstruktor kopiujący oraz destruktor //////
tab2D::tab2D() {
};
tab2D::tab2D(int x, int y, char c) {
this->width = x;
this->height = y;
if (c == 'm') {
this->iTab = new int*[this->width];
for(int i=0;i<this->height;++i)
this->iTab[i] = new int[this->width];
}
else if (c == 'c') {
this->sTab = new string*[this->width];
for(int i=0;i<this->height;++i)
this->sTab[i] = new string[this->width];
}
else {
}
};
tab2D::tab2D(tab2D&t) {
tab2D(t.width, t.height, 't');
};
tab2D::~tab2D() {
for(int i=0;i<height;++i)
delete [] iTab[i];
delete [] iTab;
for(int i=0;i<height;++i)
delete [] sTab[i];
delete [] sTab;
};
You need to qualify names from the standard library:
std::string **sTab;
^^^^^
If you're doing what I think you're doing and allocating things with new, then you should consider using std::vector to deal with the quagmire of memory management issues you're about to encounter. If you really want to juggle pointers yourself for some reason, don't forget the Rule of Three.
UPDATE Your new problem might be because the copy constructor is horribly broken:
chess::chess(chess&c) {
chess(c.width, c.height);
};
This creates and destroys a temporary object, but doesn't initialise the object being constructed, leaving it in an invalid state. You probably don't want to declare a copy-constructor at all, as long as the base class is correctly copyable. If you did need one, it should should be more like:
chess::chess(chess const & c) : // 'const' so constant objects can be copied
tab2D(c) // copy the base-class subobject
{
// do whatever else needs doing
}
Alternatively, the new problem might be due to errors in the tab2D constuctors which you haven't shown us. The best way to track it down is to step through the program with a debugger, checking that everything is correctly initialised before use.
UPDATE Probably, the runtime error is caused by allocating the wrong number of pointers. You want
iTab = new int*[height]; // Not width
and likewise for sTab.
It's crashing at the very end of the main() function where it needs to delete the starters objects. The error message that pops up when I run the program says: Debug assertion failed! Expression: _BLOCK_IS_VALID(pHead->nBlockUse). How do i fix it from crashing when deleting the starters objects?
#include <iostream>
#include <fstream>
#include "olympic.h"
using namespace std;
ofstream csis;
int main() {
const int lanes = 4;
Ranker rank(lanes);
csis.open("csis.txt");
// First make a list of names and lane assignments.
Competitor* starters[lanes];
starters[0] = new Competitor("EmmyLou Harris", 1);
starters[1] = new Competitor("Nanci Griffith", 2);
starters[2] = new Competitor("Bonnie Raitt", 3);
starters[3] = new Competitor("Joni Mitchell", 4);
// The race is run; now assign a time to each person.
starters[0]->setTime((float)12.0);
starters[1]->setTime((float)12.8);
starters[2]->setTime((float)11.0);
starters[3]->setTime((float)10.3);
// Put everyone into the ranker.
for (int i = 0; i < lanes; i++)
rank.addList(starters[i]);
// Now print out the list to make sure its right.
cout << "Competitors by lane are:" << endl;
csis << "Competitors by lane are:" << endl;
for (int i = 1; i <= lanes; i++)
rank.getLane(i)->print();
// Finally, show how they finished.
cout << "Rankings by finish are:" << endl;
csis << "Rankings by finish are:" << endl;
for (int i = 1; i <= lanes; i++)
rank.getFinish(i)->print();
for (int i = 0; i < lanes; i++)
delete starters[i];
csis.close();
}
ranker.cpp:
#include "ranker.h"
#include "competitor.h"
#include <stdlib.h>
Ranker::Ranker(int lanes) {
athlete = new Competitor*[lanes];
numAthletes = 0;
maxAthletes = lanes;
}
int Ranker::addList(Competitor* starter) {
if (numAthletes < maxAthletes && starter != NULL) {
athlete[numAthletes] = starter;
numAthletes++;
return numAthletes;
}
else
return 0;
}
Competitor* Ranker::getLane(int lane) {
for (int i = 0; i < numAthletes; i++) {
if (athlete[i]->getLane() == lane) {
return athlete[i];
}
}
return NULL;
}
Competitor* Ranker::getFinish(int position) {
switch(position) {
case 1:
return athlete[3];
break;
case 2:
return athlete[2];
break;
case 3:
return athlete[1];
break;
case 4:
return athlete[0];
break;
}
return NULL;
}
int Ranker::getFilled() {
return numAthletes;
}
Ranker::~Ranker() {
delete [] athlete;
}
competitor.h:
#ifndef _COMPETITOR_H
#define _COMPETITOR_H
class Competitor {
private:
char* name;
int lane;
double time;
public:
Competitor(char* inputName, int inputLane);
Competitor();
void setTime(double inputTime);
char* getName();
int Competitor::getLane();
double getTime();
void print();
~Competitor();
};
#endif
competitor.cpp:
#include "competitor.h"
#include <string>
#include <iostream>
#include <iomanip>
using namespace std;
Competitor::Competitor(char* inputName, int inputLane) {
name = inputName;
lane = inputLane;
}
Competitor::Competitor() {
name = 0;
lane = 0;
time = 0;
}
void Competitor::setTime(double inputTime) {
time = inputTime;
}
char* Competitor::getName() {
return name;
}
int Competitor::getLane() {
return lane;
}
double Competitor::getTime() {
return time;
}
void Competitor::print() {
cout << setw(20) << name << setw(20) << lane << setw(20) << setprecision(4) << time << endl;
}
Competitor::~Competitor() {
delete [] name;
}
Call stack:
before crash: http://i.imgur.com/d4sKbKV.png
after crash: http://i.imgur.com/C5cXth9.png
After you've added Competitor class, it seems the problem is that you delete its name in Competitor's destructor. But you assign it from string literal which can't really be deleted. I'm sure the stack trace leading to assertion will prove that.
One way of solving the problem would be using std::string to store the name.
Problem is when deleting the char* value on destructor, which is assigned with const char instead new char. So i have slightly changed the constructor to copy the const char to new char.
Competitor::Competitor(char* inputName, int charlen, int inputLane)
{
name = new char[charlen + 1];
memcpy(name , inputName, charlen );
name [charlen] = '\0';
lane = inputLane;
}
I have included both my definition of the Question class and its implementation, the first is a header file and the second a cpp file.
I put comments in to show where the problem is. For some reason under the constructor I can cout the questionText just fine but when I try to do this under the getQuestionText function it just outputs an empty string? Any help would be most appreciated!! Thanks!
#include <string>
#include <vector>
#include <iostream>
using namespace std;
#ifndef QUESTION_H
#define QUESTION_H
class Question{
public:
Question(int thePointValue, int theChapterNumber, \
string theQuestionText);
int getPointValue() const;
int getChapterNumber() const;
string getQuestionText() const;
virtual void writeQuestion(ostream& outfile) const;
virtual void writeKey(ostream& outfile) const;
private:
int pointValue;
int chapterNumber;
string questionText;
void writePointValue(ostream& outfile) const;
};
#endif
#include "Question.h"
Question::Question(int thePointValue, int theChapterNumber, \
string theQuestionText)
{
pointValue = thePointValue;
chapterNumber = theChapterNumber;
questionText = theQuestionText;
//HERE THIS WORKS PERFECTLY
cout << questionText << endl;
}
int Question::getPointValue() const
{
return pointValue;
}
int Question::getChapterNumber() const
{
return chapterNumber;
}
string Question::getQuestionText() const
{
//THIS IS THE PROBLEM. HERE IT OUPUTS AN EMPTY STRING NO MATTER WHAT!
cout << questionText << endl;
return questionText;
}
void Question::writeQuestion(ostream& outfile) const
{
writePointValue(outfile);
outfile << questionText << endl;
}
void Question::writeKey(ostream& outfile) const
{
writePointValue(outfile);
outfile << endl;
}
void Question::writePointValue(ostream& outfile) const
{
string pt_noun;
if (pointValue == 1)
pt_noun = "point";
else
pt_noun = "points";
outfile << "(" << pointValue << " " << pt_noun << ") ";
}
vector<Question *> QuestionsList(string filename, int min, int max)
{
vector<Question *> QuestionList;
string line;
vector<string> text;
ifstream in_file;
in_file.open(filename.c_str());
while (getline(in_file, line))
{
text.push_back(line);
}
string type;
for(int i = 0; i < text.size(); i ++)
{
int num = text[i].find('#');
type = text[i].substr(0, num);
if (type == "multiple")
{
MultipleChoiceQuestion myq = matchup(text[i]);
MultipleChoiceQuestion* myptr = &myq;
if (myq.getChapterNumber() >= min && myq.getChapterNumber() <= max)
{
QuestionList.push_back(myptr);
}
}
if (type == "short")
{
ShortAnswerQuestion myq = SAmatchup(text[i]);
ShortAnswerQuestion* myptr = &myq;
if (myq.getChapterNumber() >= min && myq.getChapterNumber() <= max)
{
QuestionList.push_back(myptr);
}
}
if (type == "long")
{
LongAnswerQuestion myq = LAmatchup(text[i]);
LongAnswerQuestion* myptr = &myq;
if (myq.getChapterNumber() >= min && myq.getChapterNumber() <= max)
{
QuestionList.push_back(myptr);
}
}
if (type == "code")
{
CodeQuestion myq = CODEmatchup(text[i]);
CodeQuestion* myptr = &myq;
if (myq.getChapterNumber() >= min && myq.getChapterNumber() <= max)
{
QuestionList.push_back(myptr);
}
}
cout << QuestionList[QuestionList.size()-1]->getQuestionText() << endl;
}
for (int i = 0; i < QuestionList.size(); i ++)
{
int numm = QuestionList.size();
cout << QuestionList[numm-1]->getQuestionText() << endl;
}
return QuestionList;
}
then when i call this in main the code breaks
vector<Question *> list = QuestionsList(pool_filename, min_chapter, max_chapter);
cout << list[0]->getQuestionText() << endl;
You are declaring, multiple times in your code, local objects and storing their pointer into the QuestionList vector (returned by the function) which, at the end of the function block, will contains dangling pointers.
MultipleChoiceQuestion myq = matchup(text[i]); // < local object
MultipleChoiceQuestion* myptr = &myq; // < pointer to local object
QuestionList.push_back(myptr); // < push back into vector
At this point you can either use dynamic memory allocation (I suggest you not to do that unless you are absolutely forced, and even in that case use one of the smart pointers provided by the standard library) or store the objects directly inside the vector.