Operator + member function crashes about 1/8th of the time... implemented in terms of working member functions?

I have a STRING class I have created that does more or less what you would expect a class called "STRING" to do. I have implemented operator+ in terms of my constructor and operator +=. About 1/8th of the time the program crashes, the rest of the time its fine. This suggest to me its a bad pointer but I haven't a clue where the problem is. If someone could help me out I would really appreciate it.

Some of the functions I haven't yet implemented, they are commented out in my implementation.

Head file
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

#ifndef _MYSTRING_H_ 
      #define _MYSTRING_H_ 

      #include <iostream>
      using namespace std;

      class STRING
      {
      private:
              
        char* _s; 
        unsigned _len; 
        
      public: 
        STRING(); //default constructor
        STRING(const char*);//constructor
        STRING(char); //constructor
        STRING(const STRING&);//copy constructor
        ~STRING(); //destructor
        
        int length() const;
        int position(char) const;
        void upcase(void);
        void downcase(void);
        void togglecase(void);
        
        char operator[] (unsigned) const;
        char& operator[] (unsigned);
        
        STRING& operator=(const STRING&);
        STRING& operator=(const char*);
        STRING& operator=(char);
        
        STRING& operator+=(const STRING&);
        STRING& operator+=(const char*);
        STRING& operator+=(char);
        
        STRING operator+ (const STRING& ) const;
        STRING operator+ (char*) const;
        STRING operator+(char) const;
        friend STRING operator+ (char*, const STRING&);
        friend STRING operator+ (char, const STRING&);
        
        bool operator== (const STRING& ) const; 
        bool operator== (char*) const; 
        friend bool operator== (char*, const STRING&); 
        
        bool operator< (const STRING& ) const; 
        bool operator< (char*) const; 
        friend bool operator< (char*, const STRING&); 
        
        bool operator!= (const STRING& ) const; 
        bool operator!= (char*) const; 
        friend bool operator!= (char*, const STRING&); 
        
        bool operator> (const STRING& ) const; 
        bool operator> (char*) const; 
        friend bool operator> (char*, const STRING&); 
        
        bool operator<= (const STRING& ) const; 
        bool operator<= (char*) const; 
        friend bool operator<= (char*, const STRING&); 
        
        bool operator>= (const STRING& ) const; 
        bool operator>= (char*) const; 
        friend bool operator>= (char*, const STRING&); 
        
        friend ostream& operator<< ( ostream&, const STRING&);
        friend istream& operator>> ( istream&, STRING&);
      };
      #endif 


Implementation file
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
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320

#include "MyString.h"


STRING::STRING()
{
    _s = NULL;
    _len = 0;
}

STRING::STRING(const char* c)
{
    _len = 0;
    _s = NULL;
    if (c != NULL)
    {
        while ( c[_len] != '\0')
        {
            _len++;
        }
   
        _s = new char[_len];
   
        for (unsigned i = 0; i < _len; i++)
        {
        _s[i] = c[i];
        }
    }
    
}

STRING::STRING(char c)
{
   _len = 1;
   _s = new char[0];
   _s[0] = c;
}

STRING::STRING(const STRING& s)
{
    delete[] _s;
    _s = new char[s._len];
    _len = s._len;
    
    for (int i = 0; i < _len; i++)
    {
        _s[i] = s._s[i];
    }
}

STRING::~STRING()
{
    delete[] _s;
}
       
int STRING::length() const
{
    return _len;
}

int STRING::position(char inst) const
{
     for (int i = 0; i < _len; i++)
    {
        if (inst == _s[i])
        {
                 return i;
        }
    }
    
    return -1;
}

void STRING::upcase(void)
{    
    for(int i = 0; i < _len; i++)
    {
        if (_s[i] >= 'a' && _s[i] <= 'z')
        {
            _s[i] &= 223; 
        }
    }
}

void STRING::downcase(void)
{
    for(int i = 0; i < _len; i++)
    {
        if (_s[i] >= 'A' && _s[i] <= 'Z')
        {
            _s[i] |= 32; 
        }
    }
}

