Memory Management Bug?

Completely stumped

Page 1 of 1

6 Replies - 903 Views - Last Post: 29 September 2008 - 11:03 PM Rate Topic: -----

#1 thenovices  Icon User is offline

  • D.I.C Head

Reputation: 9
  • View blog
  • Posts: 74
  • Joined: 19-January 08

Memory Management Bug?

Posted 28 September 2008 - 05:58 PM

Okay, I've spent over an hour inserting cout statements everywhere trying to find out what the bug is, and I've finally given up knowing that my paltry knowledge of memory management within C++ is probably insufficient to identify the bug even if it slapped me in the face.

So basically, the assignment is to create a Dictionary class, which has an array of Words (basically an encapsulation of a char*). The program seems like it should be really simple, which only contributes to the frustration. I've posted the parts of the code that involve memory management (most of it). I've never worked with char* and primitive arrays, so I'm really lost about how to do certain things.

Word constructor
const char* word;
Word::Word(const char* text) {
	word = text;
}



Constructor and Methods of the Dictionary Class
Word** words; //the array of pointers that point to Words
unsigned int capacity; //the capacity of the current array
unsigned int numWords; //the number of words in the array

Dictionary::Dictionary(const char* filename, int initialSize) {
	words = new Word*[initialSize];
	capacity = initialSize;
	numWords = 0;
	
	//read through the file and add words to the dictionary.
	ifstream fin(filename);
	char* word;
	while (fin >> word) {
		add(word);
	}
	cout << "Added " << numWords << " words total" << endl;
	cout << "Final capacity: " << capacity << endl;
	cout << "First word: " << *(words[0]) << endl;
	cout << "Second word: " << *(words[1]) << endl;
	cout << "Third word: " << *(words[2]) << endl;
	cout << "Fourth word: " << *(words[3]) << endl;
        // for some reason the output from these statements just prints the last word in the file four times.
}

Dictionary::~Dictionary() {
	for (unsigned int i = 0; i < numWords; ++i) {
		delete words[i]; //delete each individual Word
	}
	delete [] words; //delete the array of pointers
}

//add a word to the dictionary
void Dictionary::add(char* word) {
	if (numWords == capacity) //if there isn't any more room for words
		resize(); //double the capacity of the array
	
	words[numWords] = new Word(word);
	++numWords;
}

//resize the dictionary so there is room for more words.
void Dictionary::resize() {
	capacity *= 2; //double the capacity
	Word** tempArray = new Word*[capacity]; //create a temporary array with twice the size.
	for (unsigned int i = 0; i < numWords; ++i) {
		tempArray[i] = words[i]; //copies over the addresses of existing Words
	}
	delete [] words; //delete the old array; deletes the pointers, but not the Words.
	words = tempArray; //copy over the temporary array
}



So yeah, if you missed the comment, when I try to print out the first four words contained in the dictionary, I get the same word (the last word in the file) printed four times.

Also on a separate, but somewhat related issue, I have the following member function in the Dictionary class:
 Word** words;
Word Dictionary::getWord(int index) const{
	return *(words[index]);
}



