6. Strings in C++#
While C++ has full support for C-style strings, programmers should instead utilize the string
class. Objects of this class represent strings as variable-length sequences of characters. Unlike immutable strings in Java and Python, C++ strings are mutable. (Note: C-style strings are discussed in the “Built-in Arrays” notebook.)
To use the string type, you need to include the string header. You can put the “using std::string;” line in your source code to use just the string
type rather than having to include the std::
namespace identifier or bring in the entire std
namespace.
#include <string>
using std::string;
The string class provides significant advantages in that the class manages memory and overrides the standard operators such as ==
to check for equality and +
for string concatenation.
The following code demonstrates variaous ways to define and initialize strings:
1//filename: string_init.cpp
2//complile: g++ -std=c++17 -o string_init string_init.cpp
3//execute: ./string_init
4#include <iostream>
5#include <string>
6using std::string;
7
8int main(int argc, char *argv[]){
9 string s1; // defualt initialization, string is empty
10 string x = "hello world"; // Uses a conversion constructor
11 string y("John");
12 string z{"Steve"};
13 string w{y}; // w is a copy of y
14
15 std::cout << x << "\n" << s1 << "\n" << y << "\n" << z << "\n";
16}
6.1. String Operations#
Fortunately, the string
class provides a comprehensive range of functionality for strings, similar to what’s available with Python. The class handles memory management as well.
1//filename: greeting.cpp
2//complile: g++ -std=c++17 -o greeting greeting.cpp
3//execute: ./greeting
4#include <iostream>
5#include <string>
6using namespace std;
7
8int main(int argc, char *argv[]) {
9 string name;
10
11 cout << "What is your name?" << endl;
12 cin >> name;
13 cout << "It's nice to meet you, " << name << "\n";
14}
You should compile and run this code to see the behavior when entering different strings through the console.
Try typing in your full name. You should notice that cin
separates items by whitespace and only the first portion of the name is returned. (e.g, for “Steve Smith” only “Steve” is returned in the string.)
To read a full line of input, we can use the getline() function. Notice that getline()
does strip the newline character, unlike similar counterparts in Python and C.
1//filename: line.cpp
2//complile: g++ -std=c++17 -o line line.cpp
3//execute: ./line
4#include <iostream>
5#include <string>
6using namespace std;
7
8int main(int argc, char *argv[]) {
9 string name;
10
11 cout << "What is your name?" << endl;
12 if (getline(cin,name)) {
13 cout << "It's nice to meet you, " << name << "XXXXX" << "\n";
14 }
15 else {
16 cout << "No input available\n";
17 }
18}
Run the program. Type in your full name as a test.
How can you get the “No input available message” to appear? (anwer at the bottom of the page)
Here’s another example of getline()
to just echo input from standard input:
1//filename: echo.cpp
2//complile: g++ -std=c++17 -o echo echo.cpp
3//execute: ./echo
4#include <iostream>
5#include <string>
6using namespace std;
7
8int main(int argc, char *argv[]) {
9 string line;
10
11 cout << "Type some data to echo. Hit ctrl-d when you are complete." << endl;
12 while (getline(cin,line)) {
13 cout << line << "\n";
14 }
15}
Here’s some additional sample code of the string
class in use:
1//filename: example.cpp
2//complile: g++ -std=c++17 -o example example.cpp
3//execute: ./example
4#include <iostream>
5#include <string>
6using namespace std;;
7
8int main(int argc, char *argv[]){
9 string s1; // default initialization, string is empty
10 string x = "hello"; // Uses the copy-assignment operator for the given literal
11 string y("John"); // y is a copy of the string literal
12
13 if (s1.empty()) {
14 cout << "s1 was empty, but has a capacity of "<< s1.capacity() << "\n";
15 }
16
17 if (not x.empty()) {
18 cout << "x has a length of " << x.length() << " with capacity - " << x.capacity() << "\n";
19 cout << "x has a length of " << x.size() << "\n"; //size was added for consistency with the standard library
20 }
21
22 x += " world"; // concatenation, existing object is altered - C++ strings are mutable
23 cout << x << " - length: " << x.length() << ", capacity: " << x.capacity() << "\n";
24
25 if (x == y) { // comparison operators overloaded
26 cout << "strings are the same" << "\n";
27 }
28 else {
29 cout << "the two strings differ" << "\n";
30 }
31
32 cout << x.substr(0,5) << "-"<< x.substr(6) << "\n";
33
34 string line = "It was the best of times, it was the worst of times";
35 cout << line.find("best") << "\n";
36
37 // npos is constant containing the largest possible size
38 // of a string (same as max value of size_t)
39 // As find returns an unsigned value, -1 is not feasible so the
40 // largest possible value is used to signify a string was not found.
41 cout << (line.find("greatest") == string::npos) << "\n";
42}
https://en.cppreference.com/w/cpp/string/basic_string lists all of the available methods on the string
class.
Here’s an example to split a line by a specific string delimiter. In lines 10 & 11, the auto
keyword is used to automatically declare a variable of the appropriate type based upon the results of the left hand side of this equation.
This process works by tracking two positions within a string as we seek to find the delimiter within the string. start
tracks the current beginning of an extracted/found token. We can pass that value to find as an optional parameter to say “starting looking for the delimiter at this position”. end
tracks where we have last seen the delimiter. if a delimiter was not found, find returns string::npos
(think of that as no position), which equals the maximum size of an unsigned long int.
1//filename: split.cpp
2//complile: g++ -std=c++17 -o split split.cpp
3//execute: ./split
4#include <iostream>
5#include <string>
6using namespace std;
7
8int main(int argc, char *argv[]) {
9 string s = "java:c:c++:Python:Pascal:Basic";
10 string delim = ":";
11
12 auto start = 0U;
13 auto end = s.find(delim);
14 while (end != string::npos) {
15 std::cout << s.substr(start, end - start) << "\n";
16 start = end + delim.length();
17 end = s.find(delim, start);
18 }
19
20 std::cout << s.substr(start, end) << "\n";
21 std::cout << "Final value of end: " << end << "\n";
22}
6.2. Converting Strings to Other Types#
As part of the Standard Library, C++ contains several functions to convert strings to numerical values:
floating-point numbers: https://en.cppreference.com/w/cpp/string/basic_string/stof
“integer” numbers: https://en.cppreference.com/w/cpp/string/basic_string/stol
1//filename: convert.cpp
2//complile: g++ -std=c++17 -o convert convert.cpp
3//execute: ./convert
4#include <iostream>
5#include <string>
6#include <stdexcept>
7using namespace std;
8
9int main(int argc, char *argv[]) {
10 double d;
11 string line;
12
13 cout << "Type some data to convert a double. Hit ctrl-d when you are complete." << endl;
14 while (getline(cin,line)) {
15 try {
16 d = std::stod(line);
17 cout << "Converted number: " << d << "\n";
18 } catch (const std::invalid_argument&) {
19 cerr << "Invalid argument: " << line << "\n";
20 } catch (const std::out_of_range&) {
21 cerr << "out of range of double: " << line << "\n";
22 }
23 }
24
25 return EXIT_SUCCESS;
26}
The try-catch
statements will be discussed in the error handling and exceptions notebook.
6.3. Implementation Notes#
Behind the scenes, C++ uses an array (a contiguous segment of memory holding char
objects) to store strings. The string
class tracks the length(size) of the string stored within that array as well as the available capacity - the number of objects allocated. Looking at the example above, we see that C++ (at least this implementation) uses a default capacity of 15 to hold string values. As the string expands, the capacity will be increased when needed. We’ll present more details of this implementation when we discuss memory location and allocation in C++.
6.4. End of File#
To end input from the console, type ctrl-d. This closes the input stream immediately and returns EOF
.