C++ string Class

The string class provides strings which grow automatically. You don't have to specify an artificial maximum size when declaring string variables. In this respect they are similar to the STL container classes.

1. Declarations


#include <string>

using namespace std;

int main()
{
  string s;
  ...



  // string has a constructor: string(const char *);

  string s = "Hello, world!"; 

  s = string("Bye");

2. I/O


  // operator>>  and operator<< can be used with string
  // variables. 
  // As usual, operator>> skips leading white space and stops
  // reading at first trailing white space or end of input.

  string s;

  cin >> s;

  cout << s;


  // There is a non-member getline function:
  // istream& getline(istream&, string& s, const char delim = '\n');
  // This example reads input lines until end of file (or input error) 
  // changes the state of cin which is the return value of getline.
  // The lines read are stored in the vector v. The getline function
  // reads all characters (e.g., blanks, tabs, normal characters,
  // etc.) up to the delimiter character. The default delimiter
  // character is the newline character that terminates an input
  // line. The delimiter can be changed by passing a new delimiter
  // character as the third parameter to getline.
  //
  // Note: This function does not work correctly for some 
  // versions of Visual C++ version 6 when using it with cin, although
  // it does work for input file streams, i.e., ifstream objects. 
  // There is a fix. 


  vector<string> v;
  string s;
  ...
  while( getline(cin, s) ) {
    v.push_back(s);
  }
  

3. Assignment and concatenation

C++ strings can also be assigned using the = operator, or concatenated using the + operator:


string s1 = "first string";
string s2 = "second string";
string s3 = s1 + ", " + s2;

cout << s3 << endl;

Output:
first string, second string


// Note that the + operator does NOT work unless one of the arguments
// is a c++ string. If both are c-style strings an error occurs.

string s;

s = "abc" + "cdef";  
// ERROR: No + operator defined for operands of
// type char[4] and char[5].


// The previous example doesn't work because neither operand
// of + is a c++ string. You can convert a c-style string
// to a c++ string using the string constructor:

string s;

s = "abc" + string("cdef");  


// This is ok. Since one of the operands is a c++-string, the 
// other operand, "abc", will also be automatically converted
// to a c++ string.



// operands can be char * as well as c-string constants, but
// one of the operands still needs to be a c++ string. So
// you sill need to convert at least one of the operands
// if both are c-strings:

char w[] = "abc";

s = string(w) + "cdef";

The += operator is also defined and works as you would
expect.

4. String Comparisons

One obstacle to using c-style strings with the STL general purpose algorithms such as sorting is that c-strings are compared differently (using the function strcmp) than using the < operator and you can't overload operator< for c-strings. (The < operator is already defined for char * type, but unfortunately it is just comparing the pointer value, not the characters pointed to.)

For C++ strings, all of the typical relational operators work as expected to compare either C++ strings or a C++ string and either a C string or a static string (i.e., "one in quotes"). That is, as for concatenation, as long as one of the operands of a comparison is a c++-string, the other operand will be converted if necessary from a c-string to c++-string.


#include <string>
string passwd;

getline(cin, passwd);

// Compare c++-string to a c-string, "fred or barney" is converted
if(passwd == "fred or barney")  // equality comparison
{
    cout << "Access allowed." << endl
} else {
    cout << "Access denied!" << endl	
}



#include <cstring>
char passwd[50];

cin.getline(passwd, 50);

// Comparing char * type c-strings requires using strcmp
if(strcmp(passwd,"fred or barney") == 0 )  // c-string equality comparison
{
    cout << "Access allowed." << endl
} else {
    cout << "Access denied!" << endl	
}


5. String Length and Accessing Individual Elements

There are two member functions to get the number of characters in a c++ string: size() and length(). They are functionally the same. The 'size' name is the one used by all the STL containers, but 'length' may be more intuitive in the case of strings. Take your pick.

The operator[] is a member function of the string class. It returns a reference to the char stored at the given position in the c++-string. The subscript should be >= 0 and < size().


string s = "abc";
unsigned int len = s.size();  // len is 3

for(unsigned int i = 0; i < s.size(); i++) {
  cout << s[i] << endl;
}

Output:
a
b
c

6. The string class has iterators too!

Another similarity between the string class and the STL container classes is the use of iterators. The following example code to enumerate the characters in a string is exactly like enumerating the elements of any of the STL containers.



string s = "Twas brillig";
string::iterator p;

for(p = s.begin(); p != s.end(); ++p)
{
    cout << *p << endl;
}

Note: If characters are added or removed from a string, any
iterators associated to the string are invalidated and should be
reinitialized. 

7. Searching and Substrings

The c++ string class has the following members to search the string for a specified search character or string in the instance string:

unsigned int string::find(char ch, unsigned int pos = 0);
Returns the position of the first occurrence of ch in this string starting from position pos. If ch does not occur, string::npos is returned.
unsigned int string::find(const char *p,unsigned int pos = 0);
Returns the position of the first occurrence of the null terminated string pointed to by p in this string starting from position pos. If the string does not occur, string::npos is returned.
unsigned int string::find(const char *p, unsigned int pos, unsigned int n);
Returns the first position of the string pointed to by p in this string starting from position pos. The string searched for is the null terminated string pointed to by p, but consisting of no more than n characters if no null byte is encountered. If the string is not found in this string, string::npos is returned.
unsigned int string::find(const string& s, unsigned int pos = 0);
Returns the first position of the string s in this string starting from pos. If the string does not occur, string::npos is returned.

In all cases the return value is the beginning position of the searched for character or string if it is present. If the searched for char or string is not in the string, the return value is the constant string::npos.



static unsigned int string::pos =  ... // The largest possible
                                       // unsigned int; all bits are 1's.


This sample code searches for every instance of the string "an" in a
given string and counts the total number of instances: 

string s = "banana";

int cnt = 0;

unsigned pos = s.find("an", 0);
while ( pos != string::npos ) {
   cnt++;
   pos = s.find("an", pos);
}
cout << "an occurred " <<cnt << times << endl;

There are also corresponding member functions to search backwards in the string.

8. Substrings

The substr member function can be used to create a new string from some substring of a given string. The substring is specified by giving the starting position (the first character of a string is at position 0) and the number of characters to copy.

string string::substr(unsigned int starpos = 0, unsigned int length = string::npos)



string s = "abcdefghijklmnop";
string first5 = s.substr(0,5);   // startpos = 0, 5 chars (at pos 0 - 4)
string second5 = s.substr(5,5);  // startpos = 5, 5 chars (at pos 5 - 9)
string r10 = s.substr(10);       // startpos = 10, all remaining chars

cout << first5 << endl;
cout << second5 << endl;
cout << r10 << endl;
cout << s.substr(10) << endl;
Output:
abcde
fghij
klmnop
abcdefghijklmnop

9. More searching member functions

Two additional member functions similar to find can be very useful in breaking a string into "tokens" that are delimited by delimiter characters such as spaces or punctuation. Each of these two functions is overloaded so that it can be used either with delimiters specified by c-strings or c++-strings.

unsigned int find_first_of(const char * delim, unsigned int startpos = 0);
Returns the position of the first occurrence of any character from the c-string delim in this string starting from position pos. If no such character occurs, string::npos is returned.
unsigned int find_first_of(const string& delim, unsigned int startpos = 0);
Returns the position of the first occurrence of any character from the c++ string delim in this string starting from position pos. If no such character occurs, string::npos is returned.
unsigned int find_first_not_of(const char * delim, unsigned int startpos = 0);
Returns the position of the first occurrence of any character not from the c-string delim in this string starting from position pos. If no such character occurs, string::npos is returned.
unsigned int find_first_not_of(const string& delim, unsigned int startpos = 0);
Returns the position of the first occurrence of any character not from the c++ string delim in this string starting from position pos. If no such character occurs, string::npos is returned.

string s = "fred; barney, wilma-betty! ";
string delims = " ,;:.!?";

unsigned int startpos, delimpos;

Exercise: Write the code using find_first_not_of, find_first_of, and
substr to print the substrings of s delimited by the characters in the
string delims. The output should be as indicated here:

Output:
fred
barney
wilma
betty

10. Modifying Strings: erase and insert

string& insert(unsigned int pos, char * p)
Returns a reference to this string after the c-string pointed to by p has been inserted at position pos. Characters that were at or after position pos are "moved right" to make room for the inserted string. If pos is not in the range 0 <= pos <= size(), out_of_range exception is thrown. If pos is equal to size(), the string is inserted at the end of this string.
string& insert(unsigned int pos, const string& s)
Returns a reference to this string after the c++ string s has been inserted at position pos. Characters that were at or after position pos are "moved right" to make room for the inserted string. If pos is not in the range 0 <= pos <= size(), out_of_range exception is thrown. If pos is equal to size(), the string is inserted at the end of this string.
string& string::erase(unsigned int startpos = 0, unsigned int n = string::npos)
Returns this string after up to n characters beginning at startpos have been removed; that is, all the remaining characters or n characters, whichever is smaller, are removed. If startpos is not in the range 0 <= startpos <= size(), an out_of_range exception is thrown. If startpos is size(), no character is removed and no exception is thrown.

The erase member function takes a position and a character count and removes that many characters starting from the given position. The position is zero-indexed, as usual. If the position is greater or equal to the size, then an out_of_range exception is thrown.

The insert member function takes a starting position and a char, c-string, or c++-string, which is inserted into the string at the given position. All following characters are "moved over". The starting position can be any value from 0 up to and including the size of the string. This is different than for erase which does not allow the position to equal to size since there is no character at that position. For insert if position is equal to size, the new string is just inserted at the end. However, if position is > size, then again, an out_of_range exception is thrown.



string s = "fred barney wilma";
s.erase(5, 6); // removes "barney"; s is now "fred  wilma"  (2 spaces)

s.erase(0, s.size());  // removes all chars; s is now ""




string s = "fred wilma";

s.insert(5, "barney ");  // now s is "fred barney wilma"

s.insert(s.size(), " betty"); // now s is "fred barney wilma betty";


string s = "abc";

try { 
  s.insert(4, "d");
} catch(out_of_range e) {
  cout << "insert(4, ...) out of range" << endl;
  cout << e.what() << endl;
}

Output:
insert(4,...) out of range
basic_string::insert

11. Converting a c++ string to a char * (c-string)

Many standard C-libarary and several standard c++-libary functions expect c-strings (char *) rather than c++ string objects. This is easily handled by using the member function c_str:


cont char * c_str() const;


Note that the returned char* is a const value so you  cannot
modify this string.

If you need to modify the returned value, you should create a second
string and use the strcpy function to copy the returned value from c_str(). 



#include <fstream>

int main()
{
  ifstream ifs;
  string fname;

  cout << "Enter input file name: ";
  cin >> fname;

  // The open function expects a char * (a c-string)
  // Use c_str() to return a c-style version of fname's value.
  ifs.open(fname.c_str());
  ...
}