void STRING::togglecase(void)
{
    for(int i = 0; i < _len; i++)
    {
        if (_s[i] >= 'A' && _s[i] <= 'Z')
        {
            _s[i] |= 32; 
        }
        else if (_s[i] >= 'a' && _s[i] <= 'z')
        {
            _s[i] &= 223; 
        }
    }
}      
char STRING::operator[](unsigned index) const
{
    if (index >= _len)
    {
        cout << "Error, attempt to access outside of string";
        exit(200);
    }
    
    return _s[index];
}
char& STRING::operator[](unsigned index)
{
    if (index >= _len)
    {
        cout << "Error, attempt to access outside of string";
        exit(200);
    }
    
    return _s[index];
}   
    
STRING &STRING::operator=(const STRING& s)
{
    if (this == &s)
    {
        return *this;
    }
    
    delete[] _s;
    _s = new char[s._len];
    _len = s._len;
    
    for (int i = 0; i < _len; i++)
    {
        _s[i] = s._s[i];
    }
    
    return *this;
}    

STRING &STRING::operator=(const char* c)
{
     _len = 0;
     delete[] _s;
    _s = NULL;
    if (c != NULL)
    {
        while ( c[_len] != '\0')
        {
            _len++;
        }
   
        _s = new char[_len];
   
        for (unsigned i = 0; i < _len; i++)
        {
        _s[i] = c[i];
        }
    }
    
    return *this;
}

STRING &STRING::operator=(char c)
{
    _len = 1;
    delete[] _s;
   _s = new char[0];
   _s[0] = c;
    
    return *this;
}
           
STRING &STRING::operator+=(const STRING& s)
{   
    char* temp = new char[_len + s._len -1];
    int i = 0;
    
    for (; i < _len; i++)
    {
        temp[i] = _s[i];
    }
    
    for (int j = 0; j < s._len; j++)
    {
        temp[i+j] = s._s[j];
    }
    
    delete[] _s;
    _s = temp;
    _len+= s._len;
    
    return *this;
}

STRING &STRING::operator+=(const char* c)
{
    int charLen = 0;
    int i = 0;
    
     while ( c[charLen] != '\0')
        {
            charLen++;
        }
        
    char* temp = new char[_len + charLen -1];
    for (; i < _len; i++)
    {
        temp[i] = _s[i];
    }
    
    for (int j = 0; j < charLen; j++)
    {
        temp[i+j] = c[j];
    }
    
    delete[] _s;
    _s = temp;
    _len+= charLen;
    
    return *this;
}

STRING &STRING::operator+=(char c)
{
    
    int i = 0;
    char* temp = new char[_len];
    for (; i < _len; i++)
    {
        temp[i] = _s[i];
    }
    
    cout << c << endl;
    temp[i] = c;
    
    delete[] _s;
    _s = temp;
    _len++;
    
    return *this;
}
    

STRING STRING::operator+ (const STRING& s) const
{
       STRING temp = *this;
       temp+= s;
       return temp;
}

STRING STRING::operator+ (char* c) const
{
       STRING temp = *this;
       temp+= c;
       return temp;
}

STRING STRING::operator+ (char c) const
{
       STRING temp = *this;
       temp+= c;
       return temp;
}
     
STRING operator+ (char* c, const STRING& s)
{
      STRING temp(c);
      temp += s;
      return temp;
} 

STRING operator+ (char c, const STRING& s)
{
      STRING temp(c);
      temp += s;
      return temp;
} 
/*        
bool operator== (const STRING& ) const; 
bool operator== (char*) const; 
friend bool operator== (char*, const STRING&);         
bool operator< (const STRING& ) const; 
bool operator< (char*) const; 
friend bool operator< (char*, const STRING&);         
bool operator!= (const STRING& ) const; 
bool operator!= (char*) const; 
friend bool operator!= (char*, const STRING&);         
bool operator> (const STRING& ) const; 
bool operator> (char*) const; 
friend bool operator> (char*, const STRING&);         
bool operator<= (const STRING& ) const; 
bool operator<= (char*) const; 
friend bool operator<= (char*, const STRING&);         
bool operator>= (const STRING& ) const; 
bool operator>= (char*) const; 
friend bool operator>= (char*, const STRING&);         
*/
ostream& operator<< ( ostream& os, const STRING& s)
{
    for (int i = 0; i < s._len; i++)
    {
        os << s._s[i];
    }   
    
    os << '\0';   
} 
/*friend istream& operator>> ( istream& is, STRING&)
{
*/    

