kenics.net

Technical notes on perl, python, php, sql, cgi, c/c++, q/kdb+, unix/shell, revision control tools, data structures & algorithms, and their applications into web services and other various forms of software engineering.

C++ writing an original string class

 
 
################################ 
###   strcat strlen strcpy   ### 
################################ 
 
all under std namespace 
#include <cstring> 
 
(ref) 
http://www-indblue.blogspot.jp/2012/03/c-std-1.html 
http://www.cpp-home.com/tutorials/332_1.htm 
 
 
----------------------------------------- 
 
char arr0[2] = {'h','e'}; 
char arr1[4] = {'l','l','o',0}; 
 
cout << strlen(arr0) << endl;   // 2 
cout << strlen(arr1) << endl;   // 3 
 
strcat(arr0,arr1); 
 
cout << arr0 << endl;           // hello 
cout << strlen(arr0) << endl;   // 5 
cout << arr0[5] << endl;        // (empty) NULL 
cout << arr0[6] << endl;        // (unpredictable) 
 
int len = strlen(arr0); 
char* parr = new char[len + 1]; // better get extra 1 bit for NULL terminator 
 
strcpy(parr,arr0);              // will copy till NULL 
 
cout << parr << endl;           // hello 
cout << strlen(parr) << endl;   // 5 
 
cout << strcmp(parr,arr0) << endl; // 0    // returns 0 if equal 
 
parr[3] = 0; 
 
cout << parr << endl;              // hel 
cout << strlen(parr) << endl;      // 3 
cout << strcmp(parr,arr0) << endl; // -1 
 
------------------------------------------- 
 
===> always possible to write strlen, strcmp, strcat by yourself. 
===> just do sizeof(arr)/sizeof(arr[0]) and iterate thru a for loop. 
 
 
############################################# 
###   writing an original string class    ### 
############################################# 
 
a typical interview question. it's a good exercise. 
 
(a) kstring.h 
(b) kstring.cpp 
(c) mystr.cpp 
 
 
----------------------------------  // kstring.h 
 
class kstring{ 
 public: 
  kstring(); 
  kstring(const char*); 
  kstring(const kstring&);    // copy constructor 
  ~kstring(); 
  int getSize(){ return this->len ;} 
  char* kstring::get() const; 
  char at(int) const; 
  kstring& operator=(const kstring&);  // return type kstring& while hardcopy works too 
  kstring& operator=(const char*);     // but hardcopy causes temp var generation which we can/should avoid. 
  kstring operator+(const kstring&); 
  kstring& operator+=(const kstring&); 
  kstring& operator+=(const char*); 
 private: 
  int len; 
  char* charray; 
}; 
 
-----------------------------------  // kstring.cpp 
 
#include "kstring.h" 
#include <iostream> 
#include <cstring> 
using namespace std; 
 
kstring::kstring(): len(0), charray(NULL) 


 
kstring::kstring(const char* str) 

  this->len = strlen(str); 
  this->charray = new char[(this->len) + 1]; 
  int i; 
  for(i = 0; i < (this->len) ; i++) 
    (this->charray)[i] = str[i]; 

 
kstring::~kstring() 

  if(len > 0) 
    delete [] this->charray; 

 
kstring::kstring(const kstring& kstr) 

  if(kstr.len == 0){ 
    this->len = 0; 
    this->charray = NULL; 
  }else{ 
    this->len = kstr.len; 
    this->charray = new char[(this->len) + 1]; 
    strcpy(this->charray,kstr.charray); 
  } 

 
char kstring::at(int x) const 

  // if(x < 0 || x >= this->len) throw some_error_code;  // assume input is good. 
  return (this->charray)[x]; 

 
char* kstring::get() const 

  return this->charray; 

 
kstring& kstring::operator+=(const kstring& kstr) 

  this-> len += kstr.len; 
  kstring tmp; 
  tmp.charray = new char[(this->len) + 1]; 
  strcpy(tmp.charray,this->charray); 
  strcat(tmp.charray,kstr.charray); 
  delete [] this->charray; 
  this->charray = tmp.charray; 
  return *this; 

 
kstring& kstring::operator+=(const char* p) 

  this->len += strlen(p); 
  kstring tmp; 
  tmp.charray = new char[(this->len) + 1]; 
  strcpy(tmp.charray,this->charray); 
  strcat(tmp.charray,p); 
  delete [] this->charray; 
  this->charray = tmp.charray; 
  return *this; 

 
kstring kstring::operator+(const kstring& kstr) 

  return operator += (kstr); 

 
