Why would accessing this local member variable cause an exception? - c++

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.

Related

Segmentation fault error with structures

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

How can I store a string(from a file with n number of lines) in a dynamic array initialized as a unique pointer? C++

A student looking for some guidance...
This is a class assignment with the instructions:
Re-write your program, List of Chores, using a unique_ptr object as your data member. You should store a dynamic array in the unique_ptr object. Use this array for storing, retrieving, deleting and updating chores.
I am trying to learn more about using the unique_ptr object so I may create the constructor which is supposed to initialize the list. A text file has the list and the constructor should store that list into an array. I am trying to work around the error "Access violation reading location." In the original program, I created a temporary dynamic array with a larger capacity and copied the list into that array. There's a list of 10 chores in the text file. Here is that code:
In Header:
private:
/* var to keep len of list */
int len = 0;
int max = 9;
/* add appropriate data structure to store list */
string *arr = new string[max];
In .cpp:
/* reads the file line by line and initializes list */
ListOfChores::ListOfChores(string fileName){
ifstream file(fileName, ifstream::in);
string line;
if (file.is_open()) //Checking if the file can be opened
{
while (getline(file, line)) // Gets a single line
{
if (len >= max)
{
string *narr = new string[max + 10]; // New, larger array
for (int i = 0; i < max; i++)
{
narr[i] = arr[i]; // Copies line
}
delete[] arr; // Clears
arr = narr; // Copies
max += 1; // Growth
}
arr[len] = line; // Store a line in the array
len++; // Increases length by 1
}
file.close(); // Closes file
}
else cout << "Unable to open file" << endl;
}
And to show that I have been working on this and am not a lazy student...
New program attempt header:
private:
/* var to keep len of list */
int len = 0;
int max = 9;
/* add appropriate data structure to store list */
string *arr = new string[max]; // Primary array
string *narr = new string[max]; // New array
New program .cpp:
/* reads the file line by line and initializes list */
ListOfChores::ListOfChores(string fileName) {
unique_ptr<string[]> arr(new string[max]); // Unique pointer initialization
ifstream file(fileName, ifstream::in);
string line = " ";
if (file.is_open()) //Checking if the file can be opened
{
while (getline(file, line)) // Gets lines from file
{
if (len >= max)
{
max++; // Growth
unique_ptr<string[]> narr(new string[max]); // New unique pointer
narr = move(arr);// narr owns the object
narr[max] = line; // Store a line in the array
len++; // Increases length by 1
arr = move(narr); // arr owns the object
}
else
{
arr[len] = line; // Store a line in the array
len++; // Increases length by 1
}
}
file.close(); // Closes file
}
else cout << "Unable to open file" << endl;
}
The entire point of a unique_ptr is to destroy the managed pointer when the unique_ptr goes out of scope. This means you do not want it declared inside any confined scope. Any work you do will be destroyed as soon as the current block of code is exited. A unique_ptr created inside a function and not returned to the caller is gone and it's contents are gone with it as soon as the function returns. If you have a class intended to store a dynamic amount of data, then the data should be managed at the object's scope.
So
private:
/* var to keep len of list */
int len = 0;
int max = 20; // made bigger so first 50% increase is 10 elements
/* add appropriate data structure to store list */
std::unique_ptr<std::string[]> arr; // Primary array
// no need for New array here
Discussion of whether a 50% or 100% array size increase is better can be found here: What is the ideal growth rate for a dynamically allocated array?. As always, your mileage may vary, but a one-at-a-time increase is generally agreed upon to be a bad idea.
Now onto ListOfChores where we want to use, but not declare, the unique_ptr.
ListOfChores::ListOfChores(string fileName) {
//no unique_ptr here. Scope is too narrow to be useful
ifstream file(fileName, ifstream::in);
string line = " ";
if (file.is_open()) //Checking if the file can be opened
{
while (getline(file, line)) // Gets lines from file
{
if (len >= max)// the current size is too small Let's make it bigger!
// if we grow before adding the line, we don't need any
// special code to add the new line.
{
max *= 1.5; // Grow by 50%. Numerous studies have shown that 50% is a
// good balance of RAM vs copy overhead in the general case
std::string * narr = new string[max]; // no unique_ptr here either
// old school copy for simplicity and obviousness
for (int index = 0; index < len; index++)
{
narr[index] = arr[index]
}
arr.reset(narr); // frees and replaces the old array
// arr now manages narr
}
// done growing, add normally to array
arr[len] = line; // Store a line in the array
len++; // Increases length by 1
}
file.close(); // Closes file
}
else cout << "Unable to open file" << endl;
}
Other ListOfChores member functions will use arr, reading, adding and subtracting as needed. In order to add efficiently, the array growth code should be removed from the constructor and placed in a private method to be called by the constructor and other methods that need to enlarge the array.

