C++ STL string 类详解:接口、迭代器与常用操作
C++ STL string 类是标准库中处理文本的核心组件。文章涵盖 string 对象构造、迭代器机制、容量控制接口(size、reserve 等)、访问遍历方式及修改操作(append、insert 等)。通过对比 C 语言字符串操作,阐述使用 string 类的优势,并包含完整代码示例与常见面试题解析,帮助读者掌握高效文档阅读技巧。

C++ STL string 类是标准库中处理文本的核心组件。文章涵盖 string 对象构造、迭代器机制、容量控制接口(size、reserve 等)、访问遍历方式及修改操作(append、insert 等)。通过对比 C 语言字符串操作,阐述使用 string 类的优势,并包含完整代码示例与常见面试题解析,帮助读者掌握高效文档阅读技巧。

STL 是 C++ 标准库的重要组成部分,也是一个包罗数据结构与算法的软件框架。本文介绍 STL 的六大组件(迭代器、仿函数、算法、空间配置器、容器、配接器)以及学习方法。本文将带大家正式进入 STL 的第一个容器——string 类的学习。
C 语言中,字符串是以 \0 结尾的一些字符的集合。为了操作方便,C 标准库中提供了一些 str 系列的库函数,但是这些库函数与字符串是分离开的,不太符合 OOP 的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
在 OJ 中,有关字符串的题目基本以 string 类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用 string 类,很少有人去使用 C 库中的字符串操作函数。
在使用 string 类时,必须包含 <string> 头文件以及 using namespace std; 命名空间。
建议养成阅读官方文档的习惯,文档才是原汁原味的资料。
C++11 引入了基于范围的 for 循环。for 循环后的括号由冒号':'分为两部分:第一部分是范围内用于迭代的变量,第二部分则表示被迭代的范围。范围 for 可以作用到数组和容器对象上进行遍历,底层替换为迭代器,被称为'语法糖'。
| 函数名称 | 功能说明 |
|---|---|
| string() | 构造空的 string 类对象 |
| string(const char* s) | 用 C-string 来构造 string 类对象 |
| string(size_t n, char c) | string 类对象中包含 n 个字符 c |
| string(const string& s) | 拷贝构造函数 |
void TestString() {
string s1; // 构造空的 string 类对象 s1
string s2("hello friend"); // 用 C 格式字符串构造 string 类对象 s2
string s3(s2); // 拷贝构造 s3
}
- 提供统一的方式遍历容器;
- 算法可以泛型化,算法借助迭代器处理容器的数据。
const 迭代器用于只读访问,不能修改通过迭代器指向的元素。
rbegin() 返回反向迭代器,rend() 返回反向结束迭代器。
| 函数名称 | 功能说明 |
|---|---|
| size() | 返回字符串有效字符长度 |
| length() | 返回字符串有效字符长度 |
| resize() | 改变有效字符个数,多出的空间用字符填充 |
| capacity() | 返回空间总大小 |
| clear() | 清空有效字符 |
| reserve() | 为字符串预留空间 |
| empty() | 检测字符串是否为空串 |
| shrink_to_fit() | 缩容接口 |
| 函数名称 | 功能说明 |
|---|---|
| operator[] | 返回 pos 位置的字符 |
| begin + end | 正向迭代器范围 |
| rbegin + rend | 反向迭代器范围 |
| 范围 for | C++11 支持更简洁的遍历方式 |
| 函数名称 | 功能说明 |
|---|---|
| push_back | 在字符串后尾插字符 c |
| append | 在字符串后追加一个字符串 |
| operator+= | 在字符串后追加字符串 str |
| c_str | 返回 C 格式字符串 |
| find / npos | 查找字符位置 |
| rfind | 反向查找字符位置 |
| substr | 截取子串 |
replace 接口设计较复杂,效率不高,少用。如果是少量数据用没什么大问题,要挪动数据需谨慎。
示例:空格替换
// 所有空格替换为 %%%
string s4("hello world hello friend");
cout << s4 << endl;
size_t pos = s4.find(' ');
while (pos != string::npos) {
s4.replace(pos, 1, "%%%" );
pos = s4.find(' ', pos + 2);
}
cout << s4 << endl;
// 使用 reserve、范围 for 实现
string s5("hello world hello friend");
cout << s5 << endl;
string s6;
s6.reserve(s5.size());
for (auto ch : s5) {
if (ch != ' ') {
s6 += ch;
} else {
s6 += "%%%%";
}
}
cout << s6 << endl;
| 函数名称 | 功能说明 |
|---|---|
| operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 |
| operator>> | 输入运算符重载 |
| operator<< | 输出运算符重载 |
| getline | 获取一行字符串 |
| relational operators | 大小比较 |
#define _CRT_SECURE_NO_WARNINGS 1
#include <iostream>
#include <string>
#include <algorithm>
#include <list>
using namespace std;
void Print(const string& s) {
string::const_iterator it1 = s.begin();
while (it1 != s.end()) {
cout << *it1 << " ";
++it1;
}
cout << endl;
string::const_reverse_iterator it2 = s.rbegin();
while (it2 != s.rend()) {
cout << *it2 << " ";
++it2;
}
cout << endl;
}
void Test_string2() {
string s1("hello world");
cout << s1 << endl;
s1[0] = 'x';
cout << s1 << endl;
cout << s1.size() << endl;
for (size_t i = 0; i < s1.size(); i++) {
s1[i]++;
}
cout << s1 << endl;
string::iterator it1 = s1.begin();
while (it1 != s1.end()) {
(*it1)--;
cout << *it1 << " ";
++it1;
}
cout << endl;
list<int> lt;
lt.push_back(1);
lt.push_back(2);
lt.push_back(3);
list<int>::iterator lit = lt.begin();
while (lit != lt.end()) {
cout << *lit << " ";
++lit;
}
cout << endl;
Print(s1);
auto ret1 = find(s1.begin(), s1.end(), 'x');
if (ret1 != s1.end()) {
cout << "找到了 x" << endl;
}
int i = 0;
auto j = i;
auto k = 10;
auto p1 = &i;
auto p2 = &i;
cout << p1 << endl;
cout << p2 << endl;
int& r1 = i;
auto r2 = r1;
auto& r3 = r1;
cout << &r2 << endl;
cout << &r1 << endl;
cout << &i << endl;
cout << &r3 << endl;
for (char ch : s1) {
cout << ch << ' ';
}
cout << endl;
for (auto e : lt) {
cout << e << ' ';
}
cout << endl;
for (auto& ch : s1) {
ch -= 1;
}
cout << endl;
for (const auto& ch : s1) {
cout << ch << ' ';
}
cout << endl;
int a[10] = { 1,2,3 };
for (auto e : a) {
cout << e << " ";
}
cout << endl;
}
void TestCapacity() {
string s1;
s1.reserve(200);
size_t old = s1.capacity();
for (size_t i = 0; i < 200; i++) {
s1.push_back('x');
if (s1.capacity() != old) {
cout << s1.capacity() << endl;
old = s1.capacity();
}
}
cout << endl << endl;
}
void test_string3() {
string s1("hello world");
cout << s1.max_size() << endl;
cout << s1.size() << endl;
cout << s1.capacity() << endl;
s1.clear();
cout << s1.size() << endl;
cout << s1.capacity() << endl << endl;
TestCapacity();
string s2("hello world");
cout << s2.size() << endl;
cout << s2.capacity() << endl;
s2.reserve(5);
s2.shrink_to_fit();
cout << s2.size() << endl;
cout << s2.capacity() << endl;
string s3("hello world");
cout << s3 << endl;
s3.resize(5);
cout << s3 << endl;
s3.resize(10, 'x');
cout << s3 << endl;
s3.resize(20, 'y');
cout << s3 << endl;
}
void Test_string4() {
string s1("hello world");
s1.push_back('%');
s1.append("hello friend");
cout << s1 << endl;
s1.append(10, '#');
cout << s1 << endl;
string s2("pear hello!");
s1.append(++s2.begin(), --s2.end());
cout << s1 << endl;
string s3("hello world");
s3 += ' ';
s3 += "hello world";
cout << s3 << endl;
cout << s3 + "xxxxx" << endl;
cout << "xxxxx" + s3 << endl;
s3.assign("yyyy");
cout << s3 << endl;
}
void Test_string5() {
string s1("hello world");
s1.insert(0, "xxxxx");
cout << s1 << endl;
s1.insert(0, 1, '#');
cout << s1 << endl;
s1.insert(5, 1, '#');
cout << s1 << endl;
s1.insert(s1.begin(), '$');
cout << s1 << endl;
string s2("hello world");
s2.erase(s2.begin());
cout << s2 << endl;
s2.erase(0, 1);
cout << s2 << endl;
s2.erase(5, 2);
cout << s2 << endl;
s2.erase(5);
cout << s2 << endl << endl;
string s3("hello world");
s3.replace(5, 1, "%%%%" );
cout << s3 << endl;
s3.replace(5, 3, "*");
cout << s3 << endl;
string s4("hello world hello friend");
cout << s4 << endl;
size_t pos = s4.find(' ');
while (pos != string::npos) {
s4.replace(pos, 1, "%%%" );
pos = s4.find(' ', pos + 2);
}
cout << s4 << endl;
string s5("hello world hello friend");
string s6;
s6.reserve(s5.size());
for (auto ch : s5) {
if (ch != ' ') {
s6 += ch;
} else {
s6 += "%%%%";
}
}
cout << s6 << endl;
}
int main() {
string str;
cin >> str;
getline(cin, str);
getline(cin, str, '#');
size_t pos = str.rfind(' ');
if (pos != str.size()) {
cout << str.size() - (pos + 1) << endl;
} else {
cout << str.size() << endl;
}
return 0;
}

微信公众号「极客日志」,在微信中扫描左侧二维码关注。展示文案:极客日志 zeeklog
使用加密算法(如AES、TripleDES、Rabbit或RC4)加密和解密文本明文。 在线工具,加密/解密文本在线工具,online
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online
将 Markdown(GFM)转为 HTML 片段,浏览器内 marked 解析;与 HTML转Markdown 互为补充。 在线工具,Markdown转HTML在线工具,online
将 HTML 片段转为 GitHub Flavored Markdown,支持标题、列表、链接、代码块与表格等;浏览器内处理,可链接预填。 在线工具,HTML转Markdown在线工具,online
通过删除不必要的空白来缩小和压缩JSON。 在线工具,JSON 压缩在线工具,online