CSimpleString Class

This is the class:

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
// Soln8_02.cpp
#include <iostream>                   // For stream input/output
#include <cstring>

using std::cout;
using std::endl;

class CSimpleString
{
private:
   size_t len;
   char* buff;
public:
   CSimpleString(const char* p = nullptr);
   CSimpleString(const CSimpleString& s);
   ~CSimpleString();

   CSimpleString& operator=(const CSimpleString& rhs);
   void print();
};

// Constructor
CSimpleString::CSimpleString(const char* p) : len(0), buff(nullptr)
{
   if (p)
   {
      len = strlen(p);
      if (len)
      {
         buff = new char[len + 1];
         strcpy_s(buff, len + 1, p);
      }
   }
}

// Copy constructor
CSimpleString::CSimpleString(const CSimpleString& s)
{
   len = s.len;
   buff = new char[len + 1];
   strcpy_s(buff, len + 1, s.buff);
}

// Destructor
CSimpleString::~CSimpleString()
{
   delete [] buff;
}

// Assignment operator - does not deal with str = str
CSimpleString& CSimpleString::operator=(const CSimpleString& rhs)
{
   len = rhs.len;
   delete buff;
   buff = new char[len + 1];
   strcpy_s(buff, len + 1, rhs.buff);

   return *this;
}

void CSimpleString::print()
{
   cout << buff;
}

int main()
{
   CSimpleString s1("hello");
   CSimpleString s2("goodbye");
   cout << "s1: \"";
   s1.print();
   cout << "\"" << endl;

   cout << "s2: \"";
   s2.print();
   cout << "\"" << endl;

   cout << " After executing s2 = s1:" << endl;
   s2 = s1;

   cout << "s1 = \"";
   s1.print();
   cout << "\"" << endl;

   cout << "s2 = \"";
   s2.print();
   cout << "\"" << endl;

   return 0;
}


What is the purpose of the if statements here:

1
2
3
4
5
6
7
8
9
10
11
12
CSimpleString::CSimpleString(const char* p) : len(0), buff(nullptr)
{
   if (p)
   {
      len = strlen(p);
      if (len)
      {
         buff = new char[len + 1];
         strcpy_s(buff, len + 1, p);
      }
   }
}


Aren't they useless?
Ir means that if p has zero length - i.e. if the first character is '\0' - then lines 8 - 9 won't execute.
I know what it protects but one if statement would be sufficient, the second would protect against both. Also if you send a pointer to the constructor I doubt you would make that mistake.
I know what it protects but one if statement would be sufficient, the second would protect against both.


No. Those two if statements are checking for different things.

The first is checking that the address stored by the pointer is not NULL. We need to do this before calling strlen, because strlen will likely crash if you pass it a NULL pointer.

The second is checking that p does not point to a string of zero length.

Also if you send a pointer to the constructor I doubt you would make that mistake.

If I had a dollar for ever time I've seen a program crash because of a NULL pointer being passed somewhere it shouldn't have been, I'd own this entire planet and everything on it, and the universe would still owe me.
Last edited on
Here it is more updated:

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
// Soln8_03.cpp

#include <iostream>                   // For stream input/output
#include <cstring>

using std::cout;
using std::endl;

class CSimpleString
{
private:
   size_t len;
   char* buff;
public:
   CSimpleString(const char* p = nullptr);
   CSimpleString(const CSimpleString& s);

   CSimpleString(char c, int count=1);
   CSimpleString(int i);

   ~CSimpleString();

   CSimpleString& operator=(const CSimpleString& rhs);
   void print();
};

// Contructor - repeated given character
CSimpleString::CSimpleString(char c, int count) : buff(nullptr)
{
   len = count;
   if (len)
   {
      buff = new char[len + 1];
      memset(buff, c, len);
      buff[len] = '\0';
   }
}

// Constructor - from an integer
CSimpleString::CSimpleString(int i) : buff(nullptr)
{
   char sTmp[20];
   _itoa_s(i, sTmp, _countof(sTmp), 10);

   len = strlen(sTmp);
   if (len)
   {
      buff = new char[len + 1];
      strcpy_s(buff, len + 1, sTmp);
   }
}

// Constructor
CSimpleString::CSimpleString(const char* p) : len(0), buff(nullptr)
{
   if (p)
   {
      len = strlen(p);
      if (len)
      {
         buff = new char[len + 1];
         strcpy_s(buff, len + 1, p);
      } 
   }
}

// Copy constructor
CSimpleString::CSimpleString(const CSimpleString& s)
{
   len = s.len;
   buff = new char[len + 1];
   strcpy_s(buff, len + 1, s.buff);
}

// Destructor
CSimpleString::~CSimpleString()
{
   delete [] buff;
}

// Assignment operator - does not deal with str = str
CSimpleString& CSimpleString::operator=(const CSimpleString& rhs)
{
   len = rhs.len;
   delete buff;
   buff = new char[len + 1];
   strcpy_s(buff, len + 1, rhs.buff);

   return *this;
}

void CSimpleString::print()
{
   cout << buff;
}

int main()
{
   CSimpleString s1("hello");
   CSimpleString s2;

   s2 = s1;
   CSimpleString marker('*', 30);
   marker.print();
   cout << endl;

   cout << "s1 = \"";
   s1.print();

   cout << "\"" << endl;

   cout << "s2 = \"";
   s2.print();
   cout << "\"" << endl;

   int n = 7890;

   CSimpleString nStr(n);

   cout << n << " as a string is \"";
   nStr.print();
   cout << "\"" << endl;

   marker.print();
   cout << endl;

   return 0;
}


A few questions:

In

1
2
3
4
5
6
7
8
9
10
11
// Contructor - repeated given character
CSimpleString::CSimpleString(char c, int count) : buff(nullptr)
{
   len = count;
   if (len)
   {
      buff = new char[len + 1];
      memset(buff, c, len);
      buff[len] = '\0';
   }
}


How does buff[len]='\0'; work, how can you use the subscript operator on a pointer, is it treated as an array?
new char buff[len+1]

Why does it add 1 to the len if the terminating sequence is added to size of len and not one more then it???

Thanks for helping!
Last edited on
I know what it protects but one if statement would be sufficient, the second would protect against both. Also if you send a pointer to the constructor I doubt you would make that mistake.


Who says it would be a mistake? Take a look at the default argument for the constructor in the definition of the class.
HOW COULD I HAVE MISSED THAT, FAIL...

That's the stupidest mistake I think I have ever made on this forum. *facepalm*
How does buff[len]='\0'; work, how can you use the subscript operator on a pointer, is it treated as an array?

Yes. The name of an array is always a pointer to the first element in an array. Semantically, the two things are interchangeable - you can use a subscript operator on an pointer, and you can dereference the name of an array.
Why does it add 1 to the len if the terminating sequence is added to size of len and not one more then it???

Arrays in C and C++ start at index 0. So if you specify the size of an array to be x, then the indices of its elements are 0 to (x - 1).

Oh yea I forgot they start at 0, thanks!
Topic archived. No new replies allowed.