kstring kstring::operator=(const kstring& kstr) 

  this->len = kstr.len; 
  delete [] this->charray; 
  this->charray = new char[(this->len) + 1]; 
  for(int i = 0; i < (this->len) +1 ; i++) 
    (this->charray)[i] = kstr.at(i); 
  return *this; 

 
kstring kstring::operator=(const char* p) 

  this->len = strlen(p); 
  delete [] this->charray; 
  this->charray = new char[this->len + 1]; 
  for(int i = 0; i < (this->len) + 1 ; i++) 
    (this->charray)[i] = p[i]; 
  return *this; 

 
------------------------------------------------ // mystr.cpp 
 
#include <iostream> 
#include "kstring.h" 
using namespace std; 
 
int main() 

  kstring kstr0("hell");              // validate constructor kstring(const char*); 
 
  cout << kstr0.get() << endl;        //  hell 
  cout << kstr0.at(1) << endl;        //  e 
  cout << kstr0.getSize() << endl;    //  4 
 
  kstr0 = "world";                    // validate operator=(const char*); 
 
  cout << kstr0.get() << endl;        //  world 
  cout << kstr0.getSize() << endl;    //  5 
 
  kstring kstr1,kstr2; 
  kstr1 = "foo"; 
  kstr2 = kstr1;                      // validate operator=(const kstring&); 
 
  cout << kstr2.get() << endl;        //  foo 
  cout << kstr2.getSize() << endl;    //  3 
 
  kstr0 += kstr1;                     // validate operator+=(const kstring&); 
 
  cout << kstr0.get() << endl;        //  worldfoo 
  cout << kstr0.getSize() << endl;    //  8 
 
  kstr1 += "bar";                     // validate operator+=(const char*); 
 
  cout << kstr1.get() << endl;        //  foobar 
  cout << kstr1.getSize() << endl;    //  6 
 
  kstr0 = kstr1 + kstr2;              // validate operator+(const kstring&); 
  //kstr0 = (kstr1.operator+(kstr2)); // same 
 
  cout << kstr0.get() << endl;        //  foobarfoo 
  cout << kstr0.getSize() << endl;    //  9 
 
  kstr0 = kstr2 + "bar";              // we didnt implement operator+(const char*) but this works 
                                      // because "bar" causes kstring tmp onj to be created as in kstring = "bar" 
                                      // it's called implicit type conversion (see "explicit" doc) 
                                      // in the next section where we further generalize this operator+() with "friend" 
                                      // we can look to remove operator+=(const char*) and operator=(const char*) 
 
  cout << kstr0.get() << endl;        //  foobar 
  cout << kstr0.getSize() << endl;    //  6 
 
  return 0; 

 
------------------------------------- 
 
 
 
############################################# 
###   generalized original string class   ### 
############################################# 
 
(1) make it more efficient by relying on implicit type conversion 
 
defining operator+() overload as a class member func forces the left side of the + to be of type the class. 
but we often wanna do stuff like  kstr0 = "hello" + kstr1; 
 
so, we should define operator+() as a global func and make it friend so the func can access the member variables. 
 
wikipedia doc is perfect. 
(ref) 
http://en.wikipedia.org/wiki/Operators_in_C_and_C%2B%2B 
 
 
(2) use friend specifier to allow operator+() to be more generalized 
 
see the below code. leveraging implicit conversion is useful for generalization. but if you want to prevent it, then use "explicit" specifier. 
(ref) 
http://www.glenmccl.com/tip_023.htm 
 
 
----------------- 
 
(a)  fstring.h 
(b)  fstring.cpp 
(c)  mystr2.cpp 
 
 
----------------------------------------- // fstring.h 
 
class fstring{ 
  friend fstring operator+(const fstring&, const fstring&);   // friend global func 
 public: 
  fstring(); 
  fstring(const char*); 
  fstring(const fstring&);              // copy constructor 
  ~fstring(); 
  int getSize(){ return this->len ;} 
  char* fstring::get() const; 
  char at(int) const; 
  fstring& operator=(const fstring&); 
  //  fstring operator+(const fstring&);  // this will be implemented as a friend global func as above. 
  fstring& operator+=(const fstring&); 
 private: 
  int len; 
  char* charray; 
}; 
 
 
------------------------------------------ // fstromg.cpp 
 
#include "fstring.h" 
#include <iostream> 
#include <cstring> 
using namespace std; 
 
