2.4. The string class¶
Like a byte string, a std::string is storage for a character sequence:
#include <string> // access std::string functions
using std::string; // alias type std::string to 'string'
int main() {
string x; // empty string
string greet = "Hello, World!"; // create from C string
string hello ("Hello, World!"); // as above, constructor style syntax
string howdy = {"Hello, World!"}; // C++11 only
string howdy {"Hello, World!"}; // as above, = is optional
return 0;
}
What is different is that a std::string is a full-fledged object.
It knows it's own size, and comes with many convenience functions.
Notice that unlike a built-in variable declaration such as int x;,
the declaration string x is not incomplete.
The variable x is a complete and valid string object
that stores no characters.
Simple operations
1#include <iostream>
2#include <string>
3
4using std::string;
5
6int main() {
7 string a = "hello";
8 a += ", world!"; // joining strings is pretty easy
9
10 // Copying or creating one string from another feels as natural
11 // as a fundamental type.
12 string b = a;
13
14 if (a == b) // Same goes for comparisons
15 {
16 // modify values
17 b[0] = 'H'; // and a string feels like an 'array of char'
18 b[7] = 'W';
19 }
20
21 std::cout << a << '\n'; // and has stream support
22 std::cout << b << '\n';
23
24 return 0;
25}
front() and back()
This tab shows alternate functions for accessing the first and last characters in a string.
1#include <iostream>
2#include <string>
3
4int main() {
5 std::string value = "hello, world!";
6
7 std::cout << "first: " << value.front() << '\n';
8 std::cout << "last: " << value.back() << '\n';
9 return 0;
10}
append()
The append function allows you to append N copies of a character or
an array of characters to the end of a string.
1#include <iostream>
2#include <string>
3
4int main() {
5 using std::cout;
6 std::string hi = "hello";
7 std::string howdy = hi;
8
9 cout << "original: " << hi << '\n';
10
11 hi.append(5, 'o'); // append 5 o's
12 hi.append(", world!");
13 cout << hi << '\n';
14
15 cout << "original: " << howdy << '\n';
16
17 // append returns a new string value, so
18 // calls to append can be chained together
19 howdy.append(5, 'o').append(", world!");
20 cout << howdy << '\n';
21
22 return 0;
23}
insert()
The insert function allows you to insert 1 character or
an array of characters at a position in a string.
1#include <iostream>
2#include <string>
3
4int main() {
5 std::string value = "hello, world!";
6
7 std::cout << "original: " << value << '\n';
8
9 value.insert(0,3,'*'); // insert "***" at position 0
10 std::cout << value << '\n';
11
12 // insert a char array before the '!'
13 value.insert(value.size()-1," (this means you)");
14 std::cout << value << '\n';
15
16 return 0;
17}
Using the operator[] to access select characters in a string is,
like an array,
not range checked.
This means that if you use an index referring to an invalid position,
then your program might have undefined behavior, or fail unexpectedly.
You can use the function at anywhere operator[] is allowed.
The at function is range checked.
While there is a cost associated with this check,
if the index provided is out of range,
then an std::out_of_range exception is thrown,
which must be caught,
otherwise the program will terminate.
if (a == b)
{
b.at(0) = 'H'; // might be OK
b.at(-1) = 'W'; // never OK. throws exception
}
Remember that a std::string is not a byte string.
std::string is a class.
A decision was made long ago that in order to remain more compatible with
C, double quited strings should evaluate to byte strings.
Declarations like this are a common source of confusion for new programmers:
auto my_string = "Howdy!";
What type is my_string?
Show
my_string is not a std::string.
The default type for characters enclosed in double quotes is const char*.
This is one of those situations where auto may not be deducing the type
you actually want.
There are several simple ways to use auto and get the type
deduced to be a std::string.
Example
C++14 Feature
Adds the concept of a std::string literal to the language.
You can simply append an s to the end of the quoted string.
This identifies the literal as type std::string instead of
const char*.
auto my_string = "Howdy!"s; // preferred
Alternatively, you can call the string constructor explicitly, which works for C++ versions older than C++14.
auto my_string = string("Howdy!");
auto your_str = string{"Howdy!"}; // C++11 initialization syntax
Run It
1#include <string>
2#include <iostream>
3#include <iomanip> // std::quoted
4
5int main()
6{
7 using namespace std::string_literals;
8 using std::string;
9
10 auto my_string = "Howdy!"s;
11 auto howdy2 = string("Howdy!");
12 auto your_str = string{"Howdy!"}; // C++11 initialization syntax
13
14 string s1 = "abc\0\0def";
15 string s2 = "abc\0\0def"s;
16
17 std::cout << "s1: " << s1.size() << ' ' << std::quoted(s1) << '\n';
18 std::cout << "s2: " << s2.size() << ' ' << std::quoted(s2) << '\n';
19}
Note
Look carefully at the size values printed for s1 and s2.
Are those sizes expected? Why or why not?
2.4.1. Getting information out of a string¶
A string knows its own size and can provide other useful information.
1#include <cassert>
2#include <string>
3using std::string;
4int main() {
5 string my_string = "Hello";
6
7 assert( my_string.size() == 5 ); // .length() is available also
8 if (!my_string.empty()) {
9 my_string += ", there."; // my_string == "Hello, there."
10 }
11 return 0;
12}
And the string class provides many functions dedicated to finding substrings within a string.
Example: find
The simplest example is the find function.
Given any string object, for example, this string:
auto us = "team"s;
defined using the string literal syntax,
creates a new object us.
Once we have a string, calling the string member function
find always returns a position:
Either a position within the string, or
The special value std::string::npos which means the value was not found in the string.
We can use this to check if we found what we were looking for:
size_t pos = us.find('i');
if(pos == std::string::npos) {
std::cout << "There is no 'i' in 'team'\n";
}
The position returned by find is a zero-based index into the string.
Find can also take a sequence of characters.
In that case, it returns the position to the first char
where the entire sequence is matched.
Reverse find
Similar to find, rfind performs the same
task as find, but iterates through the string in reverse order:
starting at the end and moving towards the first character.
Keep in mind that the position returned is still based
on the same index positions as regular find.
Find first of
The find_first_of function takes a char sequence,
but unlike find where the entire sequence is used to find a match,
find_first_of examines each character in the sequence,
on at a time, and returns the minimum position of any
of the characters listed as function arguments in the string.
For example:
auto hi = "Hello world"s;
pos = hi.find("wor"); // pos == 6
if (hi.find('o') == hi.rfind('o')) {
std::cout << "There must be exactly 1 'o' in this string\n";
}
pos = hi.find_first_of("aeiou"); // pos == 1 (e)
The function returns the position of 'e' in 'Hello world', even though 'e' and 'o' are both present, because 'e' is first.
The order of the character arguments do not matter. The results would be exactly the same if the arguments were 'uoiea'. Don't take my word for it, try it yourself.
Run It
1#include <iostream>
2#include <string>
3
4using namespace std::literals;
5
6int main() {
7 auto us = "team"s;
8 size_t pos = us.find('i');
9 if(pos == std::string::npos) {
10 std::cout << "There is no 'i' in 'team'\n";
11 }
12 auto hi = "Hello world"s;
13 pos = hi.find("wor"); // pos == 6
14
15 if (hi.find('o') == hi.rfind('o')) {
16 std::cout << "There must be exactly 1 'o' in this string\n";
17 }
18 pos = hi.find_first_of("aeiou"); // pos == 1 (e)
19 pos = hi.find_first_not_of("aeiou"); // pos == 0 (H)
20
21 return 0;
22}
The special value std::string::npos is used both as an end of string indicator by functions that expect a string and as an indicator of not found by functions that return an index (like find).
Open video
2.4.2. Convert a byte string to a number¶
Another common string task is parse a C string and extract a numeric value.
The number conversion functions are part of the string header.
There are number conversion functions that C++ inherits from C.
They are all in the cstdlib header.
Of these C functions, the atoi and atof functions should not be used.
They fail silently.
That is if something bad happens, there is no way to check and even detect
whether the function completed its task.
stoi()
stoi extracts an integer value from a string.
stoi discards any whitespace characters until the first non-whitespace
character is found,
then takes as many characters as possible to form a valid integer
number representation and converts them to an integer value.
The valid integer value consists of the following parts:
an optional plus or minus sign
the digits 0-9
1#include <string>
2#include <iostream>
3
4int main() {
5 std::cout << std::stoi("42") << '\n';
6
7 const char* str_pi = "3.14159";
8 std::cout << std::stoi(str_pi) << '\n';
9}
stod()
stod extracts an floating point value from a byte string.
Other than return value, it functions similarly to stoi.
1#include <string>
2#include <iostream>
3
4int main()
5{
6 std::cout << std::stod("42") << '\n';
7
8 std::cout << std::stod("0.0000000123") << "\n"
9 << std::stod("0.012") << "\n"
10 << std::stod("15e16") << "\n"
11 << std::stod("-0x1afp-2") << "\n"
12 << std::stod("inf") << "\n"
13 << std::stod("Nan") << "\n";
14}
All of these functions allow for error handling, which we will cover in a future chapter. For now, know that these function will generate errors if given bad or unexpected input.
2.4.3. Converting a std::string to a C string¶
You cannot use std::string in a function
that expects const char* - you must convert it
to a null terminated character array.
auto my_name = "Alice"s;
printf ("Hello again, %s\n", my_name); // compile error!
// the c_str() function converts a string into a c string
printf ("Hello again, %s\n", my_name.c_str());
Self Check
Q1
Given the following:
std::string x = "The rain in Spain. . . ";
size_t pos = x.find("in");
What is the value of pos?
Q2
-
auto snowflake = us.find_first_of("Korea"); -
if (snowflake == std::string::npos) { -
int main() { -
std::cout << "Did not find anything\n"; -
std::cout << "Found it!\n"; -
std::string us = "Team USA"; -
} -
} return snowflake; -
} else {
Q3
Given the following:
#include <string>
int main (){
std::string s = "Donald Duck";
int value = 0;
if (s.find_first_of(' ') == s.find_last_of(' ')) {
value = 3;
} else {
value = 5;
}
return value;
}
What value is returned from main?
More to Explore
cppreference.com Strings library overview
YoLinux String class tutorial
Bjarne Stroustrup's C++11 FAQ: Raw String literals