The String Class: Templates Tutorial
The String Class: Templates Tutorial
A lot of books that teach introductory C++ tell you to use char pointers for string handling. I learned it this way and it drove me nuts. I was learning Java at the same time and couldn't figure out why C++ didn't have string support. It's such a necessary aspect of programming! What I didn't know is that C++ does have a standard string class, which is aptly named string. Whenever possible, I recommend using string instead of char pointers. The string class is clean, provides great functionality, and you don't need to worry about buffer overflows like you do with char pointers. This discussion will cover some of the functionality offered by the string class. Most of the functions are self-explanatory, so I'll just list the most useful ones here with a description of what each one does. I've also included a sample application that demonstrates the use of the different string functions. Note that you can declare and use a string variable just like any variable in C++. As I said before, you should treat the classes in the STL just like any other C++ programming language feature.
c_str() string length() at(int index) counting starts at 0 operator[](int index) an array clear() substr(int start, int end) find(char*/string str) string or a char*) // returns a const char* representation of the // returns the length of the string // returns the char at the specified index, // overloaded so you can access characters like // erases the string // returns the substring from start to end // searches the string for a substring (takes a
The <> notation might seem a little odd to you. If it does, check out my Templates Tutorial. A powerful feature of the STL is the use of iterators. Iterators are pointers that point into the structures of the STL. You can have an iterator that points into a vector that stores integers, and point it to the first element of the vector. You can then increment the iterator and it will point to the second element of the vector. You use the increment operator (++) to do this. You can compare the locations of two iterators using standard conditional operators ( <, >, <=, >= ). The statement itr1 < itr2 will return true ifitr1 points to an element that is closer to the start of the vector.
If you want to get the value stored at the element an iterator points to, use the dereference operator (*) like this:
*itr;
STL structures have begin() and end() functions which return iteratorsat the beginning of the stucture and one past the end of the structure (not the element at the end, one past it) respectively. Here's a quick example of using iterators, see the downloadable source code for a more thorough demonstration.
// Declare some iterators that point into vectors of integers vector<int>::iterator itr1 = intVector.begin(); vector<int>::iterator itr2 = intVector.end(); itr1++; itr1 < itr2; itr += 2; // move the iterator one element forward // true if itr1 points to an element coming before itr2 // move the iterator up by 2 elements
// This is how you would use iterators to loop through a vector for (vector<int>::iterator itr = intVector.begin(); itr < intVector.end(); itr++) { cout << *itr; // *itr gets the value from the element itr points to }
Here is a list of useful vector functions. See the downloaded source code for working examples of each of these.
push_back(T value) insert(iterator itr, T value) operator[](int index) at(int index) index is too big begin() the vector end() the vector clear() pop_back() vector // // // // add an insert access access element to the end of the list an element at a specific position an element an element, throws exception if
// return an iterator to the beginning of // return an iterator to one past the end of // erase everything in the vector // remove the element at the end of the
If we need to sort our vector, we can use the STL sort() function. This function takes an iterator to the first element and one past the last element we want sorted. If you want to sort the whole vector, use begin() and end() like so:
vector vector sort(itr1, itr2);
I find the vector class to be the most useful structure in the STL. In fact, I use it in almost all of the tutorials on this site. It's really nice having the instant access of an array with the dynamic size of a linked list. I suggest you try using the vector in place of arrays, unless you have a good reason to be using an array. Click here to download the source code for this tutorial.
Here's the list of functions that comes with the queue. And don't forget to download the source code and see the queue at work.
// We declare a queue like this, dataType can be any data type queue<dataType> myQueue; myQueue.push(item); myQueue.pop(); myQueue.front(); myQueue.back(); myStack.size(); myStack.empty(); // // // // // // adds an removes returns returns returns returns element to the back of the queue the element at the front of the queue the element at the front of the queue the element at the back of the queue the number of elements in the queue true if the queue has no elements
Basic Input/Output
Until now, the example programs of previous sections provided very little interaction with the user, if any at all. Using the standard input and output library, we will be able to interact with the user by printing messages on the screen and getting the user's input from the keyboard. C++ uses a convenient abstraction called streams to perform input and output operations in sequential media such as the screen or the keyboard. A stream is an object where a program can either insert or extract characters to/from it. We do not really need to care about many specifications about the physical media associated with the stream - we only need to know it will accept or provide characters sequentially. The standard C++ library includes the header file iostream, where the standard input and output stream objects are declared.
1 cout << "Output sentence"; // prints Output sentence on screen 2 cout << 120; // prints number 120 on screen 3 cout << x; // prints the content of x on screen
The << operator inserts the data that follows it into the stream preceding it. In the examples above it inserted the constant string Output sentence, the numerical constant 120 and variable x into the standard output stream cout. Notice that the sentence in the first instruction is enclosed between double quotes (") because it is a constant string of characters. Whenever we want to use constant strings of characters we must enclose them between double quotes ( ") so that they can be clearly distinguished from variable names. For example, these two sentences have very different results:
The insertion operator (<<) may be used more than once in a single statement:
cout << "Hello, " << "I am " << "a C++ statement";
This last statement would print the message Hello, I am a C++ statement on the screen. The utility of repeating the insertion operator (<<) is demonstrated when we want to print out a combination of variables and constants or more than one variable:
cout << "Hello, I am " << age << " years old and my zipcode is " << zipcode;
If we assume the age variable to contain the value 24 and the zipcode variable to contain 90064 the output of the previous statement would be:
It is important to notice that cout does not add a line break after its output unless we explicitly indicate it, therefore, the following statements:
will be shown on the screen one following the other without any line break between them: This is a sentence.This is another sentence. even though we had written them in two different insertions into cout. In order to perform a line break on the output we must explicitly insert a new-line character into cout. In C++ a new-line character can be specified as \n (backslash, n):
This produces the following output: First sentence. Second sentence. Third sentence. Additionally, to add a new-line, you may also use the endl manipulator. For example:
1 cout << "First sentence." << endl; 2 cout << "Second sentence." << endl;
would print out: First sentence. Second sentence. The endl manipulator produces a newline character, exactly as the insertion of '\n' does, but it also has an additional behavior when it is used with buffered streams: the buffer is flushed. Anyway, cout will be an unbuffered stream in most cases, so you can generally use both the \n escape character and the endl manipulator in order to specify a new line without any difference in its behavior.
The first statement declares a variable of type int called age, and the second one waits for an input
from cin (the keyboard) in order to store it in this integer variable. cin can only process the input from the keyboard once the RETURN key has been pressed. Therefore, even if you request a single character, the extraction from cin will not process the input until the user presses RETURN after the character has been introduced. You must always consider the type of the variable that you are using as a container with cin extractions. If you request an integer you will get an integer, if you request a character you will get a character and if you request a string of characters you will get a string of characters.
1 // i/o example 2 3 #include <iostream> 4 using namespace std; 5 6 int main () 7{ Please enter an integer value: 702 8 int i; The value you entered is 702 and its d 9 cout << "Please enter an integer value: "; 10 cin >> i; 11 cout << "The value you entered is " << i; 12 cout << " and its double is " << i*2 << ".\n"; 13 return 0; 14 }
The user of a program may be one of the factors that generate errors even in the simplest programs that use cin (like the one we have just seen). Since if you request an integer value and the user introduces a name (which generally is a string of characters), the result may cause your program to misoperate since it is not what we were expecting from the user. So when you use the data input provided by cin extractions you will have to trust that the user of your program will be cooperative and that he/she will not introduce his/her name or something similar when an integer value is requested. A little ahead, when we see the stringstream class we will see a possible solution for the errors that can be caused by this type of user input. You can also use cin to request more than one datum input from the user:
is equivalent to:
In both cases the user must give two data, one for variable a and another one for variable b that may be separated by any valid blank separator: a space, a tab character or a newline.
However, as it has been said, cin extraction stops reading as soon as if finds any blank space character, so in this case we will be able to get just one word for each extraction. This behavior may or may not be what we want; for example if we want to get a sentence from the user, this extraction operation would
not be useful. In order to get entire lines, we can use the function getline, which is the more recommendable way to get user input with cin:
1 // cin with strings 2 #include <iostream> 3 #include <string> 4 using namespace std; 5 6 int main () 7{ 8 string mystr; 9 cout << "What's your name? "; 10 getline (cin, mystr); 11 cout << "Hello " << mystr << ".\n"; 12 cout << "What is your favorite team? "; 13 getline (cin, mystr); 14 cout << "I like " << mystr << " too!\n"; 15 return 0; 16 }
What's your name? Juan Soulie Hello Juan Soulie. What is your favorite team? The Isotopes I like The Isotopes too!
Notice how in both calls to getline we used the same string identifier (mystr). What the program does in the second call is simply to replace the previous content by the new one that is introduced.
stringstream
The standard header file <sstream> defines a class called stringstream that allows a string-based object to be treated as a stream. This way we can perform extraction or insertion operations from/to strings, which is especially useful to convert strings to numerical values and vice versa. For example, if we want to extract an integer from a string we can write:
This declares a string object with a value of "1204", and an int object. Then we use stringstream's constructor to construct an object of this type from the string object. Because we can use stringstream objects as if they were streams, we can extract an integer from it as we would have done on cin by applying the extractor operator (>>) on it followed by a variable of type int. After this piece of code, the variable myint will contain the numerical value 1204.
1 // stringstreams 2 #include <iostream> 3 #include <string> 4 #include <sstream> 5 using namespace std; 6 7 int main () 8{ 9 string mystr; 10 float price=0; 11 int quantity=0; 12 13 cout << "Enter price: "; 14 getline (cin,mystr); 15 stringstream(mystr) >> price; 16 cout << "Enter quantity: "; 17 getline (cin,mystr);
18 stringstream(mystr) >> quantity; 19 cout << "Total price: " << price*quantity << endl; 20 return 0; 21 }
In this example, we acquire numeric values from the standard input indirectly. Instead of extracting numeric values directly from the standard input, we get lines from the standard input ( cin) into a string object (mystr), and then we extract the integer values from this string into a variable of type int (quantity). Using this method, instead of direct extractions of integer values, we have more control over what happens with the input of numeric values from the user, since we are separating the process of obtaining input from the user (we now simply ask for lines) with the interpretation of that input. Therefore, this method is usually preferred to get numerical values from the user in all programs that are intensive in user input.
Basic Input/Output Until now, the example programs of previous sections provided very little interaction with the user, if any at all. Using the standard input and output library, we will be able to interact with the user by printing messages on the screen and getting the user's input from the keyboard. C++ uses a convenient abstraction called streams to perform input and output operations in sequential media such as the screen or the keyboard. A stream is an object where a program can either insert or extract characters to/from it. We do not really need to care about many specifications about the physical media associated with the stream - we only need to know it will accept or provide characters sequentially. The standard C++ library includes the header file iostream, where the standard input and output stream objects are declared.
1 cout << "Output sentence"; // prints Output sentence on screen 2 cout << 120; // prints number 120 on screen 3 cout << x; // prints the content of x on screen
The << operator inserts the data that follows it into the stream preceding it. In the examples above it inserted the constant string Output sentence, the numerical constant 120 and variable x into the standard output stream cout. Notice that the sentence in the first instruction is enclosed between double quotes (") because it is a constant string of characters. Whenever we want to use constant strings of characters we must enclose them between double quotes ( ") so that they can be clearly distinguished from variable names. For example, these two sentences have very different results:
The insertion operator (<<) may be used more than once in a single statement:
cout << "Hello, " << "I am " << "a C++ statement";
This last statement would print the message Hello, I am a C++ statement on the screen. The utility of repeating the insertion operator (<<) is demonstrated when we want to print out a combination of variables and constants or more than one variable:
cout << "Hello, I am " << age << " years old and my zipcode is " << zipcode;
If we assume the age variable to contain the value 24 and the zipcode variable to contain 90064 the output of the previous statement would be:
It is important to notice that cout does not add a line break after its output unless we explicitly indicate it, therefore, the following statements:
will be shown on the screen one following the other without any line break between them: This is a sentence.This is another sentence. even though we had written them in two different insertions into cout. In order to perform a line break on the output we must explicitly insert a new-line character into cout. In C++ a new-line character can be specified as \n (backslash, n):
This produces the following output: First sentence. Second sentence. Third sentence. Additionally, to add a new-line, you may also use the endl manipulator. For example:
1 cout << "First sentence." << endl; 2 cout << "Second sentence." << endl;
would print out: First sentence. Second sentence. The endl manipulator produces a newline character, exactly as the insertion of '\n' does, but it also has an additional behavior when it is used with buffered streams: the buffer is flushed. Anyway, cout will be an unbuffered stream in most cases, so you can generally use both the \n escape character and the endl manipulator in order to specify a new line without any difference in its behavior.
1 int age;
The first statement declares a variable of type int called age, and the second one waits for an input from cin (the keyboard) in order to store it in this integer variable. cin can only process the input from the keyboard once the RETURN key has been pressed. Therefore, even if you request a single character, the extraction from cin will not process the input until the user presses RETURN after the character has been introduced. You must always consider the type of the variable that you are using as a container with cin extractions. If you request an integer you will get an integer, if you request a character you will get a character and if you request a string of characters you will get a string of characters.
1 // i/o example 2 3 #include <iostream> 4 using namespace std; 5 6 int main () 7{ Please enter an integer value: 702 8 int i; The value you entered is 702 and its d 9 cout << "Please enter an integer value: "; 10 cin >> i; 11 cout << "The value you entered is " << i; 12 cout << " and its double is " << i*2 << ".\n"; 13 return 0; 14 }
The user of a program may be one of the factors that generate errors even in the simplest programs that use cin (like the one we have just seen). Since if you request an integer value and the user introduces a name (which generally is a string of characters), the result may cause your program to misoperate since it is not what we were expecting from the user. So when you use the data input provided by cin extractions you will have to trust that the user of your program will be cooperative and that he/she will not introduce his/her name or something similar when an integer value is requested. A little ahead, when we see the stringstream class we will see a possible solution for the errors that can be caused by this type of user input. You can also use cin to request more than one datum input from the user:
is equivalent to:
In both cases the user must give two data, one for variable a and another one for variable b that may be separated by any valid blank separator: a space, a tab character or a newline.
However, as it has been said, cin extraction stops reading as soon as if finds any blank space character, so in this case we will be able to get just one word for each extraction. This behavior may or may not be what we want; for example if we want to get a sentence from the user, this extraction operation would not be useful. In order to get entire lines, we can use the function getline, which is the more recommendable way to get user input with cin:
1 // cin with strings 2 #include <iostream> 3 #include <string> 4 using namespace std; 5 6 int main () 7{ 8 string mystr; 9 cout << "What's your name? "; 10 getline (cin, mystr); 11 cout << "Hello " << mystr << ".\n"; 12 cout << "What is your favorite team? "; 13 getline (cin, mystr); 14 cout << "I like " << mystr << " too!\n"; 15 return 0; 16 }
What's your name? Juan Soulie Hello Juan Soulie. What is your favorite team? The Isotopes I like The Isotopes too!
Notice how in both calls to getline we used the same string identifier (mystr). What the program does in the second call is simply to replace the previous content by the new one that is introduced.
stringstream
The standard header file <sstream> defines a class called stringstream that allows a string-based object to be treated as a stream. This way we can perform extraction or insertion operations from/to strings, which is especially useful to convert strings to numerical values and vice versa. For example, if we want to extract an integer from a string we can write:
This declares a string object with a value of "1204", and an int object. Then we use stringstream's constructor to construct an object of this type from the string object. Because we can use stringstream objects as if they were streams, we can extract an integer from it as we would have done on cin by applying the extractor operator (>>) on it followed by a variable of type int. After this piece of code, the variable myint will contain the numerical value 1204.
1 // stringstreams 2 #include <iostream> 3 #include <string> 4 #include <sstream> 5 using namespace std; 6 7 int main () 8{ 9 string mystr; 10 float price=0; 11 int quantity=0;
12 13 14 15 16 17 18 19 20 21 }
cout << "Enter price: "; getline (cin,mystr); stringstream(mystr) >> price; cout << "Enter quantity: "; getline (cin,mystr); stringstream(mystr) >> quantity; cout << "Total price: " << price*quantity << endl; return 0;
In this example, we acquire numeric values from the standard input indirectly. Instead of extracting numeric values directly from the standard input, we get lines from the standard input ( cin) into a string object (mystr), and then we extract the integer values from this string into a variable of type int (quantity). Using this method, instead of direct extractions of integer values, we have more control over what happens with the input of numeric values from the user, since we are separating the process of obtaining input from the user (we now simply ask for lines) with the interpretation of that input. Therefore, this method is usually preferred to get numerical values from the user in all programs that are intensive in user input.
list <list> List Lists are a kind of sequence container. As such, their elements are ordered following a linear sequence. List containers are implemented as doubly-linked lists; Doubly linked lists can store each of the elements they contain in different and unrelated storage locations. The ordering is kept by the association to each element of a link to the element preceding it and a link to the element following it. This provides the following advantages to list containers: Efficient insertion and removal of elements anywhere in the container (constant time). Efficient moving elements and block of elements within the container or even between different containers (constant time). Iterating over the elements in forward or reverse order (linear time). Compared to other base standard sequence containers (vectors and deques), lists perform generally better in inserting, extracting and moving elements in any position within the container, and therefore also in algorithms that make intensive use of these, like sorting algorithms. The main drawback of lists compared to these other sequence containers is that they lack direct access to the elements by their position; For example, to access the sixth element in a list one has to iterate from a known position (like the beginning or the end) to that position, which takes linear time in the distance between these. They also consume some extra memory to keep the linking information associated to each element (which may be an important factor for large lists of small-sized elements). Storage is handled automatically by the list object, allowing it to be expanded and contracted automatically as needed. In their implementation in the C++ Standard Template Library lists take two template parameters:
Allocator: Type of the allocator object used to define the storage allocation model. By default,
the allocator class template for type T is used, which defines the simplest memory allocation model and is value-independent. In the reference for the list member functions, these same names are assumed for the template parameters.
Member functions
(constructor) Construct list (public member function) (destructor) List destructor (public member function) operator= Copy container content (public member function ) Iterators: begin Return iterator to beginning (public member function) end Return iterator to end (public member function ) rbegin Return reverse iterator to reverse beginning (public member function) rend Return reverse iterator to reverse end (public member function) Capacity: empty Test whether container is empty (public member function) size Return size (public member function) max_size Return maximum size (public member function ) resize Change size (public member function) Element access: front Access first element (public member function ) back Access last element (public member function) Modifiers: assign Assign new content to container (public member function) push_front Insert element at beginning (public member function) pop_front Delete first element (public member function) push_back
Add element at the end (public member function) pop_back Delete last element (public member function) insert Insert elements (public member function) erase Erase elements (public member function) swap Swap content (public member function ) clear Clear content (public member function) Operations: splice Move elements from list to list (public member function) remove Remove elements with specific value (public member function) remove_if Remove elements fulfilling condition (public member function template ) unique Remove duplicate values (member function ) merge Merge sorted lists (public member function ) sort Sort elements in container (public member function ) reverse Reverse the order of elements (public member function ) Allocator: get_allocator Get allocator (public member function )