My test main
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
#include <iostream>
#include "MyString.h"

using namespace std;

int main()
{
    STRING s;
    STRING s1 = "abcde";
    STRING s2 = "AbCdE";
    STRING s3 = "c";
    char c = 'a';
    cout << s1.length() << endl;
    cout << s1.position('c') << endl;
    cout << s1 << endl;
    cout << s3 << endl;
    s1.upcase();
    cout << s1 << endl;
    s1.downcase();
    cout << s1 << endl;
    cout << s2 << endl;
    s2.togglecase();
    cout << s2 << endl;
    s1 = s2;
    cout << s1 << endl;
    s1 = s2 = s3;
    cout << s1 << endl;
    s1 = c;
    cout << s1 << endl;
    s1 = "abcde";
    cout << s1 << endl;
    s2 = "fgh";
    s1 += s2;
    cout << s1 << endl;
    s1 = "abcde";
    s1 += "fgh";
    cout << s1 << endl;
    s1 += c;
    cout << s1 << endl;
    s3 += s3;
    //cout << s3 << endl;
    //s3 = s3 + s3;
    cout << s3 << endl;
    s3 = s3;
    cout << s3 << endl;
    //s3 = s3 + s3;
    //cout << s3 << endl;
    //s3 = s3 + "dd";
    //cout << s3 << endl;
    //s3 = "dd" + s3;
    //cout << s3 << endl;
    //s3 = s3 + 'a';
    //s3 = 'a' + s3;
    cin.get();
    return 0;
}


Here is my operators plus of type STRING + STRING function. This is the function giving my problems. I have looked to my operator= functions and operator+= functions for errors but have not been able to find any.