Segmentation Fault on delete[]

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.

Deleting objects on the heap which store data on the heap

My program has been written using classes from the SDL library.
I have the following class:
class s_group
{
private:
SDL_Surface* image;
unsigned int* F_total;
float* F_length;
SDL_Rect** F;
float* F_current;
unsigned int S_total;
unsigned int S_current;
public:
s_group(void);
virtual ~s_group(void);
bool setup( const char* filename, unsigned int s );
//other member functions
};
Private member pointers each store the location of memory declared on the heap, as allocated by the member function setup.
bool s_group::setup( const char* filename, unsigned int s )
{
s_group::~s_group();//delete already allocated heap memory
if(!load_file(image, filename))
{
image = NULL;
return false;
}
S_total = s;
F = new SDL_Rect*[S_total];
F_total = new unsigned int[S_total];
F_length = new float[S_total];
F_current = new float[S_total];
for(unsigned int index = 0; index < S_total; ++index)
{
F[index] = NULL;
F_total[index] = 0;
F_length[index] = 0.f;
F_current[index] = 0.f;
}
//loop for each array slot and set values of data
return true;
}
Within a large function I create an object of this class on the heap, storing its address in an s_group pointer named sparkle.
s_group* sparkle = new s_group;
sparkle->setup("sparkle_final.png", 1 );
On completion of the function I call delete to reallocate the heap memory. Removing this line solves the problem, however there would then be a memory leak.
delete sparkle;
sparkle = NULL;
This will call the destructor of the class which is where I believe the error occurs due to an internal use of the delete operator.
s_group::~s_group(void)
{
SDL_FreeSurface(image);
image = NULL;
for(unsigned int s = 0; s < S_total; ++s)
{
for(unsigned int f = 0; f < F_total[s]; ++f)
{
F[s][f].x = 0;
F[s][f].y = 0;
F[s][f].w = 0;
F[s][f].h = 0;
}
delete[] F[s];
F[s] = NULL;
}
delete[] F;
F = NULL;
delete[] F_total;
F_total = NULL;
delete[] F_length;
F_length = NULL;
delete[] F_current;
F_current = NULL;
S_total = 0;
S_current = 0;
}
On reaching the delete operator, a dialog box appears stating:
Windows has triggered a breakpoint in Program.exe. This may be due to a corruption of the heap, which indicates a bug in Program.exe or any of the DLLs it has loaded.
How do I delete this object without causing the heap corruption?
From effective C++ Scott Meyers
Item 9: Never call virtual functions during construction or destruction.
You shouldn't call virtual functions during construction or destruction, because the calls won't do what you think, and if they did, you'd still be unhappy. If you're a recovering Java or C# programmer, pay close attention to this Item, because this is a place where those languages zig, while C++ zags.
Actually, even though you should define your destructor, calling it forcibly should be out of the question
I'm unable to compile your code but here goes..
The first thing I noticed was that you called your destructor.. You don't want to do that! Instead, create a release function and call that.
The next thing I noticed is that there is no FRAME variable within the class itself.. so this line:
FRAME = new SDL_Rect*[S_total];
is going to cause a compilation error and your destructor uses FRAME but no such variable exists. I think you meant to change it to F because if not, then this line:
F[index] = NULL;
is undefined behaviour since F is uninitialized..
Also, you never initialized each index of FRAME and so accessing it in the destructor like:
FRAME[s][f].x = 0;
is a no-no.
Again, you call
delete[] F;
F = NULL;
but F has no memory allocated and is uninitialized.
Thus with all the patches I think:
class s_group
{
private:
SDL_Surface* image;
unsigned int* F_total;
float* F_length;
SDL_Rect** FRAME;
float* F_current;
unsigned int S_total;
unsigned int S_current;
void Release();
public:
s_group(void);
virtual ~s_group(void);
bool setup(const char* filename, unsigned int s);
//other member functions
};
bool s_group::setup(const char* filename, unsigned int s)
{
Release();//delete already allocated heap memory
if(!load_file(image, filename))
{
image = NULL;
return false;
}
S_total = s;
FRAME = new SDL_Rect*[S_total];
F_total = new unsigned int[S_total];
F_length = new float[S_total];
F_current = new float[S_total];
for(unsigned int index = 0; index < S_total; ++index)
{
FRAME[index] = NULL;
F_total[index] = 0;
F_length[index] = 0.f;
F_current[index] = 0.f;
}
//loop for each array slot and set values of data
return true;
}
void s_group::Release()
{
SDL_FreeSurface(image);
image = NULL;
for(unsigned int s = 0; s < S_total; ++s)
{
for(unsigned int f = 0; f < F_total[s]; ++f)
{
if (FRAME[s])
{
FRAME[s][f].x = 0;
FRAME[s][f].y = 0;
FRAME[s][f].w = 0;
FRAME[s][f].h = 0;
}
}
delete[] FRAME[s];
FRAME[s] = NULL;
}
delete[] FRAME;
FRAME = NULL;
delete[] F_total;
F_total = NULL;
delete[] F_length;
F_length = NULL;
delete[] F_current;
F_current = NULL;
S_total = 0;
S_current = 0;
}
s_group::~s_group(void)
{
Release();
}
should do it.. Just don't forget to allocate memory for FRAME[index] I wasn't sure how much or what you wanted to allocate so I changed the Release function to check if FRAME[index] is valid with an if-statement
I would strongly advise that you use some SmartPointers and forget about handling every single memory allocation yourself..
Since posting this question I have located the source of the error and solved the issue.
In a separate section of code which set the data values for the dynamic 2D array the loop validation was incorrect.
for( unsigned int index = 0; index <= F_total[ S_current ]; ++index ) {
//set data values for each slot in the array
F[ S_current ][ index ].x = 0; etc...
}
As can be seen the loop will clearly attempt to modify a location equal to the size of the created array. Noting of course that arrays begin at index 0, so the final slot will be at size - 1. Something very silly that I missed when writing the code. Actual loop:
for( unsigned int index = 0; index < F_total[ S_current ]; ++index ) {
//set data values for each slot in the array
F[ S_current ][ index ].x = 0; etc...
}
A message for anyone attempting their own memory management:
Finding the source of heap corruption is difficult as the compiler will locate the error in sections of code which do not necessarily cause the problem.
The cause of the problem will only ever be in the section of your code which is affecting the memory. Ensure that you do not attempt to access or worse modify any memory that you have not been given.
I still believe that memory management is a great way to learn and would rather complete any projects in this way than using containers or smart pointers as recommended. This is my personal preference despite custom memory management often offering very few advantages, only complexities.
When asking for assistance provide all related code on the problem. Although the compiler may direct you to the problem in one section, as I said before, with heap corruption it's not necessarily there.

access violation reading location c++

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