One of the first articles of C++ lets you master the string class (understand and use)

insert image description here

1. Why should we learn the string class

Learning the string class is a very important step in C++. The string class is a class provided by the C++ standard library for processing strings. Compared with the string processing functions in C language, it is more advanced, flexible and safe. Here are some great reasons to learn the string class:

  1. Powerful functions : The string class provides a wealth of member functions and operators for processing string splicing, searching, replacing, intercepting, inserting and other operations. Use the string class to more easily implement complex string processing tasks.
  2. Security : The string class automatically handles the memory allocation and release of strings, and is not prone to security issues such as buffer overflows like character arrays in C language. Using the string class effectively avoids many of the security holes associated with character arrays.
  3. Readability : Using the string class can make the code more readable. You don't need to pay too much attention to the underlying character processing, but use member functions and operators to manipulate strings to make the code clearer.
  4. Convenience : The string class can directly perform operations such as assignment, comparison, and connection without additional library function support, making code writing more concise.
  5. STL versatility : The string class is part of the C++ Standard Template Library (STL). Learning the string class is also to better understand and use other components of STL, such as vectors, linked lists, maps, etc.
  6. Wide range of practical applications : In C++ development, string processing is a common task, learning the string class can make you more handy in actual development.

Overall, learning the string class is very important to mastering C++ programming. It is a common tool for processing strings, allowing you to write code more efficiently, improve the quality and readability of code, and help you better deal with string processing tasks in actual development.
insert image description here

2. The string class in the standard library

2.1 Instantiation standard of string class

Class instantiation standards are divided into four types: string, u16string, u32string and wstring. They are all classes used to represent strings in C++, but their underlying character types and encoding methods are different:

string:

Bottom character type: char
Encoding method: Use single-byte encoding, usually ASCII or UTF-8 encoding.
Example:std::string myString = "Hello, world!";

u16string:

Underlying character type: char16_t
Encoding method: Use two bytes to represent a character, usually UTF-16 encoding.
Example:std::u16string myString = u"Hello, world!";

u32string:

Underlying character type: char32_t
Encoding method: Use four bytes to represent a character, usually UTF-32 encoding.
Example:std::u32string myString = U"Hello, world!";

wstring:

Underlying character type: wchar_t
Encoding method: wide character encoding, which can be UTF-16 or UTF-32, depending on the platform.
Example:std::wstring myString = L"Hello, world!";

It should be noted that different compilers and platforms may have different implementations of wide character encoding. On Windows platforms, wchar_t is usually 16-bit, while on some other platforms it may be 32-bit. Therefore, you need to pay attention to platform differences when using wstring.

The choice of which string type to use depends on your specific needs.Usually, if the program does not involve multilingual characters or Unicode characters, using string is sufficient. If you need to handle multilingual characters or Unicode characters, you can choose u16string, u32string or wstring according to your needs.
insert image description here
These differences are due to the different standards created according to different language requirements during encoding, such as the UTF-8 encoding standard. UTF-8 is a variable-length Unicode encoding method that can represent almost all characters in the world. characters, including ASCII characters and other international characters. In C++, the string class uses the single-byte char type to store characters, so it can be directly used to process UTF-8 encoded strings.

In UTF-8 encoding, ASCII characters (characters in the range 0-127) occupy only one byte, while other characters may occupy multiple bytes, usually 2 or 3 bytes. Since the string class uses the single-byte char type, it can handle UTF-8 encoded strings directly without additional conversion or processing.

Here is an example showing how to use the string class to handle UTF-8 encoded strings:

#include <iostream>
#include <string>

int main() {
    
    
    std::string utf8String = u8"Hello, 世界!";
    std::cout << utf8String << std::endl;
    return 0;
}

In the above example, we use the u8 prefix to represent a UTF-8 string, then store it in the variable utf8String of the string type, and print the output (this method requires the compiler encoding format to correspond to UTF-8, to Print according to the normal encoding format of the compiler, there is no need to add u8).

It should be noted that although the string class is suitable for UTF-8 encoding, if you need to deal with a wider range of Unicode characters (such as Emoji emoticons, etc.), you may need to use u16string or u32string class, because they can better handle multi-word The Unicode character for the section. In most application scenarios dealing with UTF-8 encoding, the string class is a very convenient and practical choice.

2.2 Understanding strings

