4.6. C++ Standard Library#
The standard library of C++ includes many classes and function that
helps to conduct commonly needed operations. We have already used some
of these in the previous chapters i.e. string, iostream, fstream.
We will now examine more of these classes and functions. For a complete
list of all functions and classes, you can search the Internet.
4.6.1. The string library#
Although we have seen some basic usage of the string class, we havenât
examine some handy functions and operators of this class. For example,
the + operator can be used in order to concatenate two strings. The
program below prints word1 and word2 to the screen:
#include <string>
#include <iostream>
int main(){
std::string a = "word1";
std::string b = " and";
std::string c = " word2";
std::string out = a + b + c;
std::cout << out << std::endl;
return 0;
}
Also if you want to learn the length of the string, you can use the
function size:
int string_size = out.size();
If you want to clear the content of the string, or check whether it is
empty or not you can use the clear and empty functions as follows.
out.clear();
if (out.empty())
std::cout << "String is empty" << std::endl;
The last function that we will examine is insert, which is used to
insert characters to specified parts of the string. Letâs check the
program below:
#include <string>
#include <iostream>
int main(){
std::string a = "word1";
std::string b = " and";
std::string c = " word2";
std::string out = a + c;
out.insert(5,b);
std::cout << out << std::endl;
return 0;
}
Here the out string first stores "word1 word2".
Then, the insert function inserts the string b to the 5th position of out string, and the
out string becomes "word1 and word2".
Since a string is a sequence of characters, it also behaves similar as an array,
meaning that we can use [ ] operator get or set a character at a specific location in the string:
#include <iostream>
#include <string>
int main ()
{
std::string msg = "hello world!";
std::cout << msg[0] << std::endl; // get first character 'h'
std::cout << msg[ msg.size() -1 ] << std::endl; // get last character '!'
// change the space with an underscore
msg[5] = '_'; // note: single characters use single quotes ', not "
std::cout << msg << std::endl;
return 0;
}
4.6.2. The vector class#
Vectors are just like arrays, but they have some additional functions which provides flexibility. Declaring a vector with default constructor is done by:
std::vector<[TYPE]> [NAME];
For example, the following creates an empty vector for storing integers:
std::vector<int> my_vec;
Important
Here letâs have a short brake to talk about a C++ feature called templates.
The < > syntax here indicates that the std::vector class is actually a template.
Templates enable to write functions or classes without specifying yet a specific type.
Instead, the code treats the type as an unknown variable itself.
When using a programmer want to use the template function or class, they need to specify the type they want to use
by specifying the needed type in the < > brackets.
Templates prevent the need to duplicate code (and thus bugs) to reimplement very similar classes or functions for
slightly different data types: one generic template implementation can be reused for many types.
For example, the std::vector template class can be used to create a resizable array of ints by
specifying std::vector<int>, but also a resizable array of strings via std::vector<std::string>.
You can even create a vector of vectors, e.g. std::vector< std::vector<int> >!
Defining templates and their more advanced uses is outside the scope of this manual. But templates are used a lot throughout the C++ Standard Library, so recognizing them and having a basic understanding of how to use them is important.
While declaring a vector, the content can also be set.
For instance, the following vector is initialized for storing
5 integers with all the values set as 0.
std::vector<int> my_vec(5,0);
A vector can even be initialized with some known initial values using the following syntax:
// initialize an int vector with two integers: 42 and -99
std::vector<int> my_vec = {42, -99};
Just as with regular arrays, an element of a vector can be accessed with [ ] operators.
my_vec[2]; // third element, since first element is at 0
The size of a vector indicates how many values it current contains.
Similar to the std::string class, the std::vector also has a size() method to return the number of items in the vector:
#include <iostream>
#include <vector>
int main ()
{
std::vector<int> a_vec;
std::cout << "size of a_vec: " << a_vec.size() << std::endl; // size = 0
std::vector<int> my_vec = {-2, -1, 0, 1, 2};
std::cout << "size of my_vec: " << my_vec.size() << std::endl; // size = 5
return 0;
}
One of the benefits of vectors over basic arrays is that their size is not fixed,
and that elements can be added or removed.
Two handy methods of vectors are push_back and pop_back.
push_back is used to add elements to the end of the
vector, and pop_back erases the last element of the vector, and
decreases the size by one.
Here is a basic example illustrating how push_back and pop_back alter a vectorâs size:
#include <iostream>
#include <vector>
int main ()
{
// empty vector
std::vector<int> a_vec;
std::cout << "size of a_vec: " << a_vec.size() << std::endl; // size = 0
// add some ints
a_vec.push_back(42);
std::cout << "size of a_vec: " << a_vec.size() << std::endl; // size = 1
a_vec.push_back(-99);
std::cout << "size of a_vec: " << a_vec.size() << std::endl; // size = 2
// remove some ints
a_vec.pop_back();
std::cout << "size of a_vec: " << a_vec.size() << std::endl; // size = 1
a_vec.pop_back();
std::cout << "size of a_vec: " << a_vec.size() << std::endl; // size = 0
return 0;
}
Using the size() and [ ] operators, it is easy to loop over all elements in a vector using a basic for-loop:
#include <iostream>
#include <vector>
int main ()
{
// make a vector
std::vector<int> a_vec = {42, -99};
// display all elements
for(unsigned int index = 0; index < a_vec.size(); index++) {
std::cout << "a_vec[" << index << "] = " << a_vec[index] << std::endl;
}
}
If your loop doesnât even need to know the index at every iteration, then you can use even a shorter loop notation:
#include <iostream>
#include <vector>
int main ()
{
// make a vector
std::vector<std::string> a_vec = {"hello", "world"};
// display all elements
for(std::string a_value : a_vec) {
std::cout << "next value: " << a_value << std::endl;
}
return 0;
}
Here is a more complex example combining a std::vector and a std::string:
#include <iostream>
#include <vector>
#include <string>
int main ()
{
// get user input as a single string with spaces
std::string response;
std::cout << "Enter your favorite fruits with empty spaces in between." << std::endl;
std::getline(std::cin, response);
// fruits vector will store the separated fruit words
std::vector<std::string> fruits;
unsigned int count = 0;
std::string word_str;
// loop over the user input, looking for spaces that demark words
for(unsigned int index = 0; index < response.size(); index++) {
if(response[index] == ' ') {
// current character is a space!
// word_str is a complete word, so add it to fruits vector
fruits.push_back(word_str);
word_str = "";
}
else {
// character is not a space, add the character to the current word
word_str = word_str + response[index];
}
}
// no more spaces found till end of input, so last word is also complete
fruits.push_back(word_str);
// print all fruits on separate lines
for(unsigned int index = 0; index < fruits.size(); index++) {
std::cout << "Fruit number " << (index + 1) << " is " << fruits[index] << std::endl;
}
return 0;
}
In this program, the response of the user is acquired with the getline
command. In a for loop, the characters are accumulated in word_str
string, until an empty space is encountered. When empty space is
reached, word_str is added to the fruits vector by the
push_back command. This process continues until the end of the
response string. In order to add the last word, push_back
function is called once again after the for loop. The output is then
printed with a for loop.
Apart from push_back and pop_back, other commonly used
functions of this class are the following: resize sets a new size
for the vector, insert inserts elements to the specified location,
clear erases the elements of the vector and sets its size to zero,
and erase erases specified elements.
Exercise 4.13
Write a program that requests a series of numbers from the user, finds the peaks of this series, stores them in a vector, and prints them to the console.
For example, if the input is 1 2 3 4 5 4 3 2 3 4 3 2 1, then the peaks
should be found as 5 and 4.
4.6.3. The map class#
Maps are for storing elements as pairs. The declaration is as follows:
std::map<[TYPE 1], [TYPE 2]> [NAME]
Note
As you can see, std::map is also a template class, but one where two types need to be specified.
Letâs examine the following example to make it clear:
#include <iostream>
#include <string>
#include <map>
int main () {
std::map<std::string, int> teams_ranks;
teams_ranks["Team 1"] = 3;
teams_ranks["Team 2"] = 1;
teams_ranks["Team 3"] = 2;
teams_ranks["Team 4"] = 5;
teams_ranks["Team 5"] = 4;
std::cout << " Results:" << std::endl;
std::cout << "Team 1: " << teams_ranks["Team 1"] << '\n';
std::cout << "Team 2: " << teams_ranks["Team 2"] << '\n';
std::cout << "Team 3: " << teams_ranks["Team 3"] << '\n';
std::cout << "Team 4: " << teams_ranks["Team 4"] << '\n';
std::cout << "Team 5: " << teams_ranks["Team 5"] << '\n';
return 0;
}
In this example five strings are mapped to some integers. You can see how this mapping can be done and how to access to these entries.
While using loops with maps, a common way is to use iterators. Check the following example:
#include <iostream>
#include <string>
#include <map>
int main ()
{
std::map<std::string,int> teams_ranks;
teams_ranks["Team 1"]=3;
teams_ranks["Team 2"]=1;
teams_ranks["Team 3"]=2;
teams_ranks["Team 4"]=5;
teams_ranks["Team 5"]=4;
cout << " Results:" << endl;
for (std::map<std::string,int>::iterator it = teams_ranks.begin(); it != teams_ranks.end(); ++it) {
std::cout << it->first << ": " << it->second << std::endl;
}
return 0;
}
The output of the last two examples are exactly the same. As you can see
the map class has an iterator type. By iterators, you can access or
modify the map objects. The iterator in the example starts from the
beginning of the team_ranks map, and scans it to the end. The
first attribute of the iterator has the value of the string, and
second holds the integers mapped to them.
Exercise 4.14
Write a program that asks five questions to the user, and stores the corresponding answers in a map structure. Then, print the questions and answers to the console.
Exercise 4.15
Write a program that is similar to Exercise 4.13, but this time also record the locations of the peaks together with the peak values.
For example, if the input is 1 2 3 4 5 4 3 2 3 4 3 2 1,
then the peaks should be found as 5 and 4, and these peaks are
located at 5 and 10.