/*
ProgEx32 -- A More Memory Efficient String Class. C++ Compilation/Linking
As mentioned in ProgEx31, we are going to try to alter our String Class so it
isn't always thrashing around in memory allocating/deallocating memory blocks.
To do that we'll add one more private data member to our class which will keep
track of the current maximum number of characters the String can hold. We'll
name the data member 'iAllowableCharacterCount', and it will be one less than
whatever the present memory allocation is. Another change is that we'll
define an equate named MINIMUM_ALLOCATION. Unlike in ProgEx31's Uninitialized
Constructor where no memory allocations occured, in this example a declaration
like so...
String s1;
will cause the Constructor to allocate an amount of memory equal to the above
equate, which in this program has been set to 8 bytes. Yet another change is
that whenever the various member functions determine that not enough memory is
indicated by this->iAllowableCharacterCount, rather than only re-allocating
the needed amount, the needed amount will be multiplied by another equate
named EXPANSION_FACTOR so as to anticipate future String growth. In this
program EXPANSION_FACTOR has been set to 2. Below is an exact copy of our
String Declaration header showing what our String Class now looks like...
//Strings.h Class Declaration For String Class So Far
#if !defined(STRINGS_H) //This is an inclusion guard to guard against other
#define STRINGS_H //files that may have previously included this file.
#define EXPANSION_FACTOR 2 //This is the factor to anticipate future space needs
#define MINIMUM_ALLOCATION 8 //Allocations will be at least this number
class String
{
public:
String(); //Uninitialized Constructor - Does nothing
String(const char); //Constructor Initializes String With char
String(const char*); //Constructor Initializes String With char*
String(const String&); //Constructor Initializes String With Another String (Copy Constructor)
String& operator=(const char); //Operator= for assigning char to String
String& operator=(const char*); //Operator= for assigning literal or char* to String
String& operator=(const String&); //Operator= for assigning 2nd String to 1st
String& operator+(const char); //Operator+ for adding char to String
String& operator+(const char*); //Operator+ for adding A Null Terminated Ascii String Array
String& operator+(const String&); //Operator+ for adding Another String To The String
int LenStr(void); //Returns the length of what's pointed to by pStrBuffer
char* lpStr(void); //Returns Address of String data Member >> this->lpStr()
~String(); //String Destructor
private:
char* pStrBuffer; //This char* member holds the address of an allocated String
int iAllowableCharacterCount; //Max number of chars that will fit in presently allocated buffer
};
#endif
To see the improvement, lets run the example we had in the last ProgEx where
we concatenated a few letters of the English alphabet together, except this
time we'll do the whole alphabet. If we would have done that in the last
example (ProgEx31) we would have had 26 allocations and 26 releases. You can
find out for yourself in the output below how the changes we made affects this
here. My comments on the code will follow the example and the output
immediately beneath...
*/
#include <stdio.h> //The String declaration below 'String s1' will cause an 8
#include "Strings.h" //byte memory allocation. The logic in the for loop will
//cause calls to the overloaded operator+ member, and that
int main(void) //member function will check the present allowable char
{ //count against the present count of chars accumulated in
String s1; //the String. Only when the char count reaches 7 will the
//function re-allocate memory and release the original 8
for(unsigned int i=65; i<91; i++) //bytes. However, it will double the
{ //present maximum char count and round to a
s1=s1+i; //16 byte paragraph boundary when it
printf("\n%s\n",s1.lpStr()); //calculates its new memory allocation size.
} //Therefore, the original 8 byte allocation will be doubled
getchar(); //to 16 bytes. The loop will continue running, accumulating
//chars, and checking bytes until it reaches 15 chars, and
return 0; //then it will re-allocate again - but this last time for
} //32 bytes. Therefore, there will only need to be two
//two re-allocations after the original 8 byte allocation
//to finish the alphabet-not 26 like in our first example!
/* --Output--
(You'll Need About 325 Lines In Your Console Window Buffer)
Entering Uninitialized String Constructor
pStrBuffer = 4079520
this->iAllowableCharacterCount = 7
Leaving Uninitialized String Constructor
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 0
this->iAllowableCharacterCount = 7
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = A
Early Exit Leaving String::operator=(const String& strRight)
A
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 1
this->iAllowableCharacterCount = 7
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = AB
Early Exit Leaving String::operator=(const String& strRight)
AB
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 2
this->iAllowableCharacterCount = 7
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABC
Early Exit Leaving String::operator=(const String& strRight)
ABC
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 3
this->iAllowableCharacterCount = 7
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCD
Early Exit Leaving String::operator=(const String& strRight)
ABCD
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 4
this->iAllowableCharacterCount = 7
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDE
Early Exit Leaving String::operator=(const String& strRight)
ABCDE
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 5
this->iAllowableCharacterCount = 7
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEF
Early Exit Leaving String::operator=(const String& strRight)
ABCDEF
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 6
this->iAllowableCharacterCount = 7
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFG
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFG
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 7
this->iAllowableCharacterCount = 7
!!!!! Memory Wasn't Adequate. We Need To Re-Allocate!
this->iAllowableCharacterCount = 15
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGH
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGH
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 8
this->iAllowableCharacterCount = 15
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHI
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHI
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 9
this->iAllowableCharacterCount = 15
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJ
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJ
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 10
this->iAllowableCharacterCount = 15
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJK
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJK
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 11
this->iAllowableCharacterCount = 15
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKL
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKL
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 12
this->iAllowableCharacterCount = 15
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLM
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLM
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 13
this->iAllowableCharacterCount = 15
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMN
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMN
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 14
this->iAllowableCharacterCount = 15
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNO
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNO
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 15
this->iAllowableCharacterCount = 15
!!!!! Memory Wasn't Adequate. We Need To Re-Allocate!
this->iAllowableCharacterCount = 31
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOP
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOP
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 16
this->iAllowableCharacterCount = 31
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOPQ
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOPQ
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 17
this->iAllowableCharacterCount = 31
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOPQR
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOPQR
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 18
this->iAllowableCharacterCount = 31
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOPQRS
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOPQRS
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 19
this->iAllowableCharacterCount = 31
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOPQRST
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOPQRST
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 20
this->iAllowableCharacterCount = 31
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOPQRSTU
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOPQRSTU
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 21
this->iAllowableCharacterCount = 31
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOPQRSTUV
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOPQRSTUV
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 22
this->iAllowableCharacterCount = 31
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOPQRSTUVW
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOPQRSTUVW
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 23
this->iAllowableCharacterCount = 31
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOPQRSTUVWX
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOPQRSTUVWX
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 24
this->iAllowableCharacterCount = 31
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOPQRSTUVWXY
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOPQRSTUVWXY
Entering String& String::operator+(const char ch) For Adding A char To A String
this->LenStr() = 25
this->iAllowableCharacterCount = 31
Memory Was Adequate. Didn't Need To Re-Allocate!
Leaving String& String::operator+(const char ch) For Adding A char To A String
Entering operator=(const String& strRight) Assigns Another String To A String
strRight.pStrBuffer = ABCDEFGHIJKLMNOPQRSTUVWXYZ
Early Exit Leaving String::operator=(const String& strRight)
ABCDEFGHIJKLMNOPQRSTUVWXYZ
*/
/* ....continued from above
I'd call this a considerable improvement. We've cut down the memory alloc-
ations from 16 down to 3. Obviously, if MINIMUM_ALLOCATION was set high
enough the concatenation of the alphabet wouldn't take any more re-allocations
at all. However, I suppose this could be construed as cheating! In any case
achieving this improvement only made the code a small amount more complicated.
The way things are now all the member functions that either assign Strings or
add to them (concatenating operator+ members) will have to compare the
parameter to the function call with the amount of memory presently held as
determined by the new iAllowableCharacterCount private member. If enough
memory is being held, rather than a re-allocation/de-allocation sequence the
parameter is simply copied to the existing memory. If enough memory isn't
present then a new allocation will be made after multiplying the present need
by EXPANSION_FACTOR. For example, allocations could follow a sequence of 8,
16, 32, 64, 128.... etc.
String& String::operator+(const char ch)
{
int iLen,iNewSize;
char* pNew;
iLen=strlen(this->pStrBuffer);
if(iLen<this->iAllowableCharacterCount)
{
this->pStrBuffer[iLen]=ch;
this->pStrBuffer[iLen+1]='\0';
}
else
{
iNewSize=((this->iAllowableCharacterCount*EXPANSION_FACTOR)/16+1)*16;
pNew=new char[iNewSize];
this->iAllowableCharacterCount=iNewSize-1;
strcpy(pNew,this->pStrBuffer);
delete [] this->pStrBuffer;
this->pStrBuffer=pNew;
this->pStrBuffer[iLen]=ch;
this->pStrBuffer[iLen+1]='\0';
}
return *this;
}
This term...
iNewSize=((this->iAllowableCharacterCount*EXPANSION_FACTOR)/16+1)*16;
has an integer division within it that in C/C++ languages ends up usually in
an integer truncation. For example, when our String above reached...
ABCDEFG
...and we had this situation...
this->LenStr() = 7
this->iAllowableCharacterCount = 7
...the formula above would have resolved to this...
iNewSize=((7*2)/16+1)*16;
...which due to integer truncation resolves to this...
iNewSize = 16;
*/
Strings.h
//Strings.h Class Declaration For String Class So Far
#if !defined(STRINGS_H) //This is an inclusion guard to guard against other
#define STRINGS_H //files that may previously included this file.
#define EXPANSION_FACTOR 2 //This is the factor to anticipate future space needs
#define MINIMUM_ALLOCATION 8 //Allocations will be at least this number
class String
{
public:
String(); //Uninitialized Constructor - Does nothing
String(const char); //Constructor Initializes String With char
String(const char*); //Constructor Initializes String With char*
String(const String&); //Constructor Initializes String With Another String (Copy Constructor)
String& operator=(const char); //Operator= for assigning char to String
String& operator=(const char*); //Operator= for assigning literal or char* to String
String& operator=(const String&); //Operator= for assigning 2nd String to 1st
String& operator+(const char); //Operator+ for adding char to String
String& operator+(const char*); //Operator+ for adding char* to String (char* Points To Null Terminated Ascii String Array
String& operator+(const String&); //Operator+ for adding Another String To The String
int LenStr(void); //Returns the length of what's pointed to by pStrBuffer
char* lpStr(void); //Returns Address of String data Member >> this->lpStr()
~String(); //String Destructor
private:
char* pStrBuffer; //This char* member holds the address of an allocated String
int iAllowableCharacterCount; //Max number of chars that will fit in presently allocated buffer
};
#endif
Strings.cpp
//Strings.cpp
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "Strings.h"
/* ****************************************************************************/
// String::String() This is an uninitialized String Constructor. It is
// called when a declaration of a String such as this occurs...
//
// String s1;
//
// Note that in this version of the Uninitialized String Constructor it actually
// allocates memory. The amount it allocates is MINIMUM_ALLOCATION, whatever
// that is set to. Then it calculates and stores the maximum number of chars
// that can be stored in a buffer of that size taking into consideration the
// need for a final NULL byte. It stores the maximum allowed char count in
// this->iAllowableCharacterCount.
/* ****************************************************************************/
String::String() //Uninitialized Constructor
{
printf("Entering Uninitialized String Constructor\n");
pStrBuffer=new char[MINIMUM_ALLOCATION];
pStrBuffer[0]='\0';
printf(" pStrBuffer = %u\n",(unsigned int)pStrBuffer);
this->iAllowableCharacterCount=MINIMUM_ALLOCATION-1;
printf(" this->iAllowableCharacterCount = %u\n",this->iAllowableCharacterCount);
printf("Leaving Uninitialized String Constructor\n\n");
}
/* ****************************************************************************/
// String::String(const char ch) //Constructor: Initializes with char
//
// This version of an overloaded String constructor would be called by a
// construction such as this...
//
// String s('R');
//
// In C++ this type of construction generalizes to any type of object whatsoever
// so if you want to initialize a simple int this will work...
//
// int iNum(5);
//
// The above will declare an int variable (object) iNum and assign 5 to it.
/* ****************************************************************************/
String::String(const char ch) //Constructor: Initializes with char
{
pStrBuffer=new char[MINIMUM_ALLOCATION];
pStrBuffer[0]=ch;
pStrBuffer[1]='\0';
iAllowableCharacterCount=MINIMUM_ALLOCATION-1;
}
/* ****************************************************************************/
// String::String(const char* pStr) //Constructor: Initializes with char*
//
// This String Class Constructor Overload would be called by a construction such
// as this...
//
// String s1("Hello, World!");
//
// First the string length ( strlen() ) of the parameter is determined, then a
// memory allocation is done where the length is rounded up to the next nearest
// 16 byte paragraph boundary. Then the char* parameter is copied to the
// storage and the allocated memory size is set in the iAllowableCharacterCount
// private member variable.
/* ****************************************************************************/
String::String(const char* pStr) //Constructor: Initializes with char*
{
int iLen,iNewSize;
iLen=strlen(pStr);
iNewSize=(iLen/16+1)*16;
pStrBuffer=new char[iNewSize];
this->iAllowableCharacterCount=iNewSize-1;
strcpy(pStrBuffer,pStr);
}
/* ****************************************************************************/
// String(const String& s) //Copy Constructor - Initialize with another String
//
// This constructor overload will be triggered by a statement such as this...
//
// String s1 = "Some String";
// String s2(s1);
//
// What you have here is a String being initialized with the contents of a
// second String. What has to happen is that seperate storage has to be set up
// in the first String so as to accomodate the copying of the second String to
// the first.
/* ****************************************************************************/
String::String(const String& s) //Constructor Initializes With Another String,
{ //i.e., Copy Constructor
int iLen,iNewSize;
iLen=strlen(s.pStrBuffer);
iNewSize=(iLen/16+1)*16;
this->pStrBuffer=new char[iNewSize];
this->iAllowableCharacterCount=iNewSize-1;
strcpy(this->pStrBuffer,s.pStrBuffer);
}
/* ****************************************************************************/
// String& String::operator=(const char ch) This version is somewhat differnt
// from the last in that it no longer deletes [] the existing buffer. The
// existing buffer could be any size really; its length would be stored in
// this->iAllowableCharacterCount. What this version does is retain the memory
// allocation - whatever it is - and simply stores the parameter char ch at
// offset 0 in the buffer and the required NULL at offset 1.
/* ****************************************************************************/
String& String::operator=(const char ch) //Overloaded operator = for assigning a character to a String
{
printf("Entering Overloaded operator=(const char ch) For Assigning A char To A String\n");
this->pStrBuffer[0]=ch;
this->pStrBuffer[1]='\0';
printf("Leaving Overloaded operator=(const char ch) For Assigning A char To A String\n\n");
return *this;
}
/* ****************************************************************************/
// String& String::operator=(const char* pStr) To assign a char* to
// pStrBuffer we first need to determine the length of pStr, then compare that
// length (iLen ) to the allowable char count in this->iAllowableCharacterCount.
// If the former ( pStr ) is less than the latter we can simply copy pStr to the
// String's buffer. If not, we must allocate a new buffer then delete [] the
// old one. The term (iLen/16+1)*16 will always round memory requirements up to
// paragraph ( 16 byte ) boundaries. Once a new allocation is made the para-
// meter is copied to the new buffer and the iAllowableCharacterCount member set
// to the new value.
/* ****************************************************************************/
String& String::operator=(const char* pStr) //Constructor For If Pointer To
{ //Asciiz String Parameter
int iLen,iNewSize;
printf("Entering operator= For Assigning A char*\n");
iLen=strlen(pStr);
if(iLen<this->iAllowableCharacterCount)
strcpy(pStrBuffer,pStr);
else
{
delete [] pStrBuffer;
iNewSize=(iLen/16+1)*16;
pStrBuffer=new char[iNewSize];
this->iAllowableCharacterCount=iNewSize-1;
strcpy(pStrBuffer,pStr);
}
printf(" pStrBuffer = %u\t%s\n",(unsigned int)pStrBuffer,pStrBuffer);
printf("Leaving operator= For Assigning A char*\n\n");
return *this;
}
/* ****************************************************************************/
// String& String::operator=(const String& strRight)
//
// This overloaded operator= member is triggered when an assignment statement
// connects to Strings. If the String on the right is the same as the one on
// the left, the function exits early by simply returning *this (what's stored
// at this). Otherwise, the function tests to see if the presently existing
// storage is adequate to store the String passed as a parameter (the one on the
// right side of the assignment statement). If it is the parameter is simply
// copied to pStrBuffer. If it isn't new storage is allocated before doing the
// copy, and the new length of the buffer is stored in iAllowableCharacterCount.
/* ****************************************************************************/
String& String::operator=(const String& strRight) //Overloaded operator = for
{ //assigning another String to
int iRightLen,iNewSize; //a String
printf("Entering operator=(const String& strRight) Assigns Another String To A String\n");
printf(" strRight.pStrBuffer = %s\n",strRight.pStrBuffer);
if(this==&strRight)
{
printf("Early Exit Leaving String::operator=(const String& strRight)\n");
return *this;
}
iRightLen=strlen(strRight.pStrBuffer);
if(iRightLen < this->iAllowableCharacterCount)
strcpy(pStrBuffer,strRight.pStrBuffer);
else
{
iNewSize=(iRightLen/16+1)*16;
delete [] this->pStrBuffer;
this->pStrBuffer=new char[iNewSize];
this->iAllowableCharacterCount=iNewSize-1;
strcpy(pStrBuffer,strRight.pStrBuffer);
}
printf("Leaving operator=(const String& strRight) Assigns Another String To A String\n\n");
return *this;
}
/* ****************************************************************************/
// String& String::operator+(const char ch) Overloaded operator + (Adds char)
//
// This member either adds a char to a NULL String or concatenates it onto the
// end of an existing String. First it checks to see if the length of the
// String in its buffer (this->pStrBuffer) < this->iAllowableCharacterCount. If
// it is then the char is simply added onto the end of the existing String. If
// it isn't a larger String is allocated and the existing String is copied to
// it. Then the existing String is released and the char is added to the end of
// the new String. Finally, what's stored at this (*this) is returned.
/* ****************************************************************************/
String& String::operator+(const char ch) //Overloaded operator + (Puts char in
{ //String)
int iLen,iNewSize;
char* pNew;
printf("\nEntering String& String::operator+(const char ch) For Adding A char To A String\n");
iLen=strlen(this->pStrBuffer);
printf(" this->LenStr() = %u\n",this->LenStr());
printf(" this->iAllowableCharacterCount = %u\n",this->iAllowableCharacterCount);
if(iLen<this->iAllowableCharacterCount)
{
printf(" Memory Was Adequate. Didn't Need To Re-Allocate!\n");
this->pStrBuffer[iLen]=ch;
this->pStrBuffer[iLen+1]='\0';
}
else
{
printf(" !!!!! Memory Wasn't Adequate. We Need To Re-Allocate!!!!!\n");
iNewSize=((this->iAllowableCharacterCount*EXPANSION_FACTOR)/16+1)*16;
pNew=new char[iNewSize];
this->iAllowableCharacterCount=iNewSize-1;
strcpy(pNew,this->pStrBuffer);
delete [] this->pStrBuffer;
this->pStrBuffer=pNew;
this->pStrBuffer[iLen]=ch;
this->pStrBuffer[iLen+1]='\0';
printf(" this->iAllowableCharacterCount = %u\n",this->iAllowableCharacterCount);
}
printf("Leaving String& String::operator+(const char ch) For Adding A char To A String\n\n");
return *this;
}
/* ****************************************************************************/
// String& String::operator+(const char* pChar) -- Adds char* to String
//
// This overloaded operator+ will be called by a construction such as this...
//
// String s1 = "John ";
//
// s1 = s1 + "Jones";
//
// which is equivalent to...
//
// s1.operator+("Jones");
//
// The 1st thing the function does is find out the total length of the existing
// String plus the length of the String to be added, i.e., the parameter pChar.
// If this total length, i.e., iLen, is less than this->iAllowableCharacterCount
// then the code must next determine whether or not anything is already stored
// at this->pStrBuffer. If pStrBuffer points to a NULL String the parameter
// pChar is simply copied to there. If something is at pStrBuffer then a
// concatenation ( strcat() ) is in order. The same basic logic is followed if
// the combined length of both Strings is such that a new and larger memory
// allocation is needed (see the else at mid point).
/* ****************************************************************************/
String& String::operator+(const char* pChar) //Overloaded operator + (Adds char
{ //literals or pointers to Asciiz
int iLen,iNewSize; //Strings)
char* pNew;
iLen=strlen(this->pStrBuffer)+strlen(pChar);
if(iLen<this->iAllowableCharacterCount) //Can we accomodate both Strings???
{
if(this->pStrBuffer) //Something is already stored in this...
strcat(this->pStrBuffer,pChar); //So Concatenate
else //Its a NULL String
strcpy(this->pStrBuffer, pChar); //So just copy to pStrBuffer
}
else //Can't accomodate both Strings, so a new memory allocation is needed.
{
iNewSize=(iLen*EXPANSION_FACTOR/16+1)*16;
pNew=new char[iNewSize];
this->iAllowableCharacterCount = iNewSize-1;
if(this->pStrBuffer)
{
strcpy(pNew,this->pStrBuffer);
delete [] pStrBuffer;
strcat(pNew,pChar);
}
else
strcpy(pNew,pChar);
this->pStrBuffer=pNew;
}
return *this;
}
/* ****************************************************************************/
// String& String::operator+(const String& strRight) //adds another String
//
// This overloaded operator+ will be called by a construction such as this...
//
// String s1 = "John ";
// String s2 = "Jones";
// s1 = s1 + s2;
//
// which is equivalent to...
//
// s1.operator+(s2);
//
// The 1st thing the function does is find out the total length of the existing
// String plus the length of the String to be added - the parameter strRight.
// If this total length, i.e., iLen, is less than this->iAllowableCharacterCount
// then the code must next determine whether or not anything is already stored
// at this->pStrBuffer. If pStrBuffer points to a NULL String the parameter
// pChar is simply copied to there. If something is at pStrBuffer then a
// concatenation ( strcat() ) is in order. The same basic logic is followed if
// the combined length of both Strings is such that a new and larger memory
// allocation is needed (see the else at mid point).
/* ****************************************************************************/
String& String::operator+(const String& strRight) //Overloaded operator + Adds
{ //Another String to the left
int iLen,iNewSize; //operand.
char* pNew;
printf("\nEntering operator+(const String& strRight)\n");
printf(" strRight.pStrBuffer = %s\n", strRight.pStrBuffer);
iLen=strlen(this->pStrBuffer) + strlen(strRight.pStrBuffer);
if(iLen < this->iAllowableCharacterCount)
{
if(this->pStrBuffer)
strcat(this->pStrBuffer,strRight.pStrBuffer);
else
strcpy(this->pStrBuffer,strRight.pStrBuffer);
}
else
{
iNewSize=(iLen*EXPANSION_FACTOR/16+1)*16;
pNew=new char[iNewSize];
this->iAllowableCharacterCount=iNewSize-1;
if(this->pStrBuffer)
{
strcpy(pNew,this->pStrBuffer);
delete [] pStrBuffer;
strcat(pNew,strRight.pStrBuffer);
}
else
strcpy(pNew,strRight.pStrBuffer);
this->pStrBuffer=pNew;
}
printf("Leaving operator+(const String& strRight)\n\n");
return *this;
}
/* ************************************************************************** */
// int String::LenStr(void) // Simply return String Length ( strlen() ) of the
// private data member this->pStrBuffer.
/* ************************************************************************** */
int String::LenStr(void)
{
return strlen(this->pStrBuffer);
}
/* ************************************************************************** */
// char* String::lpStr() // Simply return the address of private data member
// this->pStrBuffer. This could be needed for example in printf.
/* ************************************************************************** */
char* String::lpStr()
{
return pStrBuffer;
}
/* ************************************************************************** */
// This is the String Destructor. It is called when a String is being
// destroyed. In such cases it is considered good practice to set any class
// buffers to 0 so the same address does't accidentally get deleted twice.
// Calling delete on a NULL pointer is OK; calling it twice on a non null
// pointer isn't OK, because there may be something else at that address.
/* ************************************************************************** */
String::~String() //String Destructor
{
printf("\nEntering String Destructor\n");
printf(" pStrBuffer = %u\n",(unsigned int)pStrBuffer);
delete [] pStrBuffer;
pStrBuffer=0;
printf("Leaving String Destructor\n\n");
}