Heap Corruption

This is the .cpp file for a class, have a Heap Corruption problem and are sure the problem lies here. I've initialized all pointers to NULL, but are still unable to find the problem. Think the problem probably lies in the operator+ methodAny help, please?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
#include "GenString.h"
#include <ctype.h>
#include <string>
using namespace std;

//Initialize static data members
int GenString::count = 0;

GenString::GenString()
{
	string = new char[1];
	string[0] = 0;
	count++;
}

GenString::GenString(char *string_value)				
{
	this->setString(string_value);
}
GenString::GenString(const GenString &string_value)	
{
	this->setString(string_value.string);
}
GenString::~GenString()							
{
	delete[] string;
}
void GenString::setString(char* string_value)	
{
	int length = strlen(string_value) + 1;
	string = new char[length];
	memset(string, NULL, length);
	strcpy_s(string, length, string_value);
}
char* GenString::getString()							
{
	int length = strlen(string) + 1;
	char* ret = new char[length];
	memset(ret, NULL, length);
	strcpy_s(ret, length, string);
	return ret;
}
void GenString::toLower()								
{
	int length = this->getLength();
	int i = 0;
	for(i = 0; i < length;  i++)
	{
		string[i] = tolower(string[i]);
	}
}
void GenString::toUpper()	
{
	int length = this->getLength();
	for(int i = 0; i < length; i++)
	{
		string[i] = toupper(string[i]);
	}
}
char GenString::getChar( int index)
{
	
	int length = this->getLength();
	if(index < 0 || index >= length)
	{
		cout << "ERROR: Index out of bounds" << endl;
		return NULL;
	}
	return (string[index]);
}
int GenString::getLength()
{
	int length = 0;
	length = strlen(string);
	return length;
}
bool GenString::isEqual(GenString another_string)
{
	if(strcmp(this->string, another_string.string) == 0)
		return true;
	else 
		return false;
}
bool GenString::operator==( GenString right_side)
{
	//Compare right string to this string
	if(strcmp(this->string, right_side.string) == 0)
		return true;
	else 
		return false;
}
bool GenString::operator>(GenString right_side)
{
	if(strcmp(this->string, right_side.string) < 0)
		return true;
	else
		return false;
}
bool GenString::operator<(GenString right_side)
{
	if(strcmp(this->string, right_side.string) > 0)
		return true;
	else
		return false;
}
//*******************************************
//Returns true if the GenString on the right side of the >= operator is greater than or 
//equal to the GenString on the left side (this GenString). 
//*******************************************
bool GenString::operator>=(GenString right_side)
{
	if(strcmp(this->string, right_side.string) == 0 || strcmp(this->string, right_side.string) < 0)
		return true;
	else
		return false;
}
//*******************************************
//Returns true if the GenString on the right side of the <= operator is less than or 
//equal to the GenString on the left side (this GenString). This is based on the results of strcmp. 
//*******************************************
bool GenString::operator<=(GenString right_side)
{
	if(strcmp(this->string, right_side.string) == 0 || strcmp(this->string, right_side.string) > 0)
		return true;
	else
		return false;
}
//*******************************************
//Concatenates the GenString on the right side of the + operator to this GenString 
//(which is on left side of the + operator) and stores the concatenated GenString in this GenString.  
//*******************************************
void GenString::operator+=(GenString right_side)
{
	int length = right_side.getLength() + this->getLength() + 1;
	strcat_s(this->string, length, right_side.string);	
}
//*******************************************
//Creates a GenString which is the concatenation of the 
//GenString on the right side of the + operator to this 
//GenString (left operand), without changing this GenString, and returns the concatenated GenString  
//*******************************************
GenString GenString::operator+(GenString& right_side)
{
	//creating new object
	GenString result;
	int newSize = this->getLength() + right_side.getLength() + 1;
	char* temp = new char[newSize];
	memset(temp, NULL,newSize);
	strcpy_s(temp, this->getLength() + 1, this->string);
	strcat_s(temp, newSize, right_side.string);
	result.string = temp;
	return result;
}
//*************************************************
// Assigns the GenString on the right side of an assignment statement 
//to the GenString on the left side (to this GenString).
//*************************************************
void GenString::operator=(GenString right_side)
{
	int length = right_side.getLength() + 1;
	this->string = new char[length];
	memset(string, NULL, length);
	strcpy_s(this->string, length, right_side.string);
}
//************************************
//Returns the character at the specified index.  
//If the index is < 0 or > the string length, prints an error message 
//and exits the program.  (Return reference for left side)
//*********************************************
char& GenString::operator[ ](int index)
{
	if(index < 0 || index > this->getLength())
	{
		cout << "Error: Invalid index" << endl;
		exit(0);
	}
	return(string[index]);
}
//***********************************
// Prepends a space to the private data field string using the prefix increment
//***********************************
GenString GenString::operator++()		
{
	int length = strlen(string) + 1;	
	char* temp = new char[length];
	memset(temp, NULL, length);
	strcpy_s(temp, length, string);
	char space[2] = " ";
	++length;
	string = new char[length];
	memset(string,NULL, length);
	string[0] = space[0];
	for(int i = 1; i < length; i++)
		string[i] = temp [i-1];
	delete[] temp;
	return(*this);
}
//***********************************
// Removes a space (if possible) from the first character of the  private data field 
// using the prefix decrement
//***********************************
GenString GenString::operator--()		
{
	int length = strlen(string);
	if(string[0] == ' ')
	{
		for(int i = 0; i < length; i++)
		{
			string[i] = string[i+1];
		}
		return (*this);
	}
	else
		return(*this);
}
//***********************************
// Appends a space to the private data field string using the postfix increment (if possible)
//***********************************
GenString GenString::operator++(int dummy)			
{
	
	//Appending space if possible
	int length = this->getLength() + 1;
	char* string2 = " ";
	if(string[length-1] == ' ')
	{
		return(*this);
	}
	else
	{
		string = strcat(string, string2);
		return(*this);
	}
}
//***************************************
// Removes a space from the end of the private 
//data field string using the postfix decrement (if possible)
//***************************************
GenString GenString::operator--(int dummy)
{
	int length = this->getLength();
	if(string[length-1] == ' ')
	{
		string[length-1] = NULL;
		return (*this);
	}
	else
	{
		cout << "Unable to remove space from the end of the private data field with postfix "<< endl;
		return (*this);
	}
}
//********************************************************
// Overloaded >> operator. Gives cin the ability to      *
// store user input directly into GenString objects.    *
//********************************************************
istream& operator>>(istream& input, GenString& gstr_obj)
{	
	std::string str;
	getline(input, str);
	char* temp = new char[str.size()+1];
	memset(temp, NULL, str.size()+1);
	for(int i = 0; i<= str.size(); i++)
	{
		temp[i] = str[i];
	}
	gstr_obj.setString(temp);
	delete[] temp;
	return input;			//allows cascading of in operator
}
//********************************************************
// Overloaded << operator. Gives cout the ability to     *
// directly display GenString objects.                  *
//********************************************************
ostream& operator<<(ostream& screen_out, GenString gstr_obj)
{
	screen_out << gstr_obj.getString();
	return screen_out;			//allows cascading of << operator
}

