I'm doing a phone registry and in it you need to be able to add, remove and show the phones on stock. I've made it possible to add in phones but whenever I add let's say 3 phones and remove the second one then both the third and second phone are deleted and I don't understand why.
This is my CellPhoneHandler.h file:
#ifndef CELLPHONEHANDLER_H
#define CELLPHONEHANDLER_H
#include "CellPhone.h"
class CellPhoneHandler
{
private:
CellPhone **phone;
int nrOfPhones;
int priceOfPhone;
int stockCapacity;
int nrOfPhonesInArr;
public:
CellPhoneHandler();
~CellPhoneHandler();
void addPhone(string brand, int nrOf, int price);
bool removePhoneFromStock(string name, int nrOf);
int getNrOfPhones() const;
int getNrOfPhonesInArr() const;
int getPrice() const;
void getPhonesAsString(string arr[], int nrOf, int priceOfPhone) const;
};
#endif // !CELLPHONEHANDLER_H
this is my CellPhoneHandler.cpp file.
#include "CellPhoneHandler.h"
CellPhoneHandler::CellPhoneHandler()
{
this->phone = nullptr;
this->nrOfPhones = 0;
this->priceOfPhone = 0;
this->stockCapacity = 0;
this->nrOfPhonesInArr = 0;
}
CellPhoneHandler::~CellPhoneHandler()
{
for (int i = 0; i < nrOfPhonesInArr; i++)
{
delete phone[i];
}
delete[] phone;
}
void CellPhoneHandler::addPhone(string brand, int nrOf, int price)
{
if (stockCapacity < nrOfPhonesInArr + 1)
{
CellPhone ** tempArray = new CellPhone*[this->nrOfPhonesInArr + 1];
for (int i = 0; i < nrOfPhonesInArr; i++)
{
tempArray[i] = this->phone[i];
}
delete[] this->phone;
this->phone = tempArray;
this->phone[this->nrOfPhonesInArr] = new CellPhone(brand, nrOf, price);
this->nrOfPhonesInArr++;
//this->stockCapacity++;
}
}
bool CellPhoneHandler::removePhoneFromStock(string name, int nrOf)
{
bool phoneFound = false;
int index = nrOfPhonesInArr;
for (int i = 0; i < nrOfPhonesInArr; i++)
{
if (this->phone[i]->getBrand() == name);
{
index = i;
phoneFound = true;
this->nrOfPhonesInArr--;
}
}
if (phoneFound == true)
{
delete phone[index];
phone[index] = nullptr;
}
return phoneFound;
}
int CellPhoneHandler::getNrOfPhones() const
{
return this->nrOfPhones;
}
int CellPhoneHandler::getNrOfPhonesInArr() const
{
return this->nrOfPhonesInArr;
}
int CellPhoneHandler::getPrice() const
{
return this->priceOfPhone;
}
void CellPhoneHandler::getPhonesAsString(string arr[], int nrOf, int priceOfPhone) const
{
for (int i = 0; i < nrOf; i++)
{
arr[i] = this->phone[i]->toString();
}
}
The problem is caused by an unwanted ;.
if (this->phone[i]->getBrand() == name); // if ends here.
The next block is executed for all items.
{
index = i;
phoneFound = true;
this->nrOfPhonesInArr--;
}
Remove that ; in the if line.
Related
Inventory::Inventory()
{
this->cap = 10;
this->nrOfItems = 0;
this->itemArr = new Item* [cap]();
}
Inventory::~Inventory()
{
for (size_t i = 0; i < this->nrOfItems; i++)
{
delete this->itemArr[i];
}
delete[] this->itemArr;
}
void Inventory::expand()
{
this->cap *= 2;
Item **tempArr = new Item*[this->cap]();
for (size_t i = 0; i < this->nrOfItems, i++;)
{
tempArr[i] = new Item(*this->itemArr[i]);
}
for (size_t i = 0; i < this->nrOfItems, i++;)
{
delete this->itemArr[i];
}
delete[] this->itemArr;
this->itemArr = tempArr;
this->initialize(this->nrOfItems);
}
void Inventory::initialize(const int from)
{
for (size_t i = from; i < cap, i++;)
{
this->itemArr[i] = nullptr;
}
}
void Inventory::addItem(const Item& item)
{
if (this->nrOfItems >= this->cap)
{
expand();
}
this->itemArr[this->nrOfItems++] = new Item(item);
}
void Inventory::removeItem(int index)
{
}
Above is my code from Inventory.cpp and the issue is that I keep getting an Unhandled Exception from the line that has:
this->itemArr[i] = nullptr;
I have no idea where I'm messing up in the code. Below I am posting from Inventory.h:
class Inventory
{
private:
int cap;
int nrOfItems;
Item **itemArr;
void expand();
void initialize(const int from);
public:
Inventory();
~Inventory();
void addItem(const Item &item);
void removeItem(int index);
inline void debugPrint() const
{
for (size_t i = 0; i < this->nrOfItems; i++)
{
std::cout << this->itemArr[i]->debugPrint() << std::endl;
}
}
};
This is where itemArr should be housed but for some reason, it is not pulling. I am new to coding so I don't know all of the tips and tricks involved with it.
In the loop i < cap, i++;, you will first check if i is in bounds, and then increase it by one before the loop body executes. Thus if i=cap-1 the check will pass, i will become cap and you're out of bounds.
Instead write (size_t i = from; i < cap;i++), so that the increment of i is executed after the loop body.
A see several problems with your code:
In Inventory::expand(), since you are working with an array of pointers (why not an array of objects?), there is no need to make clones of the existing Item objects to the new array, just copy the existing pointers as-is. You are just expanding the array to fit more pointers, so the clones are wasted overhead. Not a fatal issue, but it is something you should be aware of.
In both Inventory::initialize() and Inventory::expand(), your loops are setup incorrectly. You are performing the i++ in the wrong place. Given this definition of a loop:
for ( <init-statement> <condition> ; <iteration_expression> )
You are performing the i++ as part of the <condition>, not the <iteration_expression>. A simply typo caused by you using the comma operator instead of ;, but an important typo nonetheless.
Inventory is violating the Rule of 3/5/0, by not implementing copy/move constructors and copy.move assignment operators.
With that said, try this instead:
class Inventory
{
private:
size_t cap;
size_t nrOfItems;
Item **itemArr;
void expand();
public:
Inventory();
Inventory(const Inventory &src);
Inventory(Inventory &&src);
~Inventory();
Inventory& operator=(Inventory rhs);
void addItem(const Item &item);
void removeItem(size_t index);
inline void debugPrint() const
{
for (size_t i = 0; i < nrOfItems; ++i)
{
std::cout << itemArr[i]->debugPrint() << std::endl;
}
}
};
Inventory::Inventory()
{
cap = 10;
nrOfItems = 0;
itemArr = new Item*[cap]();
}
Inventory::Inventory(const Inventory &src)
{
cap = src.cap;
nrOfItems = src.nrOfItems;
itemArr = new Item*[cap]();
for(size_t i = 0; i < nrOfItems; ++i)
{
itemArr[i] = new Item(*(src.itemArr[i]));
}
}
Inventory::Inventory(Inventory &&src)
{
cap = src.cap; src.cap = 0;
nrOfItems = src.nrOfItems; src.nrOfItems = 0;
itemArr = src.itemArr; src.itemArr = nullptr;
}
Inventory::~Inventory()
{
for (size_t i = 0; i < nrOfItems; ++i)
{
delete itemArr[i];
}
delete[] itemArr;
}
Inventory& Inventory::operator=(Inventory rhs)
{
Inventory temp(std::move(rhs));
std::swap(cap, temp.cap);
std::swap(nrOfItems, temp.nrOfItems);
std::swap(itemArr, temp.itemArr);
return *this;
}
void Inventory::expand()
{
size_t newCap = cap * 2;
Item **tempArr = new Item*[newCap]();
for (size_t i = 0; i < nrOfItems; ++i)
{
tempArr[i] = itemArr[i];
}
delete[] itemArr;
itemArr = tempArr;
cap = newCap;
}
void Inventory::addItem(const Item& item)
{
if (nrOfItems >= cap)
{
expand();
}
itemArr[nrOfItems] = new Item(item);
++nrOfItems;
}
void Inventory::removeItem(size_t index)
{
if (index < nrOfItems)
{
Item *item = itemArr[index];
for(size_t i = index + 1; i < nrOfItems; ++i)
{
itemArr[i-1] = itemArr[i];
}
--nrOfItems;
itemArr[nrOfItems] = nullptr;
delete item;
}
}
That being said, you really should be using std::vector instead, let it handle these details for you, eg:
#include <vector>
class Inventory
{
private:
std::vector<Item> itemVec;
public:
Inventory();
void addItem(const Item &item);
void removeItem(size_t index);
inline void debugPrint() const
{
for (Item &item : items)
{
std::cout << item.debugPrint() << std::endl;
}
}
};
Inventory::Inventory()
{
itemVec.reserve(10);
}
void Inventory::addItem(const Item& item)
{
itemVec.emplace_back(item);
}
void Inventory::removeItem(size_t index)
{
if (index < itemVec.size())
{
itemVec.erase(itemVec.begin() + index);
}
}
See how much simpler that is? :)
As the title reads, I get memory leakage when I run my program. However, I think the problem is that I do not tell the destructor to free all of the memory when the program is done. But the problem is that the program crashes when I try to put my freeMemory() function in the destructor. The compiler says that the function getString() in my base class could not read from string. I wonder if you can see the problem, because I surely can not... And to not get too many rows of code, I will only post the functions which could be the possible source of leakage. Handler.h:
class Handler {
private:
Competitor* *person;
int capacity;
int nrOfCompetitors;
void expand();
void initiate(int start) const;
int find(string name) const;
void freeMemory();
public:
Handler(int capacity = 3);
Handler(const Handler & origObj);
virtual ~Handler();
Handler operator=(const Handler & origObj);
bool addExerciser(string name, string gender, int age);
bool addProffs(string name, string gender, string compound, int nrOfSeasons);
void getCompetitors(string arr[]) const;
int getNrOfCompetitors() const;
void getProffs(string arr[]) const;
int getNrOfProffs() const;
void getExercisers(string arr[]) const;
int getNrOfExercisers() const;
bool removeCompetitor(string name);
bool changeNrOfSeasons(string name, int newNrOfSeasons) const;
void sortCompetitors();
};
Handler.cpp (just the relevant functions):
void Handler::expand() {
this->capacity += 5;
Competitor* *tmp = new Competitor*[capacity];
for (int i = 0; i < this->nrOfCompetitors; i++) {
tmp[i] = this->person[i];
}
delete[] this->person;
this->person = tmp;
this->initiate(nrOfCompetitors);
}
void Handler::initiate(int start) const {
for (int i = start; i < this->capacity; i++) {
person[i] = nullptr;
}
}
void Handler::freeMemory() {
for (int i = 0; i < nrOfCompetitors; i++) {
delete person[i];
}
delete[] person;
}
Handler::Handler(int capacity) {
this->capacity = capacity;
this->nrOfCompetitors = 0;
this->person = new Competitor*[this->capacity];
initiate(0);
}
Handler::Handler(const Handler & origObj) {
this->capacity = origObj.capacity;
this->nrOfCompetitors = origObj.nrOfCompetitors;
this->person = new Competitor*[origObj.capacity];
for (int i = 0; i < this->capacity; i++) {
person[i] = origObj.person[i];
}
initiate(nrOfCompetitors);
}
Handler::~Handler() {
//freeMemory();
delete[] person;
}
Handler Handler::operator=(const Handler & origObj) {
if (this != &origObj) {
freeMemory();
this->capacity = origObj.capacity;
this->nrOfCompetitors = origObj.nrOfCompetitors;
this->person = new Competitor*[origObj.capacity];
for (int i = 0; i < this->capacity; i++) {
person[i] = origObj.person[i];
}
initiate(nrOfCompetitors);
}
return *this;
}
bool Handler::removeCompetitor(string name) {
bool removed = false;
int found = find(name);
if (found != -1) {
delete person[found];
for (int i = found; i < nrOfCompetitors; i++) {
person[found] = person[found + 1];
}
delete person[nrOfCompetitors];
nrOfCompetitors -= 1;
removed = true;
}
return removed;
}
void Handler::sortCompetitors() {
Competitor* tmp;
bool swap;
do {
swap = false;
for (int i = 0; i < nrOfCompetitors - 1; i++) {
if (person[i]->getName() > person[i + 1]->getName()) {
tmp = person[i];
person[i] = person[i + 1];
person[i + 1] = tmp;
swap = true;
}
}
} while (swap);
}
EDIT:
When the program crashes while I am trying to use the freeMemory() function in my destructor, the compiler says that the getString() function in my base class could not read character from string.
Competitor.h (base class):
string getString() const;
virtual string getSpecificString() const = 0;
Competitor.cpp:
string Deltagare::getString() const {
return "Name: " + this->name + "\nGender: " + this->gender + "\n" + this->getSpecificString();
}
Exerciser.h (sub class):
virtual string getSpecificString() const;
Exerciser.cpp
string Exerciser::getSpecificString() const {
return "Age: " + to_string(this->age);
}
Solved! Solution:
The problems were in the destructor, assignment operator and the copy-constructor, but they are fixed now. I used a clone method because I was not able to type person[i] = new Competitor[origObj.person[i]] because of the fact that the Competitor class is an abstract class.
Competitor.h:
virtual Competitor* clone() const = 0;
Exerciser.h:
Exerciser* clone() const;
Exerciser.cpp:
Exerciser * Exerciser::clone() const {
return new Exerciser(*this);
}
Edit in the copy-constructor and the assignment operator:
this->person = new Competitor*[origObj.capacity];
for (int i = 0; i < origObj.nrOfCompetitors; i++) {
person[i] = origObj.person[i]->clone();
}
Edit in the destructor:
Handler::~Handler() {
freeMemory();
}
Header File
#pragma once
#ifndef PLAYERDATA_H
#define PLAYERDATA_H
#include <string>
using namespace std;
class PlayerData
{
private:
Private member variables
static const int SIZE = 10;
string name; //Player Name
int jnum; //Jersey Number
string team; //Player Team
string position; //Player position
int points[SIZE]; // Array of points for last 10 games
int rebounds[SIZE]; // Array of rebounds for last 10 games
int assist[SIZE]; // Array of assist for last 10 games
double ap = 0.0; // Average number of points
double ar = 0.0; // Average number of rebounds
double aa = 0.0; // Average number of assits
public:
Constructor to initialize data if no data is passed
// Constructor #1
PlayerData()
{
jnum = 0;
name = "";
team = "";
position = "";
for (int i = 0; i < SIZE; i++)
{
points[SIZE] = 0;
rebounds[SIZE] = 0;
assist[SIZE] = 0;
}
}
// Constructor #2
Constructor to accept parameter. Collects jersey number, name, team name, position, array of points for last 10 games, array of rebounds for last 10 games, array of assist for last 10 games.
PlayerData( int jn, string n, string t, string pos, int p[SIZE], int r[SIZE], int a[SIZE])
{
jnum = jn;
name = n;
team = t;
position = pos;
for (int i = 0; i < SIZE; i++)
{
points[SIZE] = p[SIZE];
rebounds[SIZE] = r[SIZE];
assist[SIZE] = a[SIZE];
}
}
// Mutator Function
void setJersery(int jn)
{
jnum = jn;
}
void setName(string n)
{
name = n;
}
void setTeam(string t)
{
team = t;
}
void setPosition(string pos)
{
position = pos;
}
void setPoints(int p[SIZE])
{
for (int z = 0; z < SIZE; z++)
{
points[SIZE] = p[SIZE];
}
}
void setRebounds(int r[SIZE])
{
for (int z = 0; z < SIZE; z++)
{
rebounds[SIZE] = r[SIZE];
}
}
void setAssist(int a[SIZE])
{
for (int z = 0; z < SIZE; z++)
{
assist[SIZE] = a[SIZE];
}
}
// Acessor methods
string getName()
{
return name;
}
int getJersey()
{
return jnum;
}
string getTeam()
{
return team;
}
string getPosition()
{
return position;
}
int getPoints()
{
return points[SIZE];
}
int getRebounds()
{
return rebounds[SIZE];
}
int getAssist()
{
return assist[SIZE];
}
/*
double averageP(int p[], const int SIZE);
double averageR(int r[], const int SIZE);
double averageA(int a[], const int SIZE);
*/
void averageP(int p[], const int SIZE);
void averageR(int r[], const int SIZE);
void averageA(int a[], const int SIZE);
double getAP()
{
return ap;
}
double getAR()
{
return ar;
}
double getAA()
{
return aa;
}
};
#endif // !PLAYERDATA_H
Calculates average points,rebounds, assist from the arrays that were passed.
PlayerData.cpp
#include "PlayerData.h"
using namespace std;
// Calculate average points
void PlayerData::averageP(int p[], const int s)
{
for (int c = 0; c < s; c++)
{
ap += p[c];
}
ap /= s;
//return ap;
}
// Calculate average rebounds
void PlayerData::averageR(int r[], const int s)
{
for (int c = 0; c < s; c++)
{
ar += r[c];
}
ar /= s;
//return ar;
}
// Calculate average assist
void PlayerData::averageA(int a[], const int s)
{
for (int c = 0; c < s; c++)
{
aa += a[c];
}
aa /= s;
//return aa;
}
Main
#include <iostream>
#include <iomanip>
#include "PlayerData.h"
using namespace std;
int main()
{
const int SIZE = 10;
int points[SIZE] = { 10,10,10,10,10,10,10,10,10,10 };
int assist[SIZE] = { 2,2,2,2,2,2,2,2,2,2, };
int rebounds[SIZE] = { 3,3,3,3,3,3,3,3,3,3 };
Here is where the problem occurs. The compiler marks under the 6 as if the int is not part of the arguments for the constructor. I'm not sure why it is doing this. I receive this message "No instance of constructor "PlayerData::PlayerData" matches the argument list."
PlayerData player1(6, "Jimmy Butler", "Chicago Bulls", "Forward", points[SIZE], rebounds[SIZE], assist[SIZE]);
getchar();
return 0;
}
Constructor requires an array of integers and in main you are passing a pointer to int. If you want to pass the whole array you should delete the [SIZE] because that is translated as (if SIZE is 5 for example) "give me the 6th element of 5 element array".
Try calling it like this.
PlayerData player1(6, "Jimmy Butler", "Chicago Bulls", "Forward", points, rebounds, assist);
I find myself in a difficult situation. I have a program which is supposed to delete any memory that is dynamically allocated, but whenever I try to call the relevant methods, it comes up with a memory heap corruption.
It seems to work when I don't call the methods, but then I've probably caused a ton of memory leaks. Would anyone have any idea what is going on?
The code is below:
CSVFile.h:
#pragma once
class InputPattern;
class OutputPattern;
class CSVFile
{
private:
const int NAME_MAX = 100;
char* name;
char** buffer;
bool loadedFlag;
int patternCount;
InputPattern** inputs;
OutputPattern** outputs;
void setLoadedFlagTrue();
void setLoadedFlagFalse();
public:
CSVFile();
~CSVFile();
CSVFile(const char*);
void setName(const char*);
char* getFilename(char*, int);
bool getLoadedFlag();
int loadFile();
InputPattern* getInputPattern(int);
OutputPattern* getOutputPattern(int);
void addInputPattern(InputPattern*);
void addOutputPattern(OutputPattern*);
void deleteInputPattern();
void deleteOutputPattern();
void printMetaData();
void printPatterns();
void deleteBuffer();
};
CSVFile.cpp:
#include "CSVFile.h"
#include "InputPattern.h"
#include "OutputPattern.h"
#include <stdio.h>
#include <string.h>
void CSVFile::setLoadedFlagTrue()
{
loadedFlag = true;
}
void CSVFile::setLoadedFlagFalse()
{
loadedFlag = false;
}
CSVFile::CSVFile()
{
name = NULL;
buffer = NULL;
inputs = NULL;
outputs = NULL;
patternCount = 0;
inputs = new InputPattern*[10];
outputs = new OutputPattern*[10];
buffer = new char*[4];
int i;
for (i = 0; i < 10; i++)
{
inputs[i] = new InputPattern();
outputs[i] = new OutputPattern();
buffer[i] = new char[NAME_MAX];
}
}
CSVFile::~CSVFile()
{
delete name;
name = NULL;
}
CSVFile::CSVFile(const char * filename)
{
name = NULL;
buffer = NULL;
inputs = NULL;
outputs = NULL;
patternCount = 0;
inputs = new InputPattern*[10];
outputs = new OutputPattern*[10];
int i;
for (i = 0; i < 10; i++)
{
inputs[i] = new InputPattern();
outputs[i] = new OutputPattern();
}
name = new char[NAME_MAX];
strcpy(name, filename);
}
void CSVFile::setName(const char * filename)
{
name = new char[NAME_MAX];
strcpy(name, filename);
}
char* CSVFile::getFilename(char * outBuff, int outBuffSize)
{
outBuff = new char[outBuffSize + 1];
strncpy(outBuff, name, outBuffSize);
return outBuff;
}
bool CSVFile::getLoadedFlag()
{
if (name == NULL)
{
setLoadedFlagFalse();
return loadedFlag;
}
if (patternCount == 10)
setLoadedFlagTrue();
else
setLoadedFlagFalse();
return loadedFlag;
}
int CSVFile::loadFile()
{
FILE* f;
if ((f = fopen(name, "r")) == NULL)
{
printf("File failed to open\n");
return 0;
}
for (patternCount = 0; patternCount < 4; patternCount++)
{
fgets(buffer[patternCount], 100, f);
}
patternCount = 0;
/*ask about input interaction; potentially remove these variables afterwards*/
float tIn, rIn, gIn, bIn, tOut, oOut;
/*might change this to make it more flexible*/
while (patternCount < 10)
{
fscanf(f, "%f,%f,%f,%f,%f,%f", &tIn, &rIn, &gIn, &bIn, &tOut, &oOut);
printf("%f,%f,%f,%f,%f,%f\n", tIn, rIn, gIn, bIn, tOut, oOut);
inputs[patternCount]->setT(tIn);
inputs[patternCount]->setR(rIn);
inputs[patternCount]->setG(gIn);
inputs[patternCount]->setB(bIn);
outputs[patternCount]->setT(tOut);
outputs[patternCount]->setO(oOut);
patternCount++;
}
fclose(f);
return patternCount;
}
InputPattern * CSVFile::getInputPattern(int index)
{
if (index >= 0 && index < 10)
return inputs[index];
else
return 0;
}
OutputPattern * CSVFile::getOutputPattern(int index)
{
if (index >= 0 && index < 10)
return outputs[index];
else
return 0;
}
void CSVFile::addInputPattern(InputPattern * in)
{
inputs[patternCount] = in;
patternCount++;
}
void CSVFile::addOutputPattern(OutputPattern * out)
{
outputs[patternCount] = out;
patternCount++;
}
void CSVFile::deleteInputPattern()
{
int i;
for (i = 0; i < patternCount; i++)
{
delete inputs[i];
}
delete inputs;
inputs = NULL;
}
void CSVFile::deleteOutputPattern()
{
int i;
for (i = 0; i < patternCount; i++)
{
delete outputs[i];
}
delete outputs;
outputs = NULL;
}
void CSVFile::printMetaData()
{
int i;
for (i = 0; i < 4; i++)
{
printf("%s", buffer[i]);
}
}
void CSVFile::printPatterns()
{
/*to be completed*/
int i;
for (i = 0; i < patternCount; i++)
{
printf("Class number %d\n", i + 1);
printf("T in = %f\n", inputs[i]->getT());
printf("R in = %f\n", inputs[i]->getR());
printf("G in = %f\n", inputs[i]->getG());
printf("B in = %f\n", inputs[i]->getB());
printf("T out = %f\n", outputs[i]->getT());
printf("O out = %f\n", outputs[i]->getO());
}
}
void CSVFile::deleteBuffer()
{
int i;
for (i = 0; i < patternCount; i++)
{
delete buffer[i];
}
delete buffer;
buffer = NULL;
}
TestHarness.cpp sample (this is executed in the main function)
bool TestHarness::testCSVFileSetFilepath() /*this works fine*/
{
bool testResult = false;
CSVFile* test = NULL;
test = new CSVFile();
char *testName = NULL;
test->setName("test.txt");
testName = test->getFilename(testName, 10);
if (strcmp("test.txt", testName) == 0)
testResult = true;
delete test;
delete testName;
test = NULL;
testName = NULL;
return testResult;
}
...........................
bool TestHarness::testCSVFileLoadFile() /*this causes the corruption*/
{
bool testResult = false;
CSVFile* test = NULL;
test = new CSVFile();
test->setName("C:/Users/user/Documents/AssignmentsSem2/ExampleFile.csv");
if (test->loadFile() == 10)
testResult = true;
test->deleteInputPattern();
test->deleteOutputPattern();
test->deleteBuffer(); /*these three above methods are the ones I'm talking about*/
delete test;
test = NULL;
return testResult;
}
You can check for memory leaks with
#define _CRTDBG_MAP_ALLOC
#include<crtdbg.h>
struct AtExit
{
~AtExit()
{
_CrtDumpMemoryLeaks();
}
}doAtExit;
just outside the main method.
This runs whenever your program ends. All it really does is display whether you have a memory leak or not. Doesn't help with actually finding them.
You might need Visual Studio for this.
This is how it looks when a memory leak is found
this my Library.h file, before the Library used to do All the dirty work: in term of manipulating the arrays and stuff, but now I am trying to make the Library the middle man that just invoke the call that has to do with any array manipulations. My problem is I am trying to have one instance of Patron array, that would hold all the patrons in the Library.
#ifndef LIBRARY_H
#define LIBRARY_H
#include <string>
#include "types.h"
#include "Book.h"
#include "Patron.h"
#include "PatronArray.h"
//class PatronArray
class Library
{
public:
Library();
~Library();
void init();
int addBook(Book*);
int addPatron(Patron*);
int remPatron(int);
int findBook(int, Book**, int*);
int findPatron(string, string, Patron**, int*);
int getMaxCollIndex();
int getMaxPatronsIndex();
Book* getBook(int);
Patron* getPatron(int);
private:
Book* collection[MAX_COLL_SIZE];
PatronArray* patrons;
int maxCollIndex;
int maxPatronsIndex;
};
#endif
This is my Library.cc file
#include "Library.h"
Library::Library()
: maxCollIndex(0)
{
patrons = new PatronArray;
for (int i=0; i<MAX_COLL_SIZE; ++i) {
collection[i] = 0;
}
}
Library::~Library()
{
delete patrons;
for (int i=0; i<maxCollIndex; ++i)
delete collection[i];
}
int Library::getMaxCollIndex() { return maxCollIndex; }
int Library::getMaxPatronsIndex()
{
return patrons->getMaxPatronsIndex();
}
Book* Library::getBook(int index)
{
if (index < 0 || index >= maxCollIndex)
return 0;
return collection[index];
}
Patron* Library::getPatron(int index)
{
return patrons->getPatron(index);
}
void Library::init()
{
Book* newBook;
Patron* newPatron;
newBook = new Book("Ender's Game", "Orson Scott Card", 1985);
addBook(newBook);
newBook = new Book("Dune", "Frank Herbert", 1965);
newBook->setStatus(LOST);
addBook(newBook);
newBook = new Book("Foundation", "Isaac Asimov", 1951);
addBook(newBook);
newBook = new Book("Hitch Hiker's Guide to the Galaxy", "Douglas Adams", 1979);
addBook(newBook);
newPatron = new Patron("Jack", "Shephard");
addPatron(newPatron);
}
int Library::addBook(Book* book)
{
if (maxCollIndex >= MAX_COLL_SIZE - 1) {
return C_NOK;
}
collection[maxCollIndex++] = book;
return C_OK;
}
int Library::addPatron(Patron* patron)
{
// the lbrary is the middle ma that invokesthe calls
//return patronArray->addPatron(patron);
return patrons->addPatron(patron);
}
int Library::remPatron(int index)
{
return patrons->remPatron(index);
}
int Library::findPatron(string fn, string ln, Patron** patron, int* index)
{
return patrons->findPatron(fn,ln,patron,index);
}
int Library::findBook(int id, Book** book, int* index)
{
for (int i=0; i<maxCollIndex; ++i) {
if (collection[i] == 0)
continue;
if (collection[i]->getId() == id) {
*book = collection[i];
*index = i;
return C_OK;
}
}
*book = 0;
*index = -1;
return C_NOK;
}
This is my PatronArray.h that holds all the Patrons registered within the Library.
#ifndef PATRONARRAY_H
#define PATRONARRAY_H
#include "Patron.h"
#include "Book.h"
#include "types.h"
//class Patron;
class PatronArray
{
public:
PatronArray();
~PatronArray();
int addPatron(Patron*);
int remPatron(int);
int findPatron(string, string, Patron**, int*);
int getMaxPatronsIndex();
Patron* getPatron(int);
private:
Patron* patrons[MAX_COLL_SIZE];
int maxPatronsIndex;
};
#endif
and this is the PatronArray.cc file and please, I know there is better way of doing this by doing templating which I currently dont understand yet plus this way helps me understand the whole object oriented style.
#include<iostream>
#include<string>
#include "PatronArray.h"
/*
* Default constructor: recheck this later
*/
PatronArray::PatronArray()
:maxPatronsIndex(0)
{
for (int i = 0; i < MAX_COLL_SIZE; ++i) {
patrons[i] = 0;
}
}
/*
* Destructor: recheck this later
*/
PatronArray::~PatronArray()
{
for (int i = 0; i < maxPatronsIndex; ++i)
delete patrons[i];
}
//get the maxindex
int PatronArray::getMaxPatronsIndex() { return maxPatronsIndex; }
/*
* Adds the given Patron to the given patrons Array
*/
int PatronArray::addPatron(Patron* patron)
{
if (maxPatronsIndex >= MAX_COLL_SIZE - 1) {
return C_NOK;
}
patrons[maxPatronsIndex++] = patron;
return C_OK;
}
/*
* Used for removing a patron in the patrons array
*/
int PatronArray::remPatron(int index)
{
if (index < 0 || index >= maxPatronsIndex)
return C_NOK;
delete patrons[index];
patrons[index] = 0;
return C_OK;
}
/*
* Searches for the patron; if found, sets the contents of the second
* parameter to that patron pointer, sets the contents of the third parameter to
* its index in the collection, and returns C_OK; if not found, sets the
* contents of the second parameter to zero, the theird to -1, and returns C_NOK
*/
int PatronArray::findPatron( string fn, string ln, Patron** patron, int* index)
{
for (int i = 0; i < maxPatronsIndex; ++i) {
if (patrons[i] == 0)
continue;
if (patrons[i]->getFname() == fn && patrons[i]->getLname() == ln) {
*patron = patrons[i];
*index = i;
return C_OK;
}
}
*patron = 0;
*index = -1;
return C_NOK;
}
Patron* PatronArray::getPatron(int index)
{
if (index < 0 || index >= maxPatronsIndex)
return 0;
return patrons[index];
}
I forgot to link my PatronArray.cc to Library.cc in my makefile, thank you Jack!