fstring::fstring(): len(0), charray(NULL) 


 
fstring::fstring(const char* str) 

  this->len = strlen(str); 
  this->charray = new char[(this->len) + 1]; 
  int i; 
  for(i = 0; i < (this->len) ; i++) 
    (this->charray)[i] = str[i]; 

 
fstring::~fstring() 

  if(len > 0) 
    delete [] this->charray; 

 
fstring::fstring(const fstring& fstr) 

  if(fstr.len == 0){ 
    this->len = 0; 
    this->charray = NULL; 
  }else{ 
    this->len = fstr.len; 
    this->charray = new char[(this->len) + 1]; 
    strcpy(this->charray,fstr.charray); 
  } 

 
char fstring::at(int x) const 

  // if(x < 0 || x >= this->len) throw some_error_code;  // assume input is good. 
  return (this->charray)[x]; 

 
char* fstring::get() const 

  return this->charray; 

 
fstring& fstring::operator+=(const fstring& fstr) 

  this-> len += fstr.len; 
  fstring tmp; 
  tmp.charray = new char[(this->len) + 1]; 
  strcpy(tmp.charray,this->charray); 
  strcat(tmp.charray,fstr.charray); 
  delete [] this->charray; 
  this->charray = tmp.charray; 
  return *this; 

 
fstring fstring::operator=(const fstring& fstr) 

  this->len = fstr.len; 
  delete [] this->charray; 
  this->charray = new char[(this->len) + 1]; 
  for(int i = 0; i < (this->len) +1 ; i++) 
    (this->charray)[i] = fstr.at(i); 
  return *this; 

 
 
 
---------------------------------------------- // mystr2.cpp 
 
#include "fstring.h" 
using namespace std; 
 
fstring operator+(const fstring& lhs, const fstring& rhs) 

  fstring tmp = lhs; 
  return tmp += rhs; 

 
#include <iostream> 
#include "fstring.h" 
using namespace std; 
 
int main() 

  fstring fstr0("hell");              // validate constructor fstring(const char*); 
 
  cout << fstr0.get() << endl;        //  hell 
  cout << fstr0.at(1) << endl;        //  e 
  cout << fstr0.getSize() << endl;    //  4 
 
  fstr0 = "world";                    // validate implicit conversion operator=(const char*);  when input is (const char*) 
 
  cout << fstr0.get() << endl;        //  world 
  cout << fstr0.getSize() << endl;    //  5 
 
  fstring fstr1,fstr2; 
  fstr1 = "foo"; 
  fstr2 = fstr1;                      // validate operator=(const fstring&); 
 
  cout << fstr2.get() << endl;        //  foo 
  cout << fstr2.getSize() << endl;    //  3 
 
  fstr0 += fstr1;                     // validate operator+=(const fstring&); 
 
  cout << fstr0.get() << endl;        //  worldfoo 
  cout << fstr0.getSize() << endl;    //  8 
 
  fstr1 += "bar";                     // validate operator+=(const char*);  when input is (const char*) 
 
  cout << fstr1.get() << endl;        //  foobar 
  cout << fstr1.getSize() << endl;    //  6 
 
  fstr0 = fstr1 + fstr2;              // validate operator+(const fstring&, const fstring&); 
  //fstr0 = (fstr1.operator+(fstr2)); // same 
 
  cout << fstr0.get() << endl;        //  foobarfoo 
  cout << fstr0.getSize() << endl;    //  9 
 
  fstr0 = fstr2 + "bar";              // validate operator+();  with 2nd input as const char* 
 
  cout << fstr0.get() << endl;        //  foobar 
  cout << fstr0.getSize() << endl;    //  6 
 
  fstr0 = "bar" + fstr2;              // validate operator+();  with 1st input as const char* 
 
  cout << fstr0.get() << endl;        //  barfoo 
  cout << fstr0.getSize() << endl;    //  6 
 
 
  return 0; 

 
--------------------------------------- 
 
 
 
 
 
########################## 
####   const usage    #### 
########################## 
 
use of "const" has to be carefully arranged. 
 
in short, you cannot bind temp object to a non-const reference. 
 
a very good simple example code quoted from cplusplus.com below. 
 
------------------------------------------- 
 
#include <string> 
#include <iostream> 
 
using namespace std; 
 
void print_me( string& s ) { 
    cout << s << endl; 

 
int main() { 
   print_me( string( "Hello World" ) ); 

 
------------------------------------------- 
 
(ref) 
http://www.cplusplus.com/forum/beginner/7834/ 
 

  1. 2014-05-27 15:56:04 |
  2. Category : cpp
  3. Page View:

Google Ads