For some reason this code works when I call it from the Dictionary constructor, but if I call it from a main.cpp, I get a runtime error. :(

I'd greatly appreciate if someone could help me find my mistake. I know that using char* and primitive arrays is just asking for pain, but unfortunately my instructor explicitly instructed not to use the string or vector class.

Is This A Good Question/Topic? 0
  • +

Replies To: Memory Management Bug?

#2 skaoth  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 91
  • View blog
  • Posts: 601
  • Joined: 07-November 07

Re: Memory Management Bug?

Posted 28 September 2008 - 08:03 PM

The problem you are having looks like its coming from how you read in the words from your dictionary and subsequently how you assign it to the Word object.
You assign the words to your dictionary like this

 fstream fin(filename);  
	 char* word;  
	 while (fin >> word) {  
		 add(word);  
	 }  


You'll notice here that the word you are adding is assigned to a char* (pointer). You then pass this pointer to your dictionary class
which is done like this

words[numWords] = new Word(word);



which then calls the word object constructor like this

	const char* word;  
	Word::Word(const char* text) {  
		word = text;  
	}  



What ends up happening then as you add more words is that you are actually assiging the const char* word in the Word class
the same pointer for all words in your input file.

This is why you are seeing all of the words in your dictionary print the last word from the input file. You haven't actually allocated and copied memory

To address the last problem, the reason it works in the constructor and not in main is because of the fact that all of the words in your dictionary
point to a variable allocated on the stack (in your constructor). What happens when the constructor call completes the 'word' variable is no longer valid
and now all of the words in your dictionary point to an invalid memory location.

To solve this you could try actually copying/allocating space for the word.
class Word
{
public:
	Word(const char* text, int size)
	{
		word = new char[size + 1];
		strncpy(word, text, size);
		word[size + 1] = '\0';
		
	{
	
	~Word() 
	{
		if(word) delete [] word;
	}
private:
	char *word;
}



Good luck

Edit:
found a typo in the destructor

This post has been edited by skaoth: 28 September 2008 - 10:30 PM

Was This Post Helpful? 1
  • +
  • -

#3 RedSonja  Icon User is offline

  • D.I.C Head
  • member icon

Reputation: 10
  • View blog
  • Posts: 172
  • Joined: 04-September 08

Re: Memory Management Bug?

Posted 28 September 2008 - 11:09 PM

>over an hour inserting cout statements everywhere trying to find out what the bug is


Use the debugger, dammit! That's what it's for.
Was This Post Helpful? 0
  • +
  • -

#4 perfectly.insane  Icon User is offline

  • D.I.C Addict
  • member icon

Reputation: 70
  • View blog
  • Posts: 644
  • Joined: 22-March 08

Re: Memory Management Bug?

Posted 29 September 2008 - 05:25 PM

Additionally:

char* word;  
while (fin >> word) {  
	add(word);  
}  



I'm surprised that this does not cause the program to abnormally terminate. Anyway, one has to allocate word in this case prior to using it, or by using a std::string to prevent buffer overflow. Allocating on the stack is not recommended, as stack corruption tends to be worse than heap corruption (in my opinion, anyway, though I prefer to stop the bugs completely).
Was This Post Helpful? 1
  • +
  • -

#5 thenovices  Icon User is offline

  • D.I.C Head

Reputation: 9
  • View blog
  • Posts: 74
  • Joined: 19-January 08

Re: Memory Management Bug?

Posted 29 September 2008 - 06:19 PM

View PostRedSonja, on 28 Sep, 2008 - 11:09 PM, said:

>over an hour inserting cout statements everywhere trying to find out what the bug is


Use the debugger, dammit! That's what it's for.


Yeah... Unfortunately I am completely clueless about how to use a debugger. I've heard that its one of the most important skills in programming, but I've never learned it. I'd greatly appreciate it if you could point me to some tutorials.

View Postperfectly.insane, on 29 Sep, 2008 - 05:25 PM, said:

Additionally:

char* word;  
while (fin >> word) {  
	add(word);  
}  



I'm surprised that this does not cause the program to abnormally terminate. Anyway, one has to allocate word in this case prior to using it, or by using a std::string to prevent buffer overflow. Allocating on the stack is not recommended, as stack corruption tends to be worse than heap corruption (in my opinion, anyway, though I prefer to stop the bugs completely).


Yeah after you mentioned that, I realized that I would be accessing memory improperly, wouldn't I? So I changed my code to this:

char* word = new char[100]; //probably not going to be any words longer than 99 letters
while (fin >> word) {
       add(word);
}
delete [] word;



I hope that is the proper way to do it. I just used the dynamic heap like you said, mainly because I don't know if you can have a pointer to memory on the stack. (At least I don't know how to write the code for it).

Well thanks for pointing that out!
Was This Post Helpful? 0
  • +
  • -

#6 trixt.er  Icon User is offline

  • D.I.C Regular
  • member icon

Reputation: 52
  • View blog
  • Posts: 426
  • Joined: 28-September 08

Re: Memory Management Bug?

Posted 29 September 2008 - 08:47 PM

Quote

I do not know if you are allowed to use strings or not but I would strongly suggest implementing them if your teacher allows you to. You can allocate dynamic strings off the heap (free-store). Seems a lot easier than taking every character of the word and putting them into a dynamic array. But once again that is only if your teacher will allow you. You could even create a struct and use it as a modified dynamic string array. The following is an option to consider.

string* name = new string;
cout << "Enter a name :";
cin >> *name;//Stores name value onto the heap.
cout << "The name is " << *pointer << endl;//Dereferencing operator is once again used to output stored name.


Was This Post Helpful? 0
  • +
  • -

#7 thenovices  Icon User is offline

  • D.I.C Head

Reputation: 9
  • View blog
  • Posts: 74
  • Joined: 19-January 08

Re: Memory Management Bug?

Posted 29 September 2008 - 11:03 PM

yeah, unfortunately the instructor has specifically said to use the char*, so that we can appreciate the ease of using the string class. xD

thanks for the suggestion though.
Was This Post Helpful? 0
  • +
  • -

Page 1 of 1