Oops... didn't mean to write "destructor". I fixed my post above.
A "string" is just an array of
char stored somewhere in memory, where the last character is the "nul" character.
1 2 3 4
|
Name Type Value Meaning
NULL pointer 0 An invalid pointer value -- it cannot be dereferenced.
nul char '\0' The ASCII NUL character
empty string char[] "" A string containing no characters other than the terminating nul.
|
In C and C++, all arrays are handled via
pointers. First, you must know something about memory spaces. What follows is simplified tremendously.
Memory is nothing but a numbered array of cells. The operating system controls which of those cells your program uses. Within your program, there are cells that store the machine code that tells the computer what to do. This is traditionally called the "text" segment. There are also cells that store data literals that you write into your program -- like
"Hello world!"
. This is traditionally called the "data" segment. There are cells that are used to store temporary data -- variables you create inside functions and the like. This is called the "stack". And finally, there are cells that you access with
new and
delete. This is called the "heap".
In both the following cases, the double-quoted stuff on the right is an array of
char stored somewhere in your program's data segment. The first example assigns the address of the very first character in the array to the pointer variable
greeting. The second example makes a copy of the string "May the road rise to meet you!" (which is in the data segment) into a variable created on the stack.
1 2
|
const char* greeting = "Hello, handsome!";
char farewell[] = "May the road rise to meet you!";
|
In both cases, you now have access to two
pointers:
-
greeting, which points to the 'H' in the string "Hello, handsome" in the data segment;
-
farewell, which points to the 'M' in the string "May the road rise to meet you!" on the stack (notice now that there are
two copies of the string "May the road rise to meet you!" in your program -- one in the data segment and one on the stack).
Hopefully that will help when you think about strings now...
The reason you don't need to explicitly access
nstring[ nlength - 1 ]
is that, while correct, it is always going to be zero.
For example:
1 2 3 4 5 6 7 8 9 10 11 12
|
MyString::MyString(const char *input)
{
// Count how many characters we need to store the input string
for (nlength = 0; input[ nlength ] != 0; nlength++);
// Also count the terminating nul character
nlength += 1;
// Get space from the heap for the string
nstring = new char[ nlength ];
// Copy all the characters, including the terminating nul, into our heap space
for (int i = 0; i < nlength; i++)
nstring[ i ] = input[ i ];
}
|
If
input points to the 'B' in the string "Bob" (which is the same as the array
{ 'B', 'o', 'b', '\0' }
, then line 4 will count three non-nul characters. Line 6 will add one to that, so that
nlength is four -- the exact number of characters needed to store the string and its nul-terminator. Next we need somewhere to put the copy, so we get a chunk of cells from the heap on line 8. Finally, lines 10 and 11 copy the input array to our chunk of cells on the heap.
Hmm, one other thing:
nstring[ i ]
is just a fancy shortcut for
*(nstring + i)
.
Hope this helps.