Introduction to string class documentation

  1. String is a class representing a sequence of characters
  2. The standard string classes provide support for such objects, with an interface similar to that of the standard character containers, but with added design features specifically for manipulating single-byte character strings.
  3. The string class is using char (i.e. as its character type, using its default char_traits and allocator types (see basic_string for more information on templates).
  4. The string class is an instance of the basic_string template class, which uses char to instantiate the basic_string template class, and uses char_traits and allocator as the default parameters of basic_string (see basic_string for more template information).
  5. Note that this class handles bytes independently of the encoding used: if used to handle sequences of multibyte or variable-length characters (such as UTF-8), all members of this class (such as length or size) and its iteration , will still operate on bytes (rather than actual encoded characters).

Summarize:

  1. string is a string class that represents strings
  2. The interface of this class is basically the same as that of regular containers, and some regular operations specially used to manipulate strings are added.
  3. string is actually at the bottom: an alias of the basic_string template class,typedef basic_string<char, char_traits, allocator>string;
  4. Sequences of multibyte or variable-length characters cannot be manipulated.
  5. When using the string class, you must include the #include header file and using namespace std (or expand std::string separately)

3.Common interface description of string class

3.1 Common construction of string class objects

function name Function Description
string(); Constructs an empty string class object, that is, an empty string
string (const string& str); copy constructor
string (const string& str, size_t pos, size_t len = npos); Creates a new string object using a substring of another std::string object, copying the substring of length len from the given position pos.
string (const char* s); Use C-string to construct string class object
string (const char* s, size_t n); Create a new string object from part of an array of characters
string (size_t n, char c); The string class object contains n characters c
template <class InputIterator> string (InputIterator first, InputIterator last); Use the iterator range [first, last) to create a new string object, the characters in the range will be copied into the string.

Example:
1. Default constructor
default (1) string();

std::string str; // 创建一个空字符串

2. Copy constructor
copy (2) string (const string& str);

std::string str1 = "Hello";
std::string str2 = str1; // 使用复制构造函数创建新的字符串对象

3. Substring constructor
substring (3) string (const string& str, size_t pos, size_t len = npos);

std::string str1 = "Hello, World!";
std::string str2 = str1.substr(0, 5); // 使用子串构造函数创建新的字符串对象,内容为 "Hello"

4. String literal constructor
from c-string (4) string (const char* s);

std::string str = "Hello, World!"; // 使用字符串字面值初始化字符串

5. Partial character array constructor
from sequence (5) string (const char* s, size_t n);

const char* str = "Hello, World!";
std::string new_str(str, 5); // 使用字符数组的前5个字符 "Hello" 来创建新的字符串对象

6. Character repeat constructor
fill (6) string (size_t n, char c);

std::string str(5, 'A'); // 创建一个包含5个字符'A'的字符串 "AAAAA"

7. Iterator range constructor
range (7) template <class InputIterator> string (InputIterator first, InputIterator last);

std::string str("Hello, World!");
std::string sub_str(str.begin(), str.begin() + 5); // 使用迭代器范围构造函数创建新的字符串对象,内容为 "Hello"

3.2 Capacity operation of string objects

function name Function Description
size Returns the effective character length of the string
length Returns the effective character length of the string
max_size Returns the maximum number of characters that a string object can hold
resize Used to change the length of a string object
capacity Return the total size of the space
reserve reserve space for strings
clear Clear valid characters
empty If the detection string is released as an empty string, it returns true, otherwise it returns false
shrink_to_fit Request the string object to release excess memory space and adjust the capacity to be the same as the string length

Example:

1. Return the effective character length of the string
size_type size() const;

string s1("hello world");
//利用有效长度逐个打印字符,并间隔打印
for (size_t i = 0; i < s1.size(); ++i)
{
    
    
	cout << s1[i] << ' ';
}

2. Return the effective character length of the string
size_type length() const;
size() and length() are completely equivalent, they both return the number of characters in the string object, there is no difference.

The functions of these two functions are the same, but they are named differently. In order to provide more programming flexibility and readability, you can choose to use size() or length() according to your personal preference.

In actual use, you can choose to use size() or length() to get the length of the string according to your preferences and project conventions, the effect of both is exactly the same. In general, size() is more commonly used, because in the C++ standard library, many containers provide the size() member function to obtain the number of elements in the container, including std::string, std::vector, etc. So, use size() to keep your code consistent and readable.

3. Returns the maximum number of characters that a string object can hold
size_type max_size() const;

std::string str;
std::cout << "Max size: " << str.max_size() << std::endl;

The max_size() function returns the maximum number of characters that a string object can hold in the current system environment. This value depends on the platform and compiler, and is usually a very large value. Its meaning is the theoretical upper limit of a string object, indicating the maximum number of characters that a string object of this type can hold under the current platform and environment.

4. Used to change the length of the string object
void resize (size_type n);void resize (size_type n, charT c);
The first version of the resize() function is used to change the length of the string object.
resize() will adjust the length of the string to n, if n is less than the current length, the string will be truncated; if n is greater than the current length, a null character will be added at the end to extend the string length.

The second version of resize() resizes the string to n, while padding the newly added characters with the character c (only takes effect if n is greater than the current length).

Example:

std::string str = "Hello";
str.resize(10);          // 调整字符串长度为 10,现在 str 为 "Hello     "
str.resize(15, '-');     // 调整字符串长度为 15,用字符 '-' 填充,现在 str 为 "Hello-----"

5. Return the total size of the space
size_type capacity() const;
The capacity() function returns the capacity of the current string object, that is, the maximum number of characters that the string object can hold without reallocating memory. Its value may be less than or equal to max_size(), depending on the actual memory allocation of the current string object. In C++, the std::string class uses dynamic allocation of memory to store strings. When the length of the string exceeds the current capacity, the string will automatically reallocate a larger memory space.

6. Reserve space for the string
void reserve (size_type n = 0);
In the std::string class of C++, reserve() is a member function used to request the string object to reallocate memory so that it can hold at least the specified number of characters. This function is very useful when the length of the string needs to increase frequently. It can avoid multiple memory allocation and copy operations, thereby improving performance.

std::string str = "Hello";
std::cout << "Capacity before reserve: " << str.capacity() << std::endl; // 输出当前容量
str.reserve(20); // 请求重新分配至少能容纳20个字符的内存空间
std::cout << "Capacity after reserve: " << str.capacity() << std::endl; // 输出重新分配后的容量

In the above example, we first output the current capacity of the string str, then call the reserve() function to request reallocation of memory space that can accommodate at least 20 characters, and finally output the capacity of the string str again. Note that after reallocating memory, the capacity may exceed the requested value of n, this is to avoid frequent memory reallocations.

Using the reserve() function can optimize the memory usage of the string object, especially when the string is predicted to become longer, allocate enough memory space in advance to reduce dynamic memory allocation and copy operations, thereby improving program performance. However, it should be noted that excessive allocation of memory may lead to waste of resources, and the capacity should be reasonably selected according to the actual situation.

7. Empty valid characters
void clear();
Using the clear() function will clear the content of the string object, that is, set its length to 0, but it will not release the memory or reduce the capacity. It turns the string object into an empty string, which is equivalent to assigning an empty string to a string.

std::string str = "Hello, World!";
std::cout << "Before clear: " << str << std::endl; // 输出原字符串内容
str.clear(); // 清空字符串内容,使其变为空字符串
std::cout << "After clear: " << str << std::endl;  // 输出空字符串

In the above example, we first output the content of the string str, then call the clear() function to clear its content, and finally output the string str again, which has now become an empty string.

The clear() function is very convenient when emptying the string content, especially when the same string object needs to be reused or the string content needs to be reset, this function can be used to quickly empty the string. Please note that clear() only clears the content of the string, it does not release memory or change the capacity. If you need to free up memory or shrink capacity, you can use the shrink_to_fit() function.

8. Check that the string is released as an empty string.
bool empty() const;
The empty() function returns a value of type bool. If the string object is empty, it returns true, otherwise it returns false.

std::string str1 = "Hello";
std::string str2;

if (str1.empty()) {
    
    
    std::cout << "str1 is empty." << std::endl;
} else {
    
    
    std::cout << "str1 is not empty." << std::endl;
}

if (str2.empty()) {
    
    
    std::cout << "str2 is empty." << std::endl;
} else {
    
    
    std::cout << "str2 is not empty." << std::endl;
}

In the above example, we created two std::string objects str1 and str2, and then checked whether they are empty using the empty() function. str1 contains the characters "Hello", so str1.empty() returns false, and str2 is an empty string, so str2.empty() returns true.

The empty() function is very useful in actual programming. It can be used to check whether a string is empty, so as to make logical judgment and processing according to the situation.

9. Release excess memory space
void shrink_to_fit();
This function is used to request the string object to release excess memory space, and adjust the capacity to be the same as the length of the string. This reduces unnecessary memory usage.

std::string str = "Hello";
str.reserve(20); // 请求重新分配至少能容纳20个字符的内存空间
// 其他操作...
str.shrink_to_fit(); // 释放多余的内存空间,容量调整为与字符串长度相同

Using the reserve() and shrink_to_fit() functions can effectively control the memory usage of string objects and avoid unnecessary memory allocation and release. Please note that dynamically adjusting the capacity may be an optimal strategy when the string needs to change length frequently. However, it is also necessary to perform reasonable memory management according to the actual situation to avoid resource waste caused by over-allocation of memory.

Notice:

  1. The underlying implementation principle of size() and length() methods is exactly the same. The reason for introducing size() is to be consistent with the interfaces of other containers. In general, size() is basically used.
  2. clear() just clears the valid characters in the string and does not change the size of the underlying space.
  3. resize(size_t n) and resize(size_t n, char c) both change the number of effective characters in the string to n, the difference is that when the number of characters increases: resize(n) fills the excess with 0 Element space, resize(size_t n, char c) uses character c to fill the extra element space. Note: When resize changes the number of elements, if the number of elements is increased, the size of the underlying capacity may be changed. If the number of elements is reduced, the total size of the underlying space remains unchanged.
  4. reserve(size_t res_arg=0): Reserve space for string, without changing the number of effective elements. When the parameter of reserve is smaller than the total size of the underlying space of string, reserve will not change the capacity.

3.3 Element access of string class objects

function name Function Description
operator[] accesses the character at the specified position pos in the string
at accesses the character at the specified position pos in the string
back Get the first character of a string
front Get the last character of a string

1. operator[]:
reference operator[](size_type pos);
const_reference operator[](size_type pos) const;
The operator[] function is used to access the character at the specified position pos in the string. Returns a reference that allows you to read or modify the character at that position. If the const modifier is used, it indicates read-only access to the string.

std::string str = "Hello";
char first_char = str[0];      // 获取字符串的第一个字符 'H'
str[0] = 'h';                  // 修改字符串的第一个字符为 'h',现在 str 为 "hello"

2. at():
reference at(size_type pos);
const_reference at(size_type pos) const;
The at() function is similar to operator[], and is also used to access the character at the specified position pos in the string. The difference is that the at() function checks that the index is valid and throws a std::out_of_range exception if the index is outside the range of the string.

std::string str = "Hello";
char first_char = str.at(0);   // 获取字符串的第一个字符 'H'
str.at(0) = 'h';               // 修改字符串的第一个字符为 'h',现在 str 为 "hello"

3. front():
reference front();
const_reference front() const;
The front() function is used to get the first character of the string and return a reference. If the const modifier is used, it indicates read-only access to the string.

std::string str = "Hello";
char first_char = str.front(); // 获取字符串的第一个字符 'H'

4.back():
reference back();
const_reference back() const;
The back() function is used to get the last character of the string and return a reference. If the const modifier is used, it indicates read-only access to the string.

std::string str = "Hello";
char last_char = str.back();   // 获取字符串的最后一个字符 'o'

These functions provide a variety of ways to access the contents of the string, and you can choose the appropriate function to read or modify the characters in the string according to your needs. Please note that when using these functions, pay attention to the effective range of the index to avoid undefined behavior caused by accessing out of bounds.

3.4 Iterators (iterator) interface of string class object

In the std::string class of C++, many Iterators (iterator) interface functions are provided for traversing and accessing the characters in the string. These functions allow you to iterate over and manipulate strings by accessing the contents of the string as iterators.

The following are some Iterators interface functions of the std::string class and their introduction and usage:

function name Function Description
begin() and end() The begin() function returns an iterator pointing to the first character of the string, and the end() function returns an iterator pointing to the character after the end of the string
rbegin() and rend() The rbegin() function returns a reverse iterator pointing to the last character of the string, and the rend() function returns a reverse iterator pointing to the position before the first character of the string
cbegin() and cend() The cbegin() function returns a const iterator pointing to the first character of the string, and the cend() function returns a const iterator pointing to the character one past the end of the string (one position after the end).
crbegin() and crend() The crbegin() function returns a const reverse iterator pointing to the last character of the string, and the crend() function returns a const reverse iterator pointing to the position before the first character of the string.

1.begin() and end():
iterator begin();
const_iterator begin() const;
iterator end();
const_iterator end() const;
The begin() function returns an iterator pointing to the first character of the string, while the end() function returns an iterator pointing to the last character of the string (a position after the end). The const modifier version of the function is used to get a const iterator over a const object.

string s("hello");
	string::iterator it = s.begin();
	while (it != s.end())
	{
    
    
		cout << *it << " ";
		++it;
	}
	cout << endl;

2.rbegin() and rend():
reverse_iterator rbegin();
const_reverse_iterator rbegin() const;
reverse_iterator rend();
const_reverse_iterator rend() const;
The rbegin() function returns a reverse iterator pointing to the last character of the string, while the rend() function returns a reverse iterator pointing to the position before the first character of the string. The const modifier version of the function is used to get a const reverse iterator over a const object.

std::string str = "Hello";
for (auto it = str.rbegin(); it != str.rend(); ++it) {
    
    
    std::cout << *it; // 逆向遍历输出字符串的所有字符 "olleH"
}

3.cbegin() and cend():
const_iterator cbegin() const;
const_iterator cend() const;
The cbegin() function returns a const iterator pointing to the first character of the string, while the cend() function returns a const iterator pointing to the character after the end of the string (a position after the end ).
4. crbegin() and crend():
const_reverse_iterator crbegin() const;
const_reverse_iterator crend() const;
The crbegin() function returns a const reverse iterator pointing to the last character of the string, while the crend() function returns a const reverse iterator pointing to the position before the first character of the string.

These Iterators interface functions provide various ways to traverse the contents of a string, and support forward and reverse iterators. You can choose the appropriate iterator type to traverse the string according to your needs, among which begin() and end() are the most commonly used iterator interface functions.

The relationship between range for and iterators

Range-based for loops and iterators are two different ways of traversing containers or iterable objects in C++. They have some differences in syntax and usage, butEssentially, it is used to iterate and access the elements in the container or sequence

  1. Range-based for loop: Range-based
    for loop is a syntactic sugar introduced by C++11 to simplify the traversal of containers or sequences. Its grammatical form is as follows:
for (element_type element : container) {
    
    
    // 对每个元素执行的操作
}

In this loop, container is an iterable object, which can be a standard container (such as std::vector, std::list, std::map, etc.), an array, a string, etc. element is a copy of each element in the container and can be used to access and manipulate that element. The range for loop automatically traverses the container and assigns the elements in the container to element on each iteration until the end of the container.

Example:

std::string str = "Hello";
for (char c : str) {
    
    
    std::cout << c << " "; // 输出:H e l l o
}
  1. Iterator:
    Iterators can also be used to traverse each character in std::string, which provides a more flexible way to access the contents of the string, and you can customize the traversal method. The std::string class provides two kinds of iterators: iterator and const_iterator.

iterator: used to modify the characters in the std::string object.
const_iterator: for read-only access to characters in a std::string object.

Example:

std::string str = "Hello";
for (std::string::iterator it = str.begin(); it != str.end(); ++it) {
    
    
    std::cout << *it << " "; // 输出:H e l l o
}

Or use the auto keyword to simplify the iterator declaration:

for (auto it = str.begin(); it != str.end(); ++it) {
    
    
    std::cout << *it << " "; // 输出:H e l l o
}

It should be noted that both the range for loop and iterator can be used to traverse the characters in std::string, the range for loop is more concise and convenient, especially suitable for traversing the entire string; while the iterator provides more flexibility, you can Used to implement more complex traversal and access methods, such as traversing only some characters or traversing strings in reverse order. In practical applications, you can choose the appropriate traversal method according to your specific needs.

3.5 Modifiers of string class objects (Modifiers)

function name Function Description
operator+= for string concatenation
append Appends a character or sequence of characters to the end of a string
push_back 在字符串末尾添加一个字符
assign 将新的内容赋值给字符串对象,从而修改字符串的内容
insert 在指定位置 pos 处插入字符或字符序列
erase 删除指定位置的字符或字符范围
replace 替换指定位置或字符范围的字符
swap 调用该函数的字符串对象与参数表示的另一个字符串对象的内容进行交换
pop_back 删除字符串中的最后一个字符

1.operator+=
+= 运算符是字符串的连接操作符,也称为字符串的拼接运算符。使用 += 运算符,您可以将一个字符串连接到另一个字符串的末尾,从而实现字符串的拼接。

+= 运算符的原型如下:

basic_string& operator+=(const basic_string& str);
basic_string& operator+=(const charT* s);
basic_string& operator+=(charT ch);

+= 运算符有三个重载版本,分别用于将另一个字符串、C 风格字符串(以 null 结尾的字符数组)或单个字符连接到当前字符串的末尾。

示例:

std::string str = "Hello";
str += " World";   // 将字符串 " World" 连接到 str 的末尾,现在 str 变为 "Hello World"
str += '!';        // 将字符 '!' 连接到 str 的末尾,现在 str 变为 "Hello World!"

在上述示例中,我们通过使用 += 运算符将字符串 " World" 和字符 ‘!’ 连接到字符串 str 的末尾,实现了字符串的拼接。

需要注意的是,+= 运算符会直接修改调用它的字符串对象,将指定的内容连接到字符串的末尾。如果你希望连接两个字符串而不修改原始字符串,可以使用 + 运算符来创建一个新的字符串,而不会修改原有的字符串对象。例如:

std::string str1 = "Hello";
std::string str2 = " World";
std::string combined = str1 + str2; // 创建一个新的字符串,不修改原有字符串

使用 += 运算符或 + 运算符,取决于你希望修改原有字符串还是创建新的字符串,或者根据具体的需求来选择适合的方法。

2.append
append() 函数用于在字符串的末尾添加字符或字符序列,从而实现字符串的拼接。
append() 函数有多个重载形式,提供了不同的方式来添加内容到字符串的末尾。以下是 std::string 类中 append() 函数的几种重载形式及其介绍和使用方法:

basic_string& append(const charT* s);
这个重载函数将一个 C 风格字符串(以 null 结尾的字符数组)添加到字符串的末尾。

std::string str = "Hello";
str.append(" World");      // 在末尾添加字符串 " World",现在 str 为 "Hello World"

basic_string& append(const charT* s, size_type n);
这个重载函数将一个指定长度的字符数组添加到字符串的末尾。

std::string str = "Hello";
str.append(" World", 5);   // 在末尾添加字符数组 " Worl"(前5个字符),现在 str 为 "Hello Worl"

basic_string& append(const basic_string& str);
这个重载函数将另一个 std::string 对象的内容添加到当前字符串的末尾。

std::string str1 = "Hello";
std::string str2 = " World";
str1.append(str2);         // 将 str2 的内容添加到 str1 的末尾,现在 str1 为 "Hello World"

basic_string& append(const basic_string& str, size_type pos, size_type n);
这个重载函数将另一个 std::string 对象从指定位置 pos 处开始的 n 个字符添加到当前字符串的末尾。

std::string str1 = "Hello";
std::string str2 = "World";
str1.append(str2, 1, 3);   // 将 str2 从位置1(包含)开始的3个字符 "orl" 添加到 str1 的末尾,现在 str1 为 "Helloorl"

basic_string& append(size_type n, charT ch);
这个重载函数将重复 n 次的字符 ch 添加到字符串的末尾。

std::string str = "Hello";
str.append(3, '!');        // 在末尾添加3个字符 '!',现在 str 为 "Hello!!!"

这些 append() 函数提供了多种方式来将内容添加到字符串的末尾,从而实现字符串的拼接。

3.push_back
void push_back(charT ch);
使用 push_back() 函数可以将一个字符 ch 添加到字符串的末尾。

示例:

std::string str = "Hello";
str.push_back('!'); // 在末尾添加字符 '!',现在 str 变为 "Hello!"

在上述示例中,我们通过使用 push_back() 函数在字符串 str 的末尾添加了字符 ‘!’,从而实现了在字符串中添加一个字符的操作。

需要注意的是,push_back() 函数会直接修改调用它的字符串对象,在字符串的末尾添加指定的字符。在使用 push_back() 之前,应该确保字符串的长度仍然在合理的范围内,避免发生字符串的溢出。在实际使用中,务必注意处理字符串长度和内存的限制。另外,C++11 之后的版本还引入了字符串拼接操作符 +=,可以使用 += 运算符来在字符串的末尾添加字符,更加简洁方便。

4.assign
assign() 函数用于将新的内容赋值给字符串对象,从而修改字符串的内容。

assign() 函数有多个重载形式,提供了不同的方式来赋值新的内容给字符串。以下是 std::string 类中 assign() 函数的几种重载形式及其介绍和使用方法:

basic_string& assign(const charT* s);
这个重载函数将一个 C 风格字符串(以 null 结尾的字符数组)赋值给字符串对象。

std::string str;
str.assign("Hello");      // 将 C 风格字符串 "Hello" 赋值给字符串对象 str

basic_string& assign(const charT* s, size_type n);
这个重载函数将一个指定长度的字符数组赋值给字符串对象。

std::string str;
str.assign("Hello", 3);   // 将字符数组 "Hel"(前三个字符)赋值给字符串对象 str

basic_string& assign(const basic_string& str);
这个重载函数将另一个 std::string 对象的内容赋值给当前字符串对象。

std::string str1 = "Hello";
std::string str2;
str2.assign(str1);       // 将 str1 的内容赋值给 str2

basic_string& assign(const basic_string& str, size_type pos, size_type n);
这个重载函数将另一个 std::string 对象从指定位置 pos 处开始的 n 个字符赋值给当前字符串对象。

std::string str1 = "Hello";
std::string str2;
str2.assign(str1, 1, 3); // 将 str1 从位置1(包含)开始的3个字符 "ell" 赋值给 str2

basic_string& assign(size_type n, charT ch);
这个重载函数将重复 n 次的字符 ch 赋值给字符串对象。

std::string str;
str.assign(5, 'x');       // 将字符 'x' 重复5次赋值给字符串对象 str,结果为 "xxxxx"

这些 assign() 函数提供了多种方式来将新的内容赋值给字符串对象,从而修改字符串的内容。

5.insert
insert() 函数用于在指定位置插入字符或字符序列,从而改变字符串的内容。

insert() 函数有多个重载形式,提供了不同的方式来在字符串中插入字符或字符序列。以下是 std::string 类中 insert() 函数的几种重载形式及其介绍和使用方法:

basic_string& insert(size_type pos, const charT* s);
这个重载函数在字符串中的指定位置 pos 处插入一个 C 风格字符串(以 null 结尾的字符数组)。

std::string str = "Hello";
str.insert(2, "xx");      // 在位置2处插入字符串 "xx",现在 str 变为 "Hexxllo"

basic_string& insert(size_type pos, const charT* s, size_type n);
这个重载函数在字符串中的指定位置 pos 处插入一个指定长度的字符数组。

std::string str = "Hello";
str.insert(3, "xx", 1);   // 在位置3处插入字符数组 "x"(前1个字符),现在 str 变为 "Helxlo"

basic_string& insert(size_type pos, const basic_string& str);
这个重载函数在字符串中的指定位置 pos 处插入另一个 std::string 对象的内容。

std::string str1 = "Hello";
std::string str2 = " World";
str1.insert(5, str2);     // 在位置5处插入 str2 的内容,现在 str1 变为 "Hello World"

basic_string& insert(size_type pos, const basic_string& str, size_type subpos, size_type sublen);
这个重载函数在字符串中的指定位置 pos 处插入另一个 std::string 对象的子字符串,从 str 的 subpos 处开始,长度为 sublen。

std::string str1 = "Hello";
std::string str2 = "World";
str1.insert(5, str2, 0, 3);   // 在位置5处插入 str2 的子字符串 "Wor",现在 str1 变为 "HelloWor"

basic_string& insert(size_type pos, size_type n, charT ch);
这个重载函数在字符串中的指定位置 pos 处插入重复 n 次的字符 ch。

std::string str = "Hello";
str.insert(2, 3, 'x');   // 在位置2处插入3个字符 'x',现在 str 变为 "Hexxxello"

这些 insert() 函数提供了多种方式来在字符串中插入字符或字符序列,从而实现字符串内容的修改。

6.erase
erase() 函数用于从字符串中删除指定位置的字符或字符序列,从而修改字符串的内容。

erase() 函数有多个重载形式,提供了不同的方式来删除字符串中的字符或字符序列。以下是 std::string 类中 erase() 函数的几种重载形式及其介绍和使用方法:

basic_string& erase(size_type pos = 0, size_type n = npos);
这个重载函数删除从指定位置 pos 开始的 n 个字符(默认情况下,删除从 pos 开始的所有字符)。

std::string str = "Hello World";
str.erase(5);       // 删除从位置5(包含)开始的所有字符,现在 str 变为 "Hello"
str.erase(0, 3);    // 删除从位置0(包含)开始的3个字符,现在 str 变为 "lo"

iterator erase(const_iterator position);
这个重载函数删除指定位置 position 处的字符,并返回一个指向删除后的下一个字符的迭代器。

std::string str = "Hello";
auto it = str.erase(str.begin() + 1); // 删除位置1处的字符 'e',现在 str 变为 "Hllo",it 指向 'l'

iterator erase(const_iterator first, const_iterator last);
这个重载函数删除从 first 到 last-1之间的字符,并返回一个指向删除后的下一个字符的迭代器。

std::string str = "Hello World";
auto first = str.begin() + 6;   // 指向字符 'W'
auto last = str.begin() + 11;   // 指向字符 '\0'
auto it = str.erase(first, last); // 删除字符 'W' 到 '\0'(不包括\0),现在 str 变为 "Hello ",it 指向 '\0'

这些 erase() 函数提供了多种方式来删除字符串中的字符或字符序列,从而实现字符串内容的修改。

7.replace
replace()函数用于将字符串中的一部分内容替换为新的子串。

replace() 函数有多个重载形式,提供了不同的方式来替换字符串中的一部分内容。以下是 std::string 类中 replace() 函数的几种重载形式及其描述和使用方法:

basic_string& replace(size_type pos, size_type count, const charT* s);
这个重载函数从字符串的位置 pos 开始,用指定的 C 风格字符串(以 null 结尾的字符数组)替换 count 个字符。

std::string str = "Hello, World!";
str.replace(7, 5, "Universe"); // 从位置 7 开始,用 "Universe" 替换 5 个字符,现在 str 变为 "Hello, Universe!"

basic_string& replace(size_type pos, size_type count, const charT* s, size_type n);
这个重载函数从字符串的位置 pos 开始,用指定长度的字符数组中的前 n 个字符替换 count 个字符。

std::string str = "Hello, World!";
str.replace(7, 5, "Earth", 3); // 从位置 7 开始,用 "Ear"("Earth" 的前 3 个字符)替换 5 个字符,现在 str 变为 "Hello, Ear, World!"

basic_string& replace(size_type pos, size_type count, const basic_string& str);
这个重载函数从字符串的位置 pos 开始,用另一个 std::string 对象的内容替换 count 个字符。

std::string str1 = "Hello, World!";
std::string str2 = "Universe";
str1.replace(7, 5, str2); // 从位置 7 开始,用 str2 的内容 "Universe" 替换 5 个字符,现在 str1 变为 "Hello, Universe!"

basic_string& replace(size_type pos, size_type count, const basic_string& str, size_type pos2, size_type count2);
这个重载函数从字符串的位置 pos 开始,用另一个 std::string 对象 str 的从 pos2 处开始的 count2 个字符替换 count 个字符。

std::string str1 = "Hello, World!";
std::string str2 = "Universe";
str1.replace(7, 5, str2, 0, 3); // 从位置 7 开始,用 str2 的子串 "Uni"(从位置 0 开始的 3 个字符)替换 5 个字符,现在 str1 变为 "Hello, Uni, World!"

basic_string& replace(iterator first, iterator last, const charT* s);
这个重载函数用指定的 C 风格字符串(以 null 结尾的字符数组)替换从 first 到 last-1 之间的字符。

std::string str = "Hello, World!";
auto first = str.begin() + 7;   // 指向字符 'W'
auto last = str.begin() + 12;   // 指向字符 '!'
str.replace(first, last, "Universe"); // 用 "Universe" 替换 'W' 到 '!'(不包括!),现在 str 变为 "Hello, Universe!"

basic_string& replace(iterator first, iterator last, const basic_string& str);

这个重载函数用另一个 std::string 对象 str 的内容替换从 first 到 last-1 之间的字符。

std::string str1 = "Hello, World!";
std::string str2 = "Universe";
auto first = str1.begin() + 7;   // 指向字符 'W'
auto last = str1.begin() + 12;   // 指向字符 '!'
str1.replace(first, last, str2); // 用 str2 的内容 "Universe" 替换 'W' 到 '!'(不包含 '!'),现在 str1 变为 "Hello, Universe!"

这些 replace() 函数提供了多种方式来替换字符串中的一部分内容,从而实现字符串内容的修改。

8.swap
swap() 函数没有参数,它将调用它的字符串对象与另一个字符串对象进行内容交换。

std::string str1 = "Hello";
std::string str2 = "World";

str1.swap(str2); // 将 str1 和 str2 的内容交换,现在 str1 变为 "World",str2 变为 "Hello"

在上述示例中,通过调用 str1.swap(str2),我们将 str1 和 str2 的内容进行了交换,str1 变为 “World”,而 str2 变为 “Hello”。

这个函数可以在交换两个字符串的内容时非常有用,而不需要对字符逐个交换或使用临时变量来完成交换。由于 swap() 是一个成员函数,所以可以通过调用它来直接对字符串对象进行交换操作,使得代码更简洁和高效。

9.pop_back
pop_back() 函数没有参数,它只需调用它的字符串对象,就会将最后一个字符从字符串中删除。

std::string str = "Hello";
str.pop_back(); // 删除最后一个字符,现在 str 变为 "Hell"

在上述示例中,通过调用 str.pop_back(),我们将字符串 str 的最后一个字符 ‘o’ 删除,从而得到新的字符串 “Hell”。

需要注意的是,使用 pop_back() 之前,应该确保字符串的长度不为零,否则会引发未定义的行为。在调用 pop_back() 之前,通常需要检查字符串是否为空。

3.6 string类对象的操作函数(operations)

1.c_str():

const char* c_str() const;

这个函数返回一个指向以 null 结尾的字符数组(C 字符串)的指针,表示当前字符串的内容。

示例:

std::string str = "Hello";
const char* cstr = str.c_str(); // cstr 指向 "Hello" 的 C 字符串形式

2.data():

const char* data() const;
这个函数返回一个指向字符数组的指针,表示当前字符串的内容。与 c_str() 类似,但 data() 不一定以 null 结尾。

示例:

std::string str = "Hello";
const char* strData = str.data(); // strData 指向 "Hello" 的字符数组形式

3.get_allocator():

allocator_type get_allocator() const noexcept;
这个函数返回当前字符串使用的分配器的副本。

示例:

std::string str = "Hello";
std::allocator<char> alloc = str.get_allocator(); // 获取 str 的分配器副本

4.copy():

size_type copy(charT* dest, size_type count, size_type pos = 0) const;
这个函数从当前字符串中复制 count 个字符到指定位置 pos 开始的字符数组 dest。

示例:

std::string str = "Hello";
char buffer[6];
str.copy(buffer, 5); // 将 str 的前 5 个字符复制到 buffer 中,buffer 现在为 "Hello\0"(带有 null 终止符)

5.find()、rfind()、find_first_of()、find_last_of()、find_first_not_of()、find_last_not_of():

这些函数用于在当前字符串中搜索指定的字符或子字符串,并返回找到的第一个匹配位置或位置偏移。

示例:

std::string str = "Hello, World!";
size_t pos = str.find("World"); // 在 str 中找到子字符串 "World",返回位置 7
size_t lastPos = str.rfind("l"); // 从字符串末尾开始找到字符 'l',返回位置 9
size_t foundPos = str.find_first_of(",!"); // 在 str 中找到第一个出现的 ',' 或 '!',返回位置 5

6. substr():

basic_string substr(size_type pos = 0, size_type count = npos) const;
这个函数返回一个新的字符串,包含从位置 pos 开始的 count 个字符的副本。

示例:

void DealUrl(const string& url)
{
    
    
	size_t pos1 = url.find("://");
	if (pos1 == string::npos)
	{
    
    
		cout << "非法url" << endl;
		return;
	}
	string protocol = url.substr(0, pos1);
	cout << protocol << endl;

	size_t pos2 = url.find('/', pos1 + 3);
	if (pos2 == string::npos)
	{
    
    
		cout << "非法url" << endl;
		return;
	}
	string domain = url.substr(pos1+3, pos2-pos1-3);
	cout << domain << endl;

	string uri = url.substr(pos2 + 1);
	cout << uri << endl << endl;
}

int main()
{
    
    	
	string url1 = "https://cplusplus.com/reference/string/string/";
	string url2 = "https://image.baidu.com/search/detail?ct=503316480&z=0&ipn=d&word=ascall&step_word=&hs=0&pn=0&spn=0&di=7108135681917976577&pi=0&rn=1&tn=baiduimagedetail&is=0%2C0&istype=0&ie=utf-8&oe=utf-8&in=&cl=2&lm=-1&st=undefined&cs=2613959014%2C543572025&os=2740573600%2C1059518451&simid=2613959014%2C543572025&adpicid=0&lpn=0&ln=179&fr=&fmq=1660115697093_R&fm=&ic=undefined&s=undefined&hd=undefined&latest=undefined&copyright=undefined&se=&sme=&tab=0&width=undefined&height=undefined&face=undefined&ist=&jit=&cg=&bdtype=0&oriquery=&objurl=https%3A%2F%2Fgimg2.baidu.com%2Fimage_search%2Fsrc%3Dhttp%3A%2F%2Fimg.php.cn%2Fupload%2Fimage%2F147%2F157%2F796%2F1593765739620093.png%26refer%3Dhttp%3A%2F%2Fimg.php.cn%26app%3D2002%26size%3Df9999%2C10000%26q%3Da80%26n%3D0%26g%3D0n%26fmt%3Dauto%3Fsec%3D1662707704%26t%3Da68cb238bbb3f99d0554098c785d526e&fromurl=ippr_z2C%24qAzdH3FAzdH3Fooo_z%26e3Brir_z%26e3BvgAzdH3FuwqAzdH3F9c9amd_z%26e3Bip4s&gsm=1&rpstart=0&rpnum=0&islist=&querylist=&nojc=undefined&dyTabStr=MCwzLDIsNCw2LDEsNSw3LDgsOQ%3D%3D";
	string url3 = "ftp://ftp.cs.umd.edu/pub/skipLists/skiplists.pdf";

	DealUrl(url1);
	DealUrl(url2);
	DealUrl(url3);
	return 0;
}

insert image description here

7.compare():

int compare(const basic_string& str) const noexcept;
这个函数用于比较当前字符串与另一个 std::string 对象 str 的大小关系。

示例:

std::string str1 = "Hello";
std::string str2 = "World";
int result = str1.compare(str2); // 返回一个整数,表示 str1 和 str2 的大小关系(类似于字符串比较的结果)

这些成员函数提供了丰富的功能,用于处理字符串的查找、比较、复制、截取等操作。

3.7 string类对象的非成员函数和npos

1.operator+(重载运算符+):

template <class CharT, class Traits, class Allocator>
basic_string<CharT, Traits, Allocator> operator+(
    const basic_string<CharT, Traits, Allocator>& lhs,
    const basic_string<CharT, Traits, Allocator>& rhs);

这个函数模板用于将两个 std::string 对象进行字符串连接,返回一个新的 std::string 对象,包含两个原始字符串的内容。

示例:

std::string str1 = "Hello";
std::string str2 = " World";
std::string result = str1 + str2; // 返回 "Hello World"

2.关系运算符(Relational operators):

template <class CharT, class Traits, class Allocator>
bool operator==(
    const basic_string<CharT, Traits, Allocator>& lhs,
    const basic_string<CharT, Traits, Allocator>& rhs);

template <class CharT, class Traits, class Allocator>
bool operator!=(
    const basic_string<CharT, Traits, Allocator>& lhs,
    const basic_string<CharT, Traits, Allocator>& rhs);

template <class CharT, class Traits, class Allocator>
bool operator<(
    const basic_string<CharT, Traits, Allocator>& lhs,
    const basic_string<CharT, Traits, Allocator>& rhs);

template <class CharT, class Traits, class Allocator>
bool operator<=(
    const basic_string<CharT, Traits, Allocator>& lhs,
    const basic_string<CharT, Traits, Allocator>& rhs);

template <class CharT, class Traits, class Allocator>
bool operator>(
    const basic_string<CharT, Traits, Allocator>& lhs,
    const basic_string<CharT, Traits, Allocator>& rhs);

template <class CharT, class Traits, class Allocator>
bool operator>=(
    const basic_string<CharT, Traits, Allocator>& lhs,
    const basic_string<CharT, Traits, Allocator>& rhs);

这些函数模板用于对 std::string 对象进行大小比较。可以通过这些运算符对两个字符串进行逐个字符的比较,从而确定它们的大小关系。

示例:

std::string str1 = "Hello";
std::string str2 = "World";
bool isEqual = (str1 == str2); // 返回 false,因为 str1 不等于 str2
bool isGreater = (str1 > str2); // 返回 true,因为 str1 大于 str2

3.swap():

template <class CharT, class Traits, class Allocator>
void swap(
    basic_string<CharT, Traits, Allocator>& lhs,
    basic_string<CharT, Traits, Allocator>& rhs);

这个函数模板用于交换两个 std::string 对象的内容,实现两个字符串的快速交换。

示例:

std::string str1 = "Hello";
std::string str2 = "World";
swap(str1, str2); // 将 str1 和 str2 的内容交换,现在 str1 变为 "World",str2 变为 "Hello"

4.operator>> 和 operator<<(重载运算符>>和<<):

template <class CharT, class Traits, class Allocator>
std::basic_istream<CharT, Traits>& operator>>(
    std::basic_istream<CharT, Traits>& is, basic_string<CharT, Traits, Allocator>& str);

template <class CharT, class Traits, class Allocator>
std::basic_ostream<CharT, Traits>& operator<<(
    std::basic_ostream<CharT, Traits>& os, const basic_string<CharT, Traits, Allocator>& str);

这些函数模板用于在输入输出流中读取或输出字符串内容。operator>> 用于从输入流中提取字符串,而 operator<< 用于将字符串插入到输出流中。

示例:

std::string str;
std::cout << "请输入一个字符串:";
std::cin >> str; // 从标准输入流中读取字符串
std::cout << "您输入的字符串是:" << str << std::endl; // 将字符串输出到标准输出流

5.getline():

template <class CharT, class Traits, class Allocator>
std::basic_istream<CharT, Traits>& getline(
    std::basic_istream<CharT, Traits>& is, basic_string<CharT, Traits, Allocator>& str,
    CharT delim);

这个函数模板用于从输入流中读取一行内容,并将其存储到字符串 str 中,直到遇到指定的分隔符 delim。

示例:

std::string str;
std::cout << "请输入一行文本:";
std::getline(std::cin, str); // 从标准输入流中读取一行文本并存储到 str 中
std::cout << "您输入的文本是:" << str << std::endl;

这些函数和操作符提供了丰富的功能,可以方便地对字符串进行连接、比较、输入输出等操作。

npos
npos 是 std::string 类中的一个静态常量成员,用于表示无效或未找到的位置。它是一个特殊的 std::string::size_type 类型的常量,通常被定义为 std::string::npos,其值在不同的编译器和实现中可能不同,但通常被设为 -1 或一个非常大的值,用于表示在字符串中未找到指定的子串或字符。

npos 主要用于字符串查找操作,比如在使用 find()、rfind()、find_first_of()、find_last_of()、find_first_not_of()、find_last_not_of() 等成员函数时,当查找失败或没有找到指定的子串或字符时,这些函数通常会返回 std::string::npos 来表示无效的位置。

示例:

std::string str = "Hello, World!";
std::string::size_type pos1 = str.find("Universe"); // 在 str 中找不到 "Universe",返回 std::string::npos
std::string::size_type pos2 = str.find('X'); // 在 str 中找不到字符 'X',返回 std::string::npos
std::string::size_type pos3 = str.find("World"); // 在 str 中找到 "World",返回 "World" 在 str 中的位置

在上述示例中,当在字符串 str 中找不到 “Universe” 或字符 ‘X’ 时,find() 函数会返回 std::string::npos 表示查找失败。而当找到 “World” 时,find() 函数会返回 “World” 在字符串中的位置。

注意:npos 的值是一个非常大的无符号整数,因此在比较 std::string::size_type 类型的值时,应使用无符号类型的比较方式,避免可能出现的错误。比如使用 pos != std::string::npos 来判断是否找到了指定的子串或字符。
insert image description here

4.vs和g++下string结构的说明

注意:下述结构是在32位平台下进行验证,32位平台下指针占4个字节。

4.1 vs下string的结构

string总共占28个字节,内部结构稍微复杂一点,先是有一个联合体,联合体用来定义string中字符串的存储空间:

当字符串长度小于16时,使用内部固定的字符数组来存放
当字符串长度大于等于16时,从堆上开辟空间

union _Bxty
{
    
     	// storage for small buffer or pointer to larger one
	value_type _Buf[_BUF_SIZE];
	pointer _Ptr;
	char _Alias[_BUF_SIZE]; // to permit aliasing
} _Bx;

这种设计也是有一定道理的,大多数情况下字符串的长度都小于16,那string对象创建好之后,内部已经有了16个字符数组的固定空间,不需要通过堆创建,效率高。其次,还有一个size_t字段保存字符串长度,一个size_t字段保存从堆上开辟空间总的容量,最后还有一个指针做一些其他事情。故总共占16+4+4+4=28个字节。
insert image description here

4.2 g++下string的结构

g++下,string是通过写时拷贝实现的,string对象总共占4个字节,内部只包含了一个指针,该指针将来指向一块堆空间,内部包含了如下字段:

The total size of the space
The effective length of the string
Reference count
The pointer to the heap space used to store the string.

4.3 The string expansion mechanism of vs and g++

In the C++ standard, the expansion mechanism of std::string is not stipulated, so different compilers may have different implementation methods. However, under normal circumstances, the expansion mechanism of the std::string class will follow the following general principles:

  1. Initial capacity : When creating an empty std::string object, the compiler will allocate some initial memory space for it. This initial capacity can be a small value, such as 15 or 31, depending on the compiler implementation.
  2. Capacity expansion strategy : When characters need to be added to std::string, if the current capacity is insufficient, the compiler will automatically trigger the capacity expansion operation. The way to expand capacity may be to reallocate a larger memory block and copy the original content to the new memory.
  3. Capacity expansion : When expanding capacity, the compiler usually increases the current capacity by a certain multiple to avoid frequent capacity expansion operations. Doing so can improve the efficiency of string insertion, but it also causes some memory to be wasted.

For example, the following code is in the Windows vs2022 environment and the Linux g++ environment

#include <iostream>
#include <string>
using namespace std;
int main()
{
    
    
	string s;
	size_t sz = s.capacity();
	cout << "making s grow:\n";
	for (int i = 0; i < 100; ++i)
	{
    
    
		s.push_back('c');
		if (sz != s.capacity())
		{
    
    
			sz = s.capacity();
			cout << "capacity changed: " << sz << endl;
		}
	}
	return 0;
}

vs2022
insert image description here
g++
insert image description here

epilogue

Interested friends can pay attention to the author, if you think the content is good, please give a one-click triple link, you crab crab! ! !
It is not easy to make, please point out if there are any inaccuracies
Thank you for your visit, UU watching is the motivation for me to persevere.
With the catalyst of time, let us all become better people from each other! ! !
insert image description here

Guess you like

Origin blog.csdn.net/kingxzq/article/details/131933471