Update: FREE homework help NOW available ...
You can contact me via:
http://sites.google.com/site/andeveryeyeshallseehim/home/he-comes
http://developers-heaven.net/forum/index.php/topic,2587.0.html
An other fairly often student problem ...
is to code a class to take in and handle dynamic strings in C++,
perhaps, (under the hood), using arrays of char that are terminated by '\0' ( i.e. C strings ) ...
The following example may give you some ideas how to start ...
Firstly the .h file:
// MyString.h // // 2016-02-05 //
#ifndef MYSTRING_H
#define MYSTRING_H
#include <iostream>
#include <cstring> // re. strlen, etc...
#include <cctype> // re. tolower
#include <cmath> // re. log10
#include <vector>
// a start to a NULL terminated C++ string class //
struct MyString // You can, the way coded here, just replace struct with class ... MAKES NO difference HERE !!! //
{
public:
// if neg num's stored as 'twos complement' ...
// this next value is the largest size_t possible //
static const size_t npos = -1;
static const size_t chunk_size = 255;
// 4 ctor's follow ...
// default ...
MyString() : len(0), str( new char[1] )
{
str[0] = 0;
}
// from C string ...
MyString( const char* s )
{
len = strlen(s);
str = new char[len+1];
strncpy( str, s, len );
str[len] = 0; // terminate with the (NULL C) '\0' char //
}
//
MyString( const size_t num, const char ch )
{
len = num;
str = new char[len+1];
for( size_t i = 0; i < len; ++ i ) str[i] = ch;
str[len] = 0; // terminate with the (NULL C) '\0' char //
}
// Copy ctor
MyString( const MyString& s )
{
len = s.len;
str = new char[len+1];
strncpy( str, s.str, len );
str[len] = 0; // terminate with the (NULL C) '\0' char //
}
// overloaded assignment i.e. overloaded operator = ...
MyString& operator = ( const MyString& s )
{
if( this != &s )
{
delete [] str; // firstly delete (free up) OLD memopry
len = s.len;
str = new char[len+1];
strncpy( str, s.str, len );
str[len] = 0; // terminate with the (NULL C) '\0' char //
}
return *this;
}
// overloaded operator += ...
MyString& operator += ( const MyString& s )
{
size_t n_len = len + s.len;
char* tmp = new char[n_len+1];
strncpy( tmp, str, len );
strncpy( tmp+len, s.str, s.len );
tmp[n_len] = 0; // terminate with '\0' char //
delete str; // delete old memory //
str = tmp; // update
len = n_len;
return *this;
}
// overloaded operator += ...
MyString& operator += ( const char ch )
{
char* tmp = new char[len+2];
strncpy( tmp, str, len );
tmp[len] = ch;
++len;
tmp[len] = 0; // terminate with '\0' char //
delete str; // delete old memory //
str = tmp; // update
return *this;
}
// overloaded operator +...
friend MyString operator + ( const MyString& a, const MyString& b )
{
MyString tmp(a);
return tmp += b;
}
friend MyString operator + ( const char ch, const MyString& b )
{
MyString tmp( 1, ch );
return tmp + b;
}
friend MyString operator + ( const MyString& a, const char ch )
{
MyString tmp( 1, ch );
return a + tmp;
}
// overloaded operator []
char operator [] ( const size_t i ) const
{
return str[i];
}
// overloaded operator []
char& operator [] ( const size_t i )
{
return str[i];
}
char* c_str() const
{
return str;
}
char*& c_str()
{
return str;
}
size_t find( const char c, const size_t start = 0 )
{
for( size_t i = start; i < len; ++ i )
{
if( str[i] == c ) return i;
}
return npos;
}
MyString& erase( const size_t start, const size_t num = npos )
{
if( start > len )
return *this;
size_t numErase = num;
if( numErase > len - start )
numErase = len - start;
size_t n_len = len - numErase;
char* tmp = new char[n_len+1];
if( start ) // if ( start > 0 ) //
{
strncpy( tmp, str, start );
tmp[start] = 0; // 'NULL terminate' //
if( numErase < len - start )
strcat( tmp, str+start+numErase );
}
else // here ... start is 0 //
{
strncpy( tmp, str + numErase, len - numErase );
tmp[n_len] = 0;
}
delete [] str;
str = tmp;
len = n_len;
return *this;
}
MyString substr( const size_t start, const size_t num = npos )
{
MyString tmp;
if( start > len )
return tmp;
tmp.len = num;
if( tmp.len > len - start )
tmp.len = len - start;
delete [] tmp.str;
tmp.str = new char[tmp.len+1];
strncpy( tmp.str, str+start, tmp.len );
tmp.str[tmp.len] = 0; // 'NULL terminate' //
return tmp;
}
~MyString() // destructor
{
delete [] str;
str = 0;
len = 0;
}
void clear()
{
delete [] str;
str = new char[1];
str[0] = 0;
len = 0;
}
size_t size() const
{
return len;
}
private:
size_t len;
char* str;
friend std::ostream& operator << ( std::ostream& os, const MyString& ms )
{
return os << ms.str;
}
friend std::istream& operator >> ( std::istream& is, MyString& ms )
{
size_t cap = MyString::chunk_size, size = 0; // c to hold each char
char c;
char* strData = new char[cap+1];
while( is.get(c) && strchr(" \t\n", c) )
; // advance over all leading (ws) delimit char's //
if( !is.eof() ) // ok ... get this first char ... //
strData[size++] = c;
else
{
delete [] ms.str;
delete [] strData;
ms.str = new char[1];
ms.str[0] = 0;
ms.len = 0;
return is;
}
while( is.get(c) && !strchr(" \t\n", c) )
{
if( size == cap )
{
cap += cap; // double memory capacity
char* tmp = new char[cap+1];
for( size_t i = 0; i < size; ++ i )
tmp[i] = strData[i];
tmp[size] = 0;
delete [] strData;
strData = tmp;
}
// now ... since reached here ...
strData[size++] = c; // append this char //
}
strData[size] = 0; // ensure terminated with 0 //
if( cap > size ) // 'right' size string //
{
char* tmp = new char[size+1];
for( size_t i = 0; i < size; ++ i )
tmp[i] = strData[i];
tmp[size] = 0;
delete [] strData;
strData = tmp;
}
delete [] ms.str;
ms.str = strData;
ms.len = size;
return is;
}
friend std::istream& getline( std::istream& is, MyString& ms, const char* delimits = "\n" )
{
size_t cap = MyString::chunk_size, size = 0; // c to hold each char
char c;
char* strData = new char[cap+1];
while( is.get(c) && !strchr( delimits, c ) )
{
if( size == cap )
{
cap += cap; // double memory capacity
char* tmp = new char[cap+1];
for( size_t i = 0; i < size; ++ i )
tmp[i] = strData[i];
tmp[size] = 0;
delete [] strData;
strData = tmp;
}
// now ... since reached here ...
strData[size++] = c; // append this char //
}
strData[size] = 0; // ensure terminated with 0 //
if( cap > size ) // 'right' size string //
{
char* tmp = new char[size+1];
for( size_t i = 0; i < size; ++ i )
tmp[i] = strData[i];
tmp[size] = 0;
delete [] strData;
strData = tmp;
}
delete [] ms.str;
ms.str = strData;
ms.len = size;
return is;
}
void friend split( std::vector< MyString >& vms, const MyString& ms, const char* delimits = " \t" )
{
size_t len = ms.len, i = 0, j = 0;
while( i < len )
{
// skip over any leading delimits char's ...
while( strchr( delimits, ms.str[i] ) )
++ i;
if( i == len ) return; // ALL delimits //
j = i;
// find j 'one past' endof 'word' ...
while( j < len && !strchr( delimits, ms.str[j] ) )
++ j;
MyString tmp( j-i, ' ' ); // get right sixed empty MyString
strncpy( tmp.str, ms.str+i, j-i );
vms.push_back( tmp ); // add this word to end of vector //
i = j+1;
}
}
} ;
// EIGHT utilities for the above MyString type ... //
MyString takeInMyString( const MyString& prompt = "" )
{
std::cout << prompt << std::flush;
MyString s;
getline( std::cin, s );
return s;
}
int takeInChr( const MyString& prompt = "" )
{
return takeInMyString( prompt )[0];
}
// defaukts to 'y' i.e. YES //
bool more( const MyString& msg_part = "" )
{
std::cout << "More " + msg_part;
return tolower( takeInChr( " (y/n) ? " )) != 'n';
}
MyString& toCapsOnAllFirstLetters( MyString& str )
{
// to get CAPS on first char ...
int prev_was_ws = 1; // start with previous was white space
size_t len = str.size();
for( size_t i = 0; i < len; ++ i )
{
if( prev_was_ws )
str[i] = toupper( str[i] );
prev_was_ws = isspace( str[i] );
}
return str;
}
MyString& toUpper( MyString& str )
{
size_t len = str.size();
for( size_t i = 0; i < len; ++ i )
str[i] = toupper( str[i] );
return str;
}
MyString& toLower( MyString& str )
{
size_t len = str.size();
for( size_t i = 0; i < len; ++ i )
str[i] = tolower( str[i] );
return str;
}
// NO ERROR checking done here !!!
// The assumption here IS that the string passed in ...
// IS VALID ... for the type requested !!! //
// Note!!! Does NOT handle scientific notation !!! //
template< typename T >
T toNumber( const MyString& val )
{
MyString str( val );
char sign = '+';
if( str[0] == '-' )
{
sign = '-';
str.erase(0, 1);
}
else if(str[0] == '+')
str.erase(0, 1);
MyString dec_part;
double dec = 0.0;
size_t pos = str.find('.');
if( pos != MyString::npos )
{
dec_part = str.substr(pos+1);
str = str.erase(pos);
//std::cin.get();
double divisor = 1;
size_t len = dec_part.size();
for( size_t i = 0; i < len; ++ i )
{
divisor *= 10;
dec += (dec_part[i] - '0')/divisor;
}
}
size_t len = str.size();
T num = 0;
for( size_t i = 0; i < len; ++ i )
num = 10*num + str[i] - '0';
if( dec_part.size() )
num += dec;
if( sign == '-' )
num *= -1;
// else ...
return num;
}
// this handles conversion from NON-NEGATIVE INTEGER NUMBERS
// to a comma formatted string //
template< typename T >
MyString commasAdded( T val ) // val is a local copy //
{
int num_digits = (int) log10((double)val) +1;
MyString tmp( num_digits, '0' ); // get string correct size //
//std::cout << "Num digits is " << num_digits << '\n';
int i = num_digits-1; // start from end and work to front //
do
{
int digit = val % 10;
tmp[i] = '0' + digit;
val /= 10;
--i;
}
while( val );
int comma = 0,
len = tmp.size();
// note integer division here: 2/3 = 0 & 3/3 = 1
int len2 = len + (len-1)/3;
// construct right size and filled with commas
MyString tmp2( len2, ',' );
while( len2 ) // start at end of string of commas ... then ...
{
--len, --len2;
++comma; // this tracks where we are //
if( comma != 4 ) // keep copying until reach the next comma to skip over //
tmp2[len2] = tmp[len];
else // ha ... we want to LEAVE this comma here //
{
comma = 1; // reset counter
//tmp2[len2] = ','; // this comma STAYs NOT over-ridden //
--len2; // so skip over //
tmp2[len2] = tmp[len]; // ok ... copy in/(and over commas) this digit
}
}
return tmp2; // return it //
}
#endif