int GenString::getCount()
{
	return(count);
}
Last edited on
Why this weird combination of std::string, direct string handling, and C functions? You're probably screwing something up somewhere and corrupting memory. Just move all your code to std::string and be done with it.
+1 what helios said. If you don't really have a GOOD reason to implement yet another string class, don't do it.

Your code has several severe problems, among them: several places where you leak memory (operator= for example), strange logic in some of your operators (++s always add spaces, s++ only if there is no space at the end), bad performance (lots of temporary and unnecessary string copies, use of strcat instead of strcpy)....

Your original problem may lie in the postfix operator++, where you add a space without having enough memory for it, thus writing a null-termination on unallocated heap space.

But really. Save you the pain and just use std::string. Even if you fix that one, there are most probably a lot of other subtile errors. Good string classes are scare and very hard to write and std::string is usually one of the best implementations.

Ciao, Imi.
Last edited on
1
2
3
4
5
6
7
void GenString::setString(char* string_value)	
{
	int length = strlen(string_value) + 1;
	string = new char[length];
	memset(string, NULL, length);
	strcpy_s(string, length, string_value);
}

This doesn't release the old string, it's a memory leak.

1
2
3
4
GenString::GenString(const GenString &string_value)	
{
	this->setString(string_value.string);
}

This doesn't initialise string, so setString will corrupt the heap (when fixed).

1
2
3
4
5
6
7
8
char* GenString::getString()							
{
	int length = strlen(string) + 1;
	char* ret = new char[length];
	memset(ret, NULL, length);
	strcpy_s(ret, length, string);
	return ret;
}

This assumes the caller will delete the returned char array, possible memory leak.

bool GenString::isEqual(GenString another_string)
All these functions take a GenString by value. Are you sure you want to do this?

1
2
3
4
5
void GenString::operator+=(GenString right_side)
{
	int length = right_side.getLength() + this->getLength() + 1;
	strcat_s(this->string, length, right_side.string);	
}

This doesn't grow the buffer, it writes off the end, corrupting the heap.

1
2
3
4
5
6
7
void GenString::operator=(GenString right_side)
{
	int length = right_side.getLength() + 1;
	this->string = new char[length];
	memset(string, NULL, length);
	strcpy_s(this->string, length, right_side.string);
}

This doesn't release the old string, it's a memory leak.

... and so on.
thanks a lot, everybody. I am yet a beginner in this and are still learning. will make the proper changes.
Topic archived. No new replies allowed.