Strings and text

10 minutes read

What is std::string and why is it needed?

In C++, strings can be represented in two ways:

  • C-style strings utilize char arrays to store the entire string. If you attempt to do anything with C-style strings, you'll quickly discover they are challenging to handle, easily confusing, and difficult to debug;

  • The std::string class enables you to create and manipulate strings intuitively. All the complicated implementation is conveniently hidden from us, allowing us to operate at a higher level of abstraction;

C++ inherits the string representation from C and fully supports the C-style strings:

#include <iostream>

int main() {
    char myString[] = "Hello, C-style strings!";
    std::cout << myString << std::endl;
    return 0;
}

Typically, std::string strings are used in C++ due to a number of advantages. However, understanding the structure of C-style strings is very important, as they can be useful in some situations (a detailed discussion is beyond this topic's scope).

In C++, a string is an object of the std::string class in the std (standard) namespace, representing a sequence of characters. It is a part of the C++ Standard Library. Working with strings via std::string is very straightforward:

#include <iostream>

int main() {
    std::string myString = "Hello, World!";
    return 0;
}

In C++, strings can be initiated in several ways. Here are some of the most common methods:

std::string str1; // Default initialization
std::string str2 = "Hello, World!"; // Initialization with a string literal
std::string str3(str2); // Copy initialization
std::string str4 = str3; // Assignment using another string

Strings are a way to represent textual data. Here's what you can do with them:

  • String manipulation. C++ offers various methods to manipulate strings. These include functions to:

    1. Append text to a string (append(), push_back(), +=);

    2. Insert or remove characters in a string (insert(), erase());

    3. Replace parts of a string (replace());

    4. Find substrings or characters (find(), rfind(), find_first_of(), find_last_of());

  • String comparison. Strings can be compared using relational operators (==, !=, <, >, <=, >=). The comparison is made lexically, similar to dictionary order.

  • String conversion. Sometimes, you need to convert strings to numbers or vice versa. C++ provides several functions for this purpose:

    1. std::stoi(): Converts a string to int;

    2. std::stof(), std::stod(): Converts a string to float and double respectively;

    3. std::to_string(): Converts numerical values to a string.

Let's explore this functionality in more detail:

String manipulation

Appending text to a string. You can append text to a string using the append() function, the push_back() function, or the += operator (just like with numbers):

std::string greeting = "Hello";
greeting.append(", World!"); // greeting is now "Hello, World!"

std::string welcome = "Hello";
welcome += ", World!"; // welcome is now "Hello, World!"

std::string additionalText = "Hello";
std::string result = greeting + additionalText; // result is now "Hello, World!Hello"

std::string phrase = "Hello";
phrase.push_back('!'); // phrase is now "Hello!"

Inserting or erasing characters in a string. The insert() function adds a string at a specified position. The erase() function removes a part of the string.

std::string originalMessage = "Hello, World!";
originalMessage.insert(6, " beautiful"); // originalMessage is now "Hello, beautiful World!"

std::string modifiedMessage = "Hello, beautiful World!";
modifiedMessage.erase(6, 10); // modifiedMessage is now "Hello, World!"

⚠️ Don't forget that strings are arranged like an array, and their indexing, just like an array, starts from 0.

Replacing parts of a string. The replace() function replaces a part of the string with another string:

std::string greeting = "Hello, World!";
greeting.replace(7, 5, "there"); // greeting is now "Hello, there!"

Finding substrings or characters. The find() function returns the position of the first occurrence of a substring. If the substring is not found, it returns -1. The rfind() function returns the position of the last occurrence of a substring:

std::string text = "Hello, World!";
int indexOfWorld = text.find("World");
if (indexOfWorld != -1)
    std::cout << "'World' found at: " << indexOfWorld << '\n';

int lastIndexOfO = text.rfind("o");
if (lastIndexOfO != -1)
    std::cout << "Last 'o' found at: " << lastIndexOfO << '\n';

In addition to searching, very often you need to select part of a line from the text.

The substr() method returns a substring. It takes two arguments: the index where the substring starts and the length of the substring. If the second argument is omitted, the substring includes all characters from the start index to the end of the string.

std::string str = "Hello, World!";
std::cout << "Substring: " << str.substr(7, 5) << '\n'; 
// Outputs: Substring: World

These are just a few examples of string manipulation in C++. The std::string class provides many more functions to handle text efficiently. Working with other methods follows a similar principle. Once you understand how to work with these methods, you can easily check the name in the documentation and use it.

For example, have a look at the Operations section here: https://en.cppreference.com/w/cpp/string/basic_string

String comparison

In C++, you can compare strings using relational operators (==, !=, <, >, <=, >=). The comparison is done lexically, which is similar to dictionary order. Here are some basic string comparison examples:

Equality and inequality. The == operator checks if two strings are equal (i.e., they contain exactly the same characters in the same order). The != operator checks if two strings are not equal:

std::string greeting = "Hello";
std::string target = "World";
std::string anotherGreeting = "Hello";

if (greeting == anotherGreeting)
    std::cout << "greeting and anotherGreeting are equal" << '\n';

if (greeting != target)
    std::cout << "greeting and target are not equal" << '\n';

Lexicographic comparison. The <, >, <=, >= operators compare strings lexicographically.

std::string fruit1 = "apple";
std::string fruit2 = "banana";

if (fruit1 < fruit2)
    std::cout << "fruit1 comes before fruit2 in the dictionary" << '\n'; 

The word "apple" comes before "banana" in the dictionary refers to the concept of lexicographic (or dictionary) order. So, "apple" comes before "banana" in the dictionary because 'a' is before 'b' in alphabetical order.

When comparing two strings lexicographically, the comparison is done character by character starting from the first character. If the first characters of both strings are the same, then the second characters are compared, and so forth. When a difference is found, the string with the smaller character (according to the character set order) comes first. If one string is a prefix of the other, the shorter string comes first.

Understanding string comparison is important for tasks such as sorting words, verifying password equality, and many other tasks.

String conversion

In C++, you may often have to convert other data types into strings or vice versa. This is especially useful when working with different I/O sources. We can't predict what data we might receive, and the most practical approach is to accept it as a regular string and then convert it to the desired type. Here are a few examples:

Converting numbers to strings. The std::to_string() function converts a number to a string.

int i = 123;
std::string s = std::to_string(i); // s is now "123"

double d = 3.14;
std::string s2 = std::to_string(d); // s2 is now "3.140000"

The inversion of it - converting strings to numbers. Many methods are available for different types, but you can Google them when you need them. Here are the most used (the std::stoi() and std::stod() functions convert a string to an integer and double):

std::string s = "123";
int i = std::stoi(s); // i is now 123

std::string s2 = "3.14";
double d = std::stod(s2); // d is now 3.14

⚠️ If the string can't be converted to a number, these functions will throw an std::invalid_argument exception. If the number is out of the range of the target numeric type, they will throw an std::out_of_range exception.

These are just a few examples of string conversions in C++. There are many more functions in C++ and its standard library that can help you convert between strings and other data types. But their operating principle is similar.

String processing

Here are a few more frequently used methods that are hard to classify into any of the above groups, but are used in almost every program:

The empty() method returns a boolean value indicating whether the string is empty (i.e., whether its size is 0):

std::string s = "";
std::cout << std::boolalpha << "Is empty: " << s.empty() << '\n'; // Outputs: True

The length() and size() methods return the number of characters in the string. These two methods are equivalent and can be used interchangeably:

std::string s = "Hello, World!";
std::cout << "Length: " << s.length() << '\n'; // Outputs: Length: 13
std::cout << "Size: " << s.size() << '\n'; // Outputs: Size: 13

The [] operator and the at() method provide access to a character at a specified index. The [] operator does not verify if the index is valid, while at() throws an std::out_of_range exception if the index is invalid:

std::string s = "Hello, World!";
std::cout << "Character at index 7: " << s[7] << '\n'; // Outputs: Character at index 7: W
std::cout << "Character at index 7: " << s.at(7) << '\n'; // Outputs: Character at index 7: W

⚠️ If the index is out of the range of the string, the at() function will throw an std::out_of_range exception. Therefore, it is preferable to use at() as it is also faster.

Conclusion

In C++, a string is an object of the std::string class that represents a sequence of characters. It enhances text manipulation by providing clarity and power through intuitive functions. You don't need to work directly with the character array, as is the case with C-style strings.
The class provides a vast set of convenient methods for various tasks: you can initialize, assign, manipulate, compare, and convert strings. Once you understand how to work with basic string processing methods, it'll be easy to work with others by referencing the documentation because of their similar principles.

3 learners liked this piece of theory. 0 didn't like it. What about you?
Report a typo