1
2
3
4
5
6
STRING STRING::operator+ (const STRING& s) const
{
       STRING temp = *this;
       temp+= s;
       return temp;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
STRING::STRING(char c)
{
   _len = 1;
   _s = new char[0]; 
   _s[0] = c; //out of bounds (your array is zero size ¿?)
}

STRING::STRING(const STRING& s)
{
    delete[] _s; //¿what are you deleting?
    _s = new char[s._len];
    _len = s._len;
    
    for (int i = 0; i < _len; i++)
    {
        _s[i] = s._s[i];
    }
}
Your program is full of bugs. Let consider for example only two functions the default constructor and the operator +=( char c )

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
STRING::STRING()
{
    _s = NULL;
    _len = 0;
}

STRING &STRING::operator+=(char c)
{
    
    int i = 0;
    char* temp = new char[_len];
    for (; i < _len; i++)
    {
        temp[i] = _s[i];
    }
    
    cout << c << endl;
    temp[i] = c;
    
    delete[] _s;
    _s = temp;
    _len++;
    
    return *this;
}


Let assume that there is such code

1
2
STRING s;
s += 'A';


_len of the objetc s is equal to 0. And what are you doing in operator +=?

char* temp = new char[_len];

and after that

temp[i] = c;

You should be coution with pointers. Please check all your code.

Also it is a bad idea to assign names to variables that starts from undescore because such names reserved by the implementation.
Last edited on
mystified by the -1 in the allocation, which looks like it will then be one character short

 
char* temp = new char[_len + s._len -1];



Last edited on
wow that's a lot of strange code

memory access errors:
1. in operator=: zero-length array allocation (new char[0]), followed by a write to the element number 1 (_s[0] = c;)
2. in operator+=: allocation for _len + s._len - 1, but the loop writes at the index i+j, which reaches _len + s._len - 1.
3. In the second operator+=, same story (allocation for _len + charLen - 1, accessing temp[_len + charLen - 1]
4. in the third operator+=, allocation for _len, but the last write (temp[i] = c, outside the loop) writes to temp[_len]

besides those errors, I see some compiler diagnostics:
1. comparison between signed and unsigned in 11 places
2. exit() called without a header file
3. operator<< lacks a return statement

and many style issues:
1. "using namespace std;" in a header file
2. binary operators implemented as member functions (even though they correctly call compound assignment operators internally)
3. constructors don't use member initializers
4. toupper/tolower replacements use magic numbers
5. other library code is reimplemented needlessly

PS: totally missed the delete _s; in the copy ctor
Last edited on
@Cubbi
1. "using namespace std;" in a header file


This complaint should be addressed to numerous authors of books on C++.:)
Hi cubbi, thanks for your response.

1. That is strange yeah. I guess I could have just dynamically alocated a single character and set my pointer to it.
2. That is just a quirk in the implementation. The _len is the number of characters in the string, the first element is "1" not "0" so conversions can be odd at times. Not really related to my problem.
3. You have to create a temporary pointer to memory for that function. There isn't another way to do it.
4. I don't know whats strange about this. Temp = the contents of the object. The last character equals the content of the passed character. Again, there isn't a way to do this function without a temporary pointer.

1. I could be more careful about that.
2. My instructor is to blame for this one :p.
3. Thanks for point that out! Probably would have lost points on that. Fixed.

1. You can blame my instructor for this as well!
2. I don't know what you mean about this. Please elaborate.
3. I should do that. Need to brush up on Myers.
4. Again my instructor! I can't increment or decrement by a constant, but I can use unary operators with a constant. Strange specification but I have to follow it.
5. The purpose of this project is to re implement standard libraries.

PS: Please elaborate. As far as I know, dynamic memory is very neccessary in the copy constructor.

Cubbi, while I do appreciate your comments on my practice, suggestions for better alternatives would be very helpful.

Also, none of the things you mentioned are causing problems with my code, at least as far as I know. I would appreciate help finding exactly what is causing my errors. Thank you.
Last edited on
none of the things you mentioned are causing problems with my code

Huh? the first four were actual runtime errors, each of which was fatal under memory profiler (which is why I missed the stray delete in the copy ctor, it's never called. Once called, it crashed too).

The next batch were compiler diagnostics, I had to fix some of them to even get your code to compile.

The last batch was just things that stood out.
Last edited on
I'm sorry I missunderstood you. I am going to take a close look at my code. I am not getting runtime errors with these, and my code never had trouble compiling, which has me confused. We are using a dated IDE though. Again, thank you.
Last edited on
Would you mind explaining why some of these run time errors are occurring? I am not getting them in my testing (at least not yet) and I don't understand conceptually why they are causing problems. Thank you.
Your still having the issues? You've fixed the problems already stated? Ok, so where exactly is your program crashing, run the code over and over and give us the exact line in the code it breaks.
Would you mind explaining why some of these run time errors are occurring

Because dereferencing a pointer that's not pointing at an object is an error.
Take the last operator+= for example:

char* temp = new char[_len];


This created an array of _len char. its elements may be accessed as temp[0] to temp[_len-1], as you do in the following loop:

1
2
3
4
   for (; i < _len; i++)
    {
        temp[i] = _s[i];
    }


Now the loop ended because i == _len, and there you have

temp[i] = c;


There is no "temp[_len]", it doesn't exist.

Here's what I see:

 ABW: Array bounds write
      This is occurring while in:
            STRING::operator+=(char) [test.cc:311]
                   }
                   
                   cout << c << endl;
            =>     temp[i] = c;
                   
                   delete[] _s;
                   _s = temp;
            main           [test.cc:422]
            __start        [test.ibm-pure.tsk]
      Writing 1 byte to 0x30320f80 in the heap.
      Address 0x30320f80 is 1 byte past end of a malloc'd block at 0x30320f78 of 8 bytes.
      This block was allocated from:
...
            STRING::operator+=(char) [test.cc:304]
               {
                   
                   int i = 0;
            =>     char* temp = new char[_len];
                   for (; i < _len; i++)
                   {
                       temp[i] = _s[i];
            main           [test.cc:422]
            __start        [test.ibm-pure.tsk]

EDIT: I'm an idiot. Thank you.
Last edited on
I received the grade from my project today, I scored 98%! Thank you all for your help. Cubbi thanks for your patience with me, especially when I was being really dense.
Topic archived. No new replies allowed.