C String Proper Type and String Objects Andy
C String, Proper Type, and String Objects Andy Wang COP 4530: Data Structures, Algorithms, and Generic Programming
Lecture Overview • Goal – Design a string class that overcomes the disadvantages of C strings • Roadmap – Critique of C strings – The need for proper type – String objects
In-Class Exercise Write a C function that copies one string to another. void strcpy(char *dest, char *src) { … }
Assumptions of C Strings • Allocated memory char *str; str = malloc(sizeof(char)*11); • Null termination str[10] = “ ” strcpy(str, “ 0123456789”);
What can go wrong? void strcpy(char *copy_cat, char *cat) { int j; for (j = 0; cat[j] != ‘ ’; j++) { copy_cat[j] = cat[j]; } What if the string is copy_cat[j] = ‘ ’; not null } terminated? What if the string is not allocated?
Other String Functions • Still assume null-terminated strings • Still assume allocated memory • Security holes… – Internet worms – System break-ins
The Concept of Proper Type • A proper type should be – Responsible for its own data • Data protected from clients and other programs – Responsible for its own behavior • Make behavior available to clients • Implementation hidden from the public view – Responsible for its own existence • Automatic memory management
C++ Class Objects • Responsible for their own data – Protected or private data – Controlled access through public methods • Responsible for their own behavior – Public methods • Responsible for their own existence – Constructors/deconstructors
In-Class Exercise: String Class namespace rcl { class String { // friend… public: // … private: // … }
String Class class String { // friend iostream operators public: // constructors/destructors // operators // builders // data accessors (const) // string comparison function private: // data // helper methods } // equality and order comparison operators
Private Data char *str; unsigned int size; // equal to C strlen(); class String { // friend iostream operators public: // constructors/destructors // operators // builders // data accessors (const) // String comparison function private: // data // helper methods } // equality and order comparison operators
Data Accessors unsigned int Size() const; unsigned int Length() const; char Element(unsigned int n) const; class String { // friend iostream operators public: // constructors/destructors // operators // builders // data accessors (const) // String comparison function private: // data // helper methods } // equality and order comparison operators
Data Accessors unsigned int String: : Size() const { return size; } unsigned int String: : Length() const { // note: strlen takes char*; therefore, we need to implement an operator that converts String to char*. return strlen(*this); }
In-Class Exercise: Element Return the nth character of the String. Watch out for boundary cases. char String: : Element(unsigned int n) const { … }
Element char String: : Element(unsigned int n) const { char ch; if ((size == 0) || (n >= size)) { return ‘ ’; } else { return str[n]; } }
String Comparison Function static int Str. Cmp(const String&, const String&) class String { // friend iostream operators public: // constructors/destructors // operators // builders // data accessors (const) // String comparison function private: // data // helper methods } // equality and order comparison operators
Str. Cmp int String: : Str. Cmp(const String& S 1, const String& S 2) { if ((S 1. Size() == 0) && (S 2. Size() == 0)) { return 0; } else if ((S 1. Size() == 0) && (S 2. Size() != 0)) { return – 1; } else if ((S 1. Size() != 0) && (S 2. Size() == 0)) { return 1; } else { return (strcmp(S 1. str, S 2. str); } }
Equality Operators int operator==(const String& S 1, const String& S 2); int operator!=(const String& S 1, const String& S 2); int operator<=(const String& S 1, const String& S 2); int operator>(const String& S 1, class String { // friend iostream operators const String& S 2); public: // constructors/destructors // operators // builders // data accessors (const) // String comparison function private: // data // helper methods } // equality and order comparison operators
Comparison Operators int operator==(const String& S 1, const String& S 2) { return (String: : Str. Cmp(S 1, S 2) == 0); } int operator!=(const String& S 1, const String& S 2) { return (String: : Str. Cmp(S 1, S 2) != 0); } int operator>(const String& S 1, const String& S 2) { return (String: : Str. Cmp(S 1, S 2) > 0); }
Comparison Operators int operator>=(const String& S 1, const String& S 2) { return (String: : Str. Cmp(S 1, S 2) >= 0); } int operator<(const String& S 1, const String& S 2) { return (String: : Str. Cmp(S 1, S 2) < 0); } int operator<=(const String& S 1, const String& S 2) { return (String: : Str. Cmp(S 1, S 2) <= 0); }
Helper Methods static void Error(const char*); static char* newstr(int n); static int xstrlen(const char*); static void xstrcpy(char *, const char*); void Clear(); { void Clone(const String& S); class// String friend iostream operators public: // constructors/destructors // operators // builders // data accessors (const) // String comparison function private: // data // helper methods } // equality and order comparison operators
Error void String: : Error(const char* msg) { cerr << “** String error: “ << msg << ‘n’; exit(EXIT_FAILURE); }
In-Class Exercise: newstr It creates a new String of size n (C String with an array size of n + 1). void String: : newstr(int n) { … }
newstr char *String: : newstr(int n) { char *Cptr = 0; if (n >= 0) { Cptr = new char[n + 1]; if (Cptr == 0) { Error(“memory allocation failure”) } Cptr[n] = ‘ ’; } return Cptr; }
xstrlen int String: : xstrlen(const char* s) { int len; if (s != 0) { // check for null pointer for (len = 0; s[len] != ‘ ’; ++len) { } } return len; }
xstrcpy void String: : xstrcpy(char *dest, const char *src) if (src != 0) { // check for null pointer if (dest != 0) { // check for null pointer int j; for (j = 0; src[j] != ‘ ’; ++j) { dest[j] = src[j]; } dest[j] = ‘ ’; } else { Error(“xstrcpy: null destination”); } } }
In-Class Exercise: Clear If the String has storage allocated, delete it, and set the storage pointer and size to zero. void Clear() { … }
Clear void String: : Clear() { if (str) { delete[] str; str = 0; size = 0; } }
In-Class Exercise: Clone If makes a copy of the parameter S. void *String: : Clone(const String& S) { … }
Clone void String: : Clone(const String& S) { size = S. Size(); if (size > 0) { str = newstr(size); xstrcpy(str, S. str); } else { str = 0; } }
Operators String &operator=(const String& S); char &operator[] (unsigned int I) const; operator const char* () const class String { // friend iostream operators public: // constructors/destructors // operators // builders // data accessors (const) // String comparison function private: // data // helper methods } // equality and order comparison operators
Operator= String &String: : operator=(const String& S) { if (this != &S) { Clear(); Clone(S); } return *this; }
Operator[] char& String: : operator[] (unsigned int n) const { if ((size == 0) || (n > size)) { Error(“index out of range”); } return str[n]; }
Operator const char* String: : operator const char* () const { return str; }
Builder Functions void Wrap(const char* Cptr); void Get. Line(istream& inl); int Set. Size(unsigned int sz, char fill); class String { // friend iostream operators public: // constructors/destructors // operators // builders // data accessors (const) // String comparison function private: // data // helper methods } // equality and order comparison operators
Wrap void String: : Wrap(const char* Cptr) { Clear(); if (Cptr) { size = xstrlen(Cptr); str = newstr(size); xstrcpy(str, Cptr); } }
Get. Line void String: : Get. Line(istream& is) { unsigned int curr_size = 0, buff_size = init_buff_size; char *buffer = new char[buff_size + 1]; for (char x = is. get(); ((x != ‘n’) && (!is. eof()); x = is. get()) { if (curr_size == buff_size) { buff_size *= 2; char *newbuffer = new char[buff_size + 1]; // copy buffer to newbuffer delete[] buffer; buffer = newbuffer; } buffer[curr_size++] = x; } buffer[curr_size] = ‘ ’; Wrap(buffer); delete[] buffer; }
Set. Size int String: : Set. Size(unsigned int sz, char fill) { if (sz != Size()) { char *newdata = newstr(sz); if (newdata == 0) return 0; unsigned int j; if (sz < Size()) { for (j = 0; j < sz; ++j) { newdata[j] = str[j]; } } else { for (j = 0; j < Size(); ++j) { newdata[j] = str[j]; } for (j = Size(); j < sz; ++j) { newdata[j] = fill; } delete[] str; str = newdata; size = sz; } } return 1; }
Constructors/Destructors String(); explicit String(const char* Cptr); ~String(); String (const String &S); class String { // friend iostream operators public: // constructors/destructors // operators // builders // data accessors (const) // String comparison function private: // data // helper methods } // equality and order comparison operators
Constructors / Deconstructors String: : String() : str(0), size(0) {} String: : String(const char *Cptr) : str(0), size(0) { Wrap(Cptr); } String: : String(const String& S) { Clone(S); } String: : ~String() { if (str) delete[] str; }
I/O Operators friend ostream& operator<<(ostream& os, const String& S); friend istream& operator>>(istream& is, String S); class String { // friend iostream operators public: // constructors/destructors // operators // builders // data accessors (const) // String comparison function private: // data // helper methods } // equality and order comparison operators
Operator<< ostream& operator<<(ostream& os, const String& S) { os << S. str; return os; }
Operator>> istream& operator>>(istream &is, String &S) { unsigned int curr_size = 0; buff_size = init_buff_size; char x; // skip clear space char *buffer = String: : newstr(buff_size); buffer[curr_size++] = x; for (x = is. peek(); (// x is not white space or eof); x = is. peek()) { if (curr_size == buff_size) { buff_size *= 2; char *newbuffer = String: : newstr(buff_size); // copy buffer into newbuffer delete[] buffer; buffer = newbuffer; } buffer[curr_size++] = x; is. get(); } buffer[curr_size] = ‘ ’; S. Wrap(buffer); delete[] buffer; return is; }
- Slides: 43