I've been writing a program to simulate a paging system for an assignment. The program almost works but for some reason I'm getting a segfault when I try to delete my dynamically allocated array of frames.
Here's the algorithm code:
int main(int argc, char* argv[])
{
// Initialize page count
PageCount = 0;
// Validate input
ValidateArgs(argc, argv);
// Load programs and trace from list file
Programs = LoadPrograms();
Trace = LoadTrace();
// Load main memory
MainMemory Memory = MainMemory(Programs);
// Run the Algorithm
Run(Memory);
// Print results
Print();
// Print the output to a file
PrintOutput();
return 0;
}
void Run(MainMemory memory)
{
int page, frame;
vector<int> replaceFrame;
for (long i = 0; i < Trace.size(); i++)
{
// Get page and frame
page = Programs[Trace[i].ProgramNum].GetPage(Trace[i].Word);
frame = memory.IsInMemory(page);
if (frame != -1)
{
// Access page
memory.Frames[frame].Access(i);
}
else
{
// Find page to replace
if (Algorithm == "clock")
{
replaceFrame = memory.FindClock();
}
else if (Algorithm == "lru")
{
replaceFrame = memory.FindLRU(i);
}
else
{
replaceFrame = memory.FindOldest(i);
}
// Replace page
memory.Frames[replaceFrame[0]].Replace(page, i);
// Replace with next contiguous page for prepaging
if (HowToPage)
{
memory.Frames[replaceFrame[1]].Replace(
Programs[Trace[i].ProgramNum].GetNextPage(
Trace[i].Word), i);
}
}
}
return;
}
Program and Request are both data types loaded from files. Request is just a data struct and Program has a vector of ints as one of its members.
At the end of this function, my MainMemory object (the one that contains the dynamically allocated array) calls its destructor which is in my MainMemory struct:
struct MainMemory
{
Frame* Frames;
int Number;
// Initializes an object of the MainMemory class
MainMemory(vector<Program> thePrograms)
{
Number = MemorySize / PageSize;
Frames = new Frame[Number];
int numberProgs = thePrograms.size(), counter = 0;
// Load main memory
for (int i = 0; i < numberProgs; i++)
{
for (int j = 0; j < thePrograms[i].Pages.size(); j++)
{
int page = thePrograms[i].Pages[j];
Frames[counter] = Frame(page, 0);
if (counter + 1 < Number)
{
counter++;
}
else
{
return;
}
}
}
}
// Initializes an object of the MainMemory class with another object
// of the MainMemory class
MainMemory(const MainMemory& cpy)
{
*this = cpy;
}
// Sets one MainMemory equal to another
MainMemory& operator=(const MainMemory& rhs)
{
Number = rhs.Number;
Frames = new Frame[Number];
for (int i = 0; i < Number; i++)
{
Frames[i] = Frame(rhs.Frames[i].Number,
rhs.Frames[i].TimeStamp, rhs.Frames[i].UseCount,
rhs.Frames[i].UseBit);
}
return *this;
}
// Deletes the MainMemory object
~MainMemory()
{
delete[] Frames;
Frames = NULL;
}
};
After some testing, I know that the Frames object has a memory address coming in to the destructor. Further, the code fails at the line indicated. The Frame struct doesn't have any dynamic elements so I didn't bother creating a destructor for it and instead let C++ do that for me.
struct Frame
{
int Number;
int TimeStamp;
int UseCount;
bool UseBit;
// Initializes an empty object of the Frame class
Frame() { }
// Initializes an object of the Frame class
Frame(int number, int time)
{
Number = number;
TimeStamp = time;
UseCount = time;
UseBit = false;
}
// Initializes an object of the Frame class
Frame(int number, int time, int count, bool use)
{
Number = number;
TimeStamp = time;
UseCount = count;
UseBit = use;
}
// Simulates a replacement of one frame with a page from secondary
void Replace(int page, int time)
{
Number = page;
TimeStamp = time;
UseCount = time;
UseBit = true;
PageFaults++;
return;
}
// Simulates a memory access to the frame
void Access(int time)
{
UseCount = time;
UseBit = true;
return;
}
};
But clearly, something's not working so I'm wondering where I screwed up.
Thanks for your help!
EDIT: I rechecked my constructor to see if it was shallow-copying anything. All elements in the copied element were in different locations from the original.
EDIT: I've been asked to add a SSCCE to this post:
int main(int argc, char* argv[])
{
PageCount = 0;
Programs = LoadPrograms();
Trace = LoadTrace();
MainMemory Memory(Programs);
cout << endl << "Running algorithm" << endl;
cout << endl << "Memory is at location " << &Memory << endl;
Test(Memory);
return 0;
}
void Test(MainMemory memory)
{
cout << endl << "Memory at location " << &memory << endl;
return;
}
This is the output I get:
Running algorithm
Memory is at location 0x7fff910a4eb0
Memory at location 0x7fff910a4ec0
In destructor
Frames in 0x7fff910a4ec0
Frames deleted
Destruction finished
It's copying correctly at least. Further, after changing the copy constructor, to explicitly copy the object (thanks Joachim Pileborg), it almost finishes executing Run(). However, there's still a problem with deallocating the memory. So, I think the issue is with the Run() function itself.
I would do this as a comment but the length of my reply precludes this. I can spot a number of oddities in the program that may or may not be related to the crash you are getting.
This is bad:
MainMemory(const MainMemory& cpy)
{
*this = cpy;
}
You would be creating multiple references to pointers, alloying multiple deletions of the same memory block.
Here, you do not delete Frames before assigning a new value to it.
MainMemory& operator=(const MainMemory& rhs)
{
Number = rhs.Number;
Frames = new Frame[Number];
for (int i = 0; i < Number; i++)
{
Frames[i] = Frame(rhs.Frames[i].Number,
rhs.Frames[i].TimeStamp, rhs.Frames[i].UseCount,
rhs.Frames[i].UseBit);
}
return *this;
}
I expect that this is causing the double deletions:
MainMemory Memory = MainMemory(Programs);
is then causing your problem (combined with the first issue above). Should be:
MainMemory Memory (Programs) ;
I would also question the constructor use for the Frames class.
Related
I've been beating my head against this one for awhile. In the deconstructor of my class, I have a for loop that is supposed to iterate through an array of objects and delete them. When I try though, I get a read access violation. The attached code is supposed to read info from two documents and use that to create Country objects.
#include "pch.h"
#include "CountryCatalogue.h"
#include "Country.h"
#include <iterator>
#include <map>
//imports for reading the files
#include <iostream>
#include <fstream>
CountryCatalogue::CountryCatalogue()
{
_maxSize = 10;
_curSize = 0;
_catalogue = new Country*[_maxSize];
}
CountryCatalogue::CountryCatalogue(std::string continentFileName, std::string countryFileName)
{
//block that opens the files and checks to make sure they can be read
//open up the files
std::ifstream inFile1;
std::ifstream inFile2;
//opening both text files and ensuring that the file is readable to the program
inFile1.open(continentFileName);
if (!inFile1) {
std::cout << "Unable to open file";
exit(1); // terminate with error
}
inFile2.open(countryFileName);
if (!inFile2) {
std::cout << "Unable to open file";
exit(1); // terminate with error
}
// read the continet file
// while there is still stuff to read in the file
std::string str;
while (!inFile1.eof())
{
std::string Country, Cont;
//reading lines from file and assigning to variables
std::getline(inFile1, Country);
std::getline(inFile1, Cont);
//mapping to variables read from file
_countryContinent.insert(std::pair<std::string, std::string>(Country, Cont));
_curSize++;
}
//closing file after use
inFile1.close();
//creating array
_catalogue = new Country*[_curSize+2];
//resetting size to zero for later itteration
_curSize = 0;
// read the country file
// while there is still stuff to read in the file
while (!inFile2.eof())
{
std::string name, POP, AREA;
int pop;
double area = 0.0;
std::getline(inFile2, name);
std::getline(inFile2, POP);
std::getline(inFile2, AREA);
if (!POP.empty() && POP[POP.length() - 1] == '\n') {
POP.erase(POP.length() - 1);
}
if (!AREA.empty() && AREA[AREA.length() - 1] == '\n') {
AREA.erase(AREA.length() - 1);
}
pop = std::stoi(POP);
area = std::stod(AREA);
//creating iterator to search through mapped values
std::map<std::string, std::string>::iterator it;
it = _countryContinent.find(name);
//creating empty string variable to store continent
std::string cont;
//using value found by iterator to make continent string
//ensuring value isn't the end valueof the map
if (it != _countryContinent.end()){
cont = it->second;
}
//std::cout << name << pop << area << cont << std::endl;
// add the country to the catalogue
addCountry(name, pop, area, cont);
}
}
CountryCatalogue::~CountryCatalogue() {
/*for (int i = 0; i < _curSize; i++){
delete _catalogue[i];
std::cout << "deleted" << i << std::endl;
}*/
delete[] _catalogue;
}
void CountryCatalogue::addCountry(std::string name, int pop, double area, std::string cont) {
//std::cout << name << pop << area << cont << std::endl;
//std::cout << _curSize << std::endl;
Country* toAdd = new Country(name, pop, area, cont);
if (_curSize == _maxSize) {
expandCapacity();
}
//adding country object to array
_catalogue[_curSize] = toAdd;
//adding to _curSize for next iteration
_curSize++;
}
void CountryCatalogue::printCountryCatalogue() {
std::string s;
/*for (int i = 0; i < _curSize; i++) {
s += _catalogue[i]->to_string() + "\n";
}*/
std::cout << _curSize << std::endl;
}
void CountryCatalogue::expandCapacity() {
//doubling array size
_maxSize = _maxSize * 2;
//creating pointer to new array of new size
Country** newCatalogue = new Country*[_maxSize];
//copying old array into new
for (int i = 0; i < _curSize; i++) {
newCatalogue[i] = _catalogue[i];
}
//deleting old array
delete[] _catalogue;
//making _catalogue point to newCatalogue
_catalogue = newCatalogue;
}
UPDATE:
What my code is supposed to do is get information from text files and create objects using that data. I am required to use an array instead of a vector. The code runs fine and I can create the country object. The issue is that I cannot add the created object to the _catalogue array, as I cannot delete it afterwards. When I attempt to iterate through the array, I receive a message saying Heap Corruption was detected.
Your problem is due to this line
_catalogue = new Country*[_curSize+2];
in the second constructor. You have forgotten to update _maxSize so you have a mismatch between _maxSize and the real allocated amount of memory.
Try:
_maxSize = _curSize+2;
_catalogue = new Country*[_maxSize];
You created _catalogue as a dynamic array.
To release the memory allocated for arrays of elements using new TYPE[SIZE] the syntax is:
delete[] _catalogue;
Loop is Needed for deleting memory allocated for Matrix elements. For example
int matrix = new int[rows][cols];
for (int i = 0; i < rows; ++i)
delete [] matrix[i];
The array is deleted row by row.
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...
I'm building a sparse matrix class that holds two arrays (row and column) of pointers to doubly linked lists (down and right). Sort of like this:
rows
c0123456789
o1
l2
u3
m4 A-->B-->
n5 | |
s6 | V
7 V D-->
8 C-->
9
Both arrays are initialized to have nullptr in every space until something is inserted in that place.
I have a function "readFile" that reads in objects from a text file and inserts them into this sparse matrix. For some reason, before this function returns, all of the data in it is fine, but after I return, I get random memory locations in my arrays. Here is main.cpp
#include <iostream>
#include <string>
#include <fstream>
#include "sparseMatrix.h"
using namespace std;
class basic
{
private:
int x, y;
string word;
basic *down;
basic *right;
public:
basic(int x, int y, string word)
{
this->x = x;
this->y = y;
this->word = word;
down = nullptr;
right = nullptr;
}
int getX()
{
return x;
}
int getY()
{
return y;
}
basic *getRight()
{
return right;
}
void setRight(basic *newRight)
{
right = newRight;
}
basic *getDown()
{
return down;
}
void setDown(basic *newDown)
{
down = newDown;
}
void print()
{
cout << "X: " << x << ", Y: " << y << ", word: " << word << ".\n";
}
};
sparseMatrix<basic> readFileBROKEN(string pathToFile);
sparseMatrix<basic> *readFile(string pathToFile);
int main()
{
cout << "Working:\n\n";
sparseMatrix<basic> *workingMatrix = readFile("C:/users/jmhjr/desktop/testdata.txt");
cout << "After returning, here are all the locations that are NOT nullptr:\n";
workingMatrix->printyArray();
cin.get();
cout << "Not working:\n\n";
sparseMatrix<basic> brokenMatrix = readFileBROKEN("C:/users/jmhjr/desktop/testdata.txt");
cout << "After returning, here are all the locations that are NOT nullptr:\n";
brokenMatrix.printyArray();
cin.get();
delete workingMatrix;
}
sparseMatrix<basic> readFileBROKEN(string pathToFile)
{
ifstream inputFile;
inputFile.open(pathToFile);
if (inputFile.fail())
{
cout << "Couldn't open " << pathToFile << "!\n";
exit(-1);
}
sparseMatrix<basic> matrix(100, 100);
while (!inputFile.eof())
{
int x, y;
string word;
inputFile >> x >> y >> word;
basic data(x, y, word);
matrix.insert(data);
}
cout << "Before returning, here are all the locations that are NOT nullptr:\n";
matrix.printyArray();
cout << "press ENTER to return\n";
cin.get();
return matrix;
}
sparseMatrix<basic> *readFile(string pathToFile)
{
ifstream inputFile;
inputFile.open(pathToFile);
if (inputFile.fail())
{
cout << "Couldn't open " << pathToFile << "!\n";
exit(-1);
}
sparseMatrix<basic> *matrix = new sparseMatrix<basic>(100, 100);
while (!inputFile.eof())
{
int x, y;
string word;
inputFile >> x >> y >> word;
basic data(x, y, word);
matrix->insert(data);
}
cout << "Before returning, here are all the locations that are NOT nullptr:\n";
matrix->printyArray();
cout << "press ENTER to return\n";
cin.get();
return matrix;
}
and here is sparseMatrix.h:
template <class dataType>
class sparseMatrix
{
private:
//The dimensions of the sparse matrix.
int width;
int height;
//Dynamic array of pointers to heads of linked lists.
dataType** xArray;
dataType** yArray;
public:
//Constructor. Sets everything in the two arrays to nullptr.
sparseMatrix(int height, int width)
{
this->width = width;
this->height = height;
xArray = new dataType*[width];
yArray = new dataType*[height];
for (int row = 0; row < height; row++)
{
this->yArray[row] = nullptr;
}
for (int col = 0; col < width; col++)
{
this->xArray[col] = nullptr;
}
}
//Deconstructor. First goes through the matrix and looks for every city it can find, and deletes
//all of those. Then when it's done, it deletes the two dynamic arrays.
~sparseMatrix()
{
dataType *currentdataType;
dataType *next;
for (int row = 0; row < height; row++)
{
currentdataType = yArray[row];
while (currentdataType != nullptr)
{
next = currentdataType->getRight();
delete currentdataType;
currentdataType = next;
}
}
delete [] yArray;
delete [] xArray;
}
//Creates a copy of the data we are passed, then creates links to this copy.
void insert(dataType data)
{
//Make sure the data is valid.
if (data.getX() < 0 || data.getX() >= width || data.getY() < 0 || data.getY() >= height)
{
std::cout << "That dataType doesn't fit into the sparse matrix!\n";
data.print();
std::cin.get();
}
else
{
//Copy the data we were passed.
dataType *newData = new dataType(data);
//Easy case. If nothing is in this row, set yArray[row] to the address of this data.
if (yArray[data.getY()] == nullptr)
{
yArray[data.getY()] = newData;
}
//Not so easy case. Move forward (right) until we find the right location, then set links.
else
{
dataType *current = yArray[data.getY()];
while (current->getRight() != nullptr)
{
current = current->getRight();
}
current->setRight(newData);
}
//Easy case. If nothing is in this col, set xArray[col] to the address of this data.
if (xArray[data.getX()] == nullptr)
{
xArray[data.getX()] = newData;
}
//Not so easy case. Move forward (down) until we find the right location, then set links.
else
{
dataType *current = xArray[data.getX()];
while (current->getDown() != nullptr)
{
current = current->getDown();
}
current->setDown(newData);
}
}
}
void printyArray()
{
for (int r = 0; r < height; r++)
{
if (yArray[r] != nullptr)
{
std::cout << r << ' ';
//yArray[r]->print();
}
}
}
};
readFile reads everything in from a file that looks like this:
0 0 hello
5 2 world
6 8 foo
9 5 bar
...
As expected, before returning, the only locations that are NOT nullptr are the ones that I have inserted into. (0, 2, 8 and 5). However when the function returns, EVERY SINGLE location in the array is not nullptr. I added a second function which returns a pointer to dynamically allocated sparseMatrix object, rather then returning the object itself, and this fixed it. However, I don't understand why. It seems like these two functions should behave identically the same way.
Also, the part that is most confusing to me, why does this run perfectly fine in Xcode, but not in Visual Studio?
tomse's answer is correct and gives the why and a fix, but it's an unnecessarily expensive fix for this problem. His suggestion of the copy constructor also solves numerous future problems such as the classics Why did my vector eat my data? and Dude, where's my segfault? Make the copy constructor. Don't use it unless you have to.
I think Andras Fekete got the problem right, but his post is kind of garbled. His solution is bang on, though.
Define your function like this:
bool readFile(string pathToFile, sparseMatrix<basic> & matrix)
Remove the definition of matrix inside the function in favour of the one passed in.
Return false on error so you know the matrix is bad (or use exceptions).
Create the matrix in the calling function and pass it into the revised reader function.
sparseMatrix<basic> matrix(100, 100);
if readFile("C:/users/jmhjr/desktop/testdata.txt", matrix);
That puts you right back where you were with the pointer version, but without the pointer and without having to do the extra work of copying data you didn't need to copy.
Your function:
sparseMatrix<basic> readFileBROKEN(string pathToFile)
returns a copy of the object (which is OK), but sparseMatrix does not define a copy constructor, so the default generated will be used which creates a shallow copy by just copying the adresses inside the returned object.
But the memory where the address points to is deleted when you leave your function (because the destructor of the locally created object is called).
To solve this you have to define your own copy contructor in sparseMatrix which copies all the content of the object.
sparseMatrix(const sparseMatrix& rhs) :
width(rhs.width),
height(rhs.height),
xArray(nullptr),
yArray(nullptr)
{
... and now copy all the content from rhs.xArray to this->xArray,
(same for yArray)
}
The problem is that you're allocating 'matrix' inside both of the readFile functions. Upon returning from the function, both variables are deallocated. However, returning the value (eradFile) the matrix is copied into your variable of the calling function, whereas returning the pointer (readFileBROKEN) is just returning the address where the matrix used to be stored.
To fix this, you should allocate the 'matrix' variable, and pass in a reference to the function. Then the function can return a void while stuffing the matrix properly.
I am trying to write a program that will read the contents of a .csv file into an array then print the results to the screen (part of a larger project) when the function getNumberOfRooms() is called an exception is thrown when it tries to return the value of the numberOfRooms variable, a private member within the class. Has anyone had a problem like this before or helped someone with this sort of problem? If so how did you solve it?
Thanks in advance,
Full source code available here: https://bitbucket.org/skutov/micropuzzle/
The exception that is thrown when getNumberOfRooms() is called:
Unhandled exception at 0x01354aa6 in MICROPUZZLE.exe: 0xC0000005: Access violation
reading location 0xccccccd0.
These are the functions in question (all of the time the variable is referenced in the class)
ClassMap::ClassMap ()
{
numberOfRooms = 0;
// Get number of rooms in map.csv
/* Find number of entries in map.csv file */
numberOfRooms = number_of_lines;
// allocate memory for rooms array
/* loading data from file into array */
}
}
// self explanitory
int ClassMap::getNumberOfRooms()
{
// Exception occurs on this line when accessing the variable
return numberOfRooms;
}
int ClassMap::printRoomDescriptions ()
{
for(int j = this->getNumberOfRooms(); j > 0; j--)
{
cout << roomArray[j].getDescription();
}
return 0;
}
Here is the class header:
class ClassMap
{
private:
int currentLocation;
int numberOfRooms;
// pointer to array initialised in constructor
ClassRoom *roomArray;
public:
// Constructors and Destructors
ClassMap();
~ClassMap();
// Print description, events and directions for current room
std::string getCurrentRoom();
// Change currentLocation to neighbour of current room if possible
int moveRoom(char direction);
// self explanitory
int getNumberOfRooms();
// dump room descriptions to command line (debugging)
int printRoomDescriptions();
};
Here is the constructor for ClassMap which also initializes roomArray:
ClassMap::ClassMap ()
{
numberOfRooms = 0;
// Get number of rooms in map.csv
unsigned int number_of_lines = 0;
FILE *infile = fopen("map.csv", "r");
int ch;
while (EOF != (ch=getc(infile)))
if ('\n' == ch)
++number_of_lines;
fclose(infile);
numberOfRooms = number_of_lines;
// allocate memory for rooms array
roomArray = new ClassRoom[numberOfRooms+1];
// set starting room
int currentLocation = 1;
// load that shit up
{
// Holders for values read from file
int newRoomID = 0;
char newRoomDescription[79] = "";
int newRoomNorthNeighbour = 0;
int newRoomEastNeighbour = 0;
int newRoomSouthNeighbour = 0;
int newRoomWestNeighbour = 0;
// used for iterations
int i = 0;
// File stream for map.csv
std::ifstream mapFile;
// Crack that shit open
mapFile.open ("map.csv");
// Line buffer for parsing
std::string line;
// For each line in the map.csv file read in the values into variables declared above then run initialise function for each room to store values into array
while (std::getline(mapFile, line))
{
// re-init parameters
newRoomID = 0;
newRoomNorthNeighbour = 0;
newRoomEastNeighbour = 0;
newRoomSouthNeighbour = 0;
newRoomWestNeighbour = 0;
for(i = 0;i<79;i++)
{
newRoomDescription[i] = ' ';
}
int parameter = 0;
int paraStart = 0;
int paraEnd = 0;
std::string buffer;
std::istringstream iss(line);
for(parameter = 0; parameter <= 5; parameter++)
{
// Empty buffer from last iteration
buffer.clear();
// Find end of current parameter
paraEnd = line.find(',',paraStart+1);
switch (parameter)
{
case 0:
buffer = line.substr((paraStart),(paraEnd-paraStart));
newRoomID = atoi(buffer.c_str());
break;
case 1:
buffer = line.substr((paraStart+2),(line.find("\"",paraStart+2)-(paraStart+2)));
for(i = 0;i<(buffer.length());i++)
{
newRoomDescription[i] = buffer.c_str()[i];
}
//newRoomDescription
break;
case 2:
buffer = line.substr((paraStart+1),(paraEnd-paraStart));
newRoomNorthNeighbour = atoi(buffer.c_str());
break;
case 3:
buffer = line.substr((paraStart+1),(paraEnd-paraStart));
newRoomEastNeighbour = atoi(buffer.c_str());
break;
case 4:
buffer = line.substr((paraStart+1),(paraEnd-paraStart));
newRoomSouthNeighbour = atoi(buffer.c_str());
break;
case 5:
buffer = line.substr((paraStart+1),(paraEnd-paraStart));
newRoomWestNeighbour = atoi(buffer.c_str());
break;
} // switch
// Cycle paraEnd to paraStart
paraStart = paraEnd;
} // for parameters loop
// Init next room with data
new (&roomArray[newRoomID]) ClassRoom( newRoomNorthNeighbour,
newRoomEastNeighbour,
newRoomSouthNeighbour,
newRoomWestNeighbour,
newRoomDescription);
} // while !EOF
// Close the file because we're a good little program and we don't need that shit no more
mapFile.close();
}
}
The key to this issue is:
Access violation reading location 0xccccccd0
0xcccccccc is a special value used in debug mode to denote an unitialised pointer. (See How to end up with a pointer to 0xCCCCCCCC ) It is set in debug mode to cause this kind of crash - it means the pointer you are using is not yet setup. Once you set up the pointer correctly the error will go away. (The slight difference from 0xcccccccc is the offset of the member you're trying to access inside that object.)
ADDED:
This is your error:
ClassRoom* roomArray = static_cast<ClassRoom*>( ::operator new ( sizeof ClassRoom * numberOfRooms ) );
This creates a local roomArray variable, and hides the member variable. What you really want is:
roomArray = static_cast<ClassRoom*>( ::operator new ( sizeof ClassRoom * numberOfRooms ) );
Or better yet:
roomArray = new ClassRoom[numberOfRooms];
I guess the problem is your for loop for(int j = this->getNumberOfRooms(); j > 0; j--). It should look like this: for(int j = this->getNumberOfRooms()-1; j >= 0; j--).
The last accessible index in an arry with N entries is N-1. On the other hand, the first index is 0.
Hi there I need to Build something like a dictionary and each word according to my code can have 100 meanings, but maybe it has only 5 meanings then I will be allocating 95 extra space for nothing or maybe it has more than 100 meanings then the program will crash, I know the vector class is very easy and could be good use of, but the task is almost building my own vector class, to learn how it works. Thus **meanings and some other stuff remain the same and here is my code, Also I know I am causing memory leakage, how can I delete properly? :
#include <iostream>
#include <string>
#include <cstring>
using namespace std;
class Expression {
char *word_with_several_meanings; // like "bank", "class"
char **meanings; // a pointer to a pointer stores all meanings
int meanings_ctr; // meanings counter
//-----------FUNCTIONS------------------------------------------------
public:
void word( char* = NULL );
void add_meaning(char* = NULL);
char* get_word();
int get_total_number_of_meanings();
char* get_meaning(int meanx = 0);
Expression(int mctr = 0); // CTOR
~Expression(); // DTOR
};
Expression::Expression(int mctr ) {
meanings_ctr = mctr; // Setting the counter to 0
meanings = new char * [100]; // Allocate Space for 100 meanings
}
Expression::~Expression() {
delete [] meanings; // Deleting the memory we allocated
delete [] word_with_several_meanings; // Deleting the memory we allocated
}
void Expression::word( char *p2c )
{
word_with_several_meanings = new char[strlen(p2c)+1];
// copy the string, DEEP copy
strcpy(word_with_several_meanings, p2c);
}
void Expression::add_meaning(char *p2c)
{
//meanings = new char * [meanings_ctr+1];
meanings[meanings_ctr] = new char[strlen(p2c)+1];
strcpy(meanings[meanings_ctr++],p2c);
}
char * Expression::get_meaning( int meanx )
{
return *(meanings+meanx);
}
char * Expression::get_word()
{
return word_with_several_meanings;
}
int Expression::get_total_number_of_meanings()
{
return meanings_ctr;
}
int main(void) {
int i;
Expression expr;
expr.word("bank ");
expr.add_meaning("a place to get money from");
expr.add_meaning("b place to sit");
expr.add_meaning("4 letter word");
expr.add_meaning("Test meaning");
cout << expr.get_word() << endl;
for(int i = 0; i<expr.get_total_number_of_meanings(); i++)
cout << " " << expr.get_meaning(i) << endl;
Expression expr2;
expr2.word("class");
expr2.add_meaning("a school class");
expr2.add_meaning("a classification for a hotel");
expr2.add_meaning("Starts with C");
cout << expr2.get_word() << endl;
for( i = 0; i<expr2.get_total_number_of_meanings(); i++)
cout << " " << expr2.get_meaning(i) << endl;
Expression expr3;
expr3.word("A long test ... ");
char str[] = "Meaning_ ";
for (int kx=0;kx<26;kx++)
{
str[8] = (char) ('A'+kx);
expr3.add_meaning(str);
}
cout << expr3.get_word() << endl;
for(i = 0; i < expr3.get_total_number_of_meanings(); i++)
cout << " " << expr3.get_meaning(i) << endl;
return 0;
}
When you are allocating a multi dimensional array with new then you are allocating it with a loop, e.g.
char **x = new char*[size]
for (int i = 0; i < N; i++) {
x[i] = new int[size];
}
So you also have to delete it in this fashion:
for (int i = 0; i < N; i++) {
delete[] x[i];
}
delete[] x;
Thus when you're having arbitrary sizes of your array you'll have to store them somewhere for using them within the destructor.
delete [] meanings; // Deleting the memory we allocated
won't get rid of your memory allocated, only the pointers themselves.
To free up the actual memory, you will need to iterate through your meanings array, and delete [] each element in it.
Something like:
for (int i = 0; i < meanings_ctr; ++i)
{
delete [] meanings[meanings_ctr];
meanings[meanings_ctr] = NULL;
}
delete [] meanings;
--
For the problem of what to do if you get more than 100 meanings (or in general when your collection is full), the standard technique is to allocate a new array that is double the size (which you can do since it is dynamic), copy your existing collection into that one, and then dispose of your existing one.
I'd use a simple linked list (this is simplified, not complete and untested; also there should be proper getters/setters and stuff):
class Meaning {
char text[20];
Meaning *next;
Meaning(const char *text) : next(0) {
strcpy(this->text, text);
}
}
class Word {
char text[20];
Meaning *first;
Meaning *last;
Word(const char *text) : first(0), last(0) {
strcpy(this->text, text);
}
~Word() {
Meaning *m = first, *n;
while(m) {
n = m->next;
delete m;
m = n;
}
}
void AddMeaning(const char *text) {
if (last) {
last = last->next = new Meaning(text);
}
else {
first = last = new Meaning(text);
}
}
void print() {
printf("%s:\n\t", text);
Meaning *m = first;
while (m) {
printf("%s, ", m->text);
m = m->next;
}
}
}