在 C++ 中,string是处理字符串的核心容器,它封装了丰富的接口来简化字符串操作。本文将围绕string的迭代器访问、初始化方式、容量调整(reserve)、反转(reverse) 四大核心功能展开,结合可直接运行的代码和结果验证建议,帮你快速掌握string的实用技巧。
一、迭代器与范围 for:遍历 string 的两种核心方式
string作为 STL 容器的一种,支持迭代器(类似指针的访问工具)和范围 for 两种遍历方式,所有的STL容器都可以用以上两种方式遍历,其中范围 for 的底层本质就是迭代器。下面通过代码详细演示两者的用法。
1.1 迭代器遍历:灵活控制访问过程
迭代器的核心作用是 "指向容器元素",支持*解引用获取值、++移动到下一个元素,适用于所有 STL 容器(如vector、list等)。注意 :原文代码存在语法错误(如#include<iostrean漏写m、mainO错写括号、cout符号错误),以下是修正后的可运行代码:
cpp
#include <iostream> // 修正:补充<iostream>完整头文件
#include <string>
using namespace std; // 修正:添加分号
int main() {
string s = "asjhjksd"; // 待遍历的字符串
cout << "原字符串:" << s << endl;
// 方式1:显式声明迭代器类型(string::iterator)
string::iterator it = s.begin(); // begin()获取指向第一个元素的迭代器
cout << "显式迭代器遍历:";
while (it != s.end()) { // end()获取指向"最后一个元素的下一个位置"的迭代器
cout << *it << " "; // 解引用获取当前元素
it++; // 移动到下一个元素
}
cout << endl;
// 方式2:用auto简化迭代器类型(推荐)
// 修正:auto自动推导为string::iterator,避免长类型书写
cout << "auto简化迭代器遍历:";
for (auto it = s.begin(); it != s.end(); it++) {
cout << *it << " ";
}
cout << endl;
return 0;
}
1.2 范围 for:简化遍历的 "语法糖"
范围 for 专门用于 "遍历容器中所有元素",无需手动控制迭代器的开始和结束,语法更简洁。其底层逻辑与迭代器完全一致,遍历过程是将s的元素逐个赋值给ch。
关键细节:如何用范围 for 修改字符串?
若直接写for (auto ch : s),ch是元素的 "拷贝",修改ch不会影响原字符串;若在ch前加&(引用),则ch直接关联原字符串的元素,支持修改。
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "asjhjksd";
cout << "修改前:" << s << endl;
// 1. 普通范围for(仅遍历,不修改)
cout << "普通范围for遍历:";
for (auto ch : s) {
cout << ch << " ";
}
cout << endl;
// 2. 引用型范围for(支持修改原字符串)
for (auto& ch : s) { // 关键:添加&,ch成为原元素的引用
ch = toupper(ch); // 将小写字母转为大写
}
cout << "引用修改后:" << s << endl; // 输出:ASJHJKSD
return 0;
}
结果验证建议(图片内容)
运行上述两段代码后,截图应包含:
- 原字符串输出(如
asjhjksd); - 显式迭代器与 auto 迭代器的遍历结果(如
a s j h j k s d); - 引用型范围 for 修改后的大写字符串(如
ASJHJKSD)。
二、反向迭代器与传统访问:更多遍历选择
除了正向遍历,string还支持反向迭代器(从后往前遍历) 和数组式访问(用 [] 运算符),满足不同场景需求。
2.1 反向迭代器:从后往前遍历
反向迭代器通过rbegin()(指向最后一个元素)和rend()(指向 "第一个元素的前一个位置")控制范围,++操作实际是 "向前移动"。
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "asjhjksd";
cout << "正向遍历:";
for (auto ch : s) cout << ch << " ";
cout << endl;
// 反向迭代器遍历
cout << "反向遍历:";
auto rit = s.rbegin(); // auto推导为string::reverse_iterator
while (rit != s.rend()) {
cout << *rit << " "; // 依次输出:d s k j h j s a
rit++; // 反向迭代器的++是"向前移动"
}
cout << endl;
return 0;
}
2.2 传统数组式访问:借助 [] 运算符重载
string重载了[]运算符,允许像访问数组一样通过 "索引" 获取元素(索引从 0 开始),语法更符合 C 语言习惯。
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
string s = "asjhjksd";
cout << "数组式访问遍历:";
// size()获取字符串长度(元素个数)
for (int i = 0; i < s.size(); i++) {
cout << s[i] << " "; // 等价于*(s.begin() + i)
}
cout << endl;
return 0;
}
2.3 只读遍历:const 迭代器
若只需 "遍历不修改",可在迭代器函数前加c(如cbegin()、crbegin()),获取const类型迭代器,避免误修改。
cpp
// const正向迭代器(只读)
for (auto it = s.cbegin(); it != s.cend(); it++) {
// *it = 'a'; // 报错:const迭代器不允许修改
cout << *it << " ";
}
// const反向迭代器(只读)
for (auto rit = s.crbegin(); rit != s.crend(); rit++) {
cout << *rit << " ";
}
结果验证建议(图片内容)
截图应包含:
- 正向遍历结果(
a s j h j k s d); - 反向迭代器遍历结果(
d s k j h j s a); - 数组式访问结果(与正向遍历一致)。
三、string 的初始化:简洁的 "内置类型式" 写法
string的初始化方式有多种,最常用且直观的是拷贝初始化 ,语法与内置类型(如int)完全一致,降低记忆成本。
cpp
#include <iostream>
#include <string>
using namespace std;
int main() {
// 常用初始化:拷贝初始化(类似int a = 10;)
string s1 = "zhdshk"; // 直接赋值字符串常量
cout << "s1: " << s1 << endl;
// 其他常见初始化(补充参考)
string s2; // 默认初始化:空字符串
string s3(s1); // 拷贝构造:s3是s1的副本
string s4(5, 'a'); // 填充初始化:5个'a',即"aaaaa"
cout << "s2: " << s2 << "(空字符串)" << endl;
cout << "s3: " << s3 << "(s1的副本)" << endl;
cout << "s4: " << s4 << "(5个'a')" << endl;
return 0;
}
补充说明
更多初始化方式(如用字符指针、子字符串初始化)可参考cppreference.com或原文提到的cplusplus.com,文档中有详尽的参数说明。
结果验证建议(图片内容)
截图应包含 4 个字符串的输出:
s1: zhdshk;s2: (空字符串)(无内容);s3: zhdshk(与 s1 一致);s4: aaaaa。
四、reserve 函数:灵活调整 string 的容量
reserve(n)的核心作用是预分配字符串的容量(capacity) ,用于优化内存分配效率,不影响字符串的长度(size)和内容。理解size与capacity的区别是关键:
size:字符串当前的元素个数(实际存储的字符数);capacity:字符串在不重新分配内存的情况下,最多能存储的元素个数(底层数组的大小)。
4.1 reserve 的核心规则(原文重点)
- 若
n > 当前capacity:扩容到n(或更大,取决于编译器); - 若
n < 当前capacity:不强制缩容(是否缩容由编译器决定); - 若
n < 当前size:绝对不缩容(容量不能小于实际元素个数); - 不改变
size和字符串内容。
4.2 代码演示:reserve 的实际效果
以下代码基于原文test_string4()修正,直观展示reserve对size和capacity的影响:
cpp
#include <iostream>
#include <string>
using namespace std;
// 测试reserve函数
void test_string4() {
// 初始化一个较长的字符串
string s2("hello worldxxxxxxxxxxxxx"); // 内容:hello world + 11个x
cout << "初始状态:" << endl;
cout << "size: " << s2.size() << endl; // 输出实际字符数(11+11=22?需以运行结果为准)
cout << "capacity: " << s2.capacity() << endl; // 编译器默认分配的容量
cout << "------------------------" << endl;
// 1. reserve(20):n < 初始capacity(假设初始capacity>20)
s2.reserve(20);
cout << "reserve(20)后:" << endl;
cout << "size: " << s2.size() << endl; // size不变
cout << "capacity: " << s2.capacity() << endl; // 可能不缩容(编译器决定)
cout << "------------------------" << endl;
// 2. reserve(40):n > 初始capacity
s2.reserve(40);
cout << "reserve(40)后:" << endl;
cout << "size: " << s2.size() << endl; // size仍不变
cout << "capacity: " << s2.capacity() << endl; // 扩容到40(或更大)
cout << "------------------------" << endl;
}
int main() {
test_string4();
return 0;
}
结果验证建议(图片内容)
以 GCC 编译器为例,截图可能包含:
- 初始状态:
size:22,capacity:31(编译器默认分配的容量通常略大于实际需求); reserve(20)后:size:22,capacity:31(不缩容);reserve(40)后:size:22,capacity:40(扩容到 40)。
五、reverse 函数:一键反转 string 或容器
reverse是 STL 算法库中的函数,支持对string、vector等容器进行反转,只需传入 "待反转范围" 的迭代器(左闭右开[begin, end))。
5.1 代码演示:反转 string
cpp
#include <iostream>
#include <string>
#include <algorithm> // 必须包含:reverse函数在<algorithm>中
using namespace std;
int main() {
string s = "hello world";
cout << "反转前:" << s << endl;
// 反转:传入s的首尾迭代器(覆盖整个字符串)
reverse(s.begin(), s.end());
cout << "反转后:" << s << endl; // 输出:dlrow olleh
return 0;
}
5.2 扩展:反转 vector
reverse同样适用于vector,用法完全一致:
cpp
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
int main() {
vector<int> v = {1, 2, 3, 4, 5};
cout << "反转前:";
for (auto num : v) cout << num << " ";
reverse(v.begin(), v.end()); // 反转vector
cout << "\n反转后:";
for (auto num : v) cout << num << " "; // 输出:5 4 3 2 1
return 0;
}
结果验证建议(图片内容)
截图包含两部分:
- string 反转:
反转前:hello world,反转后:dlrow olleh; - vector 反转:
反转前:1 2 3 4 5,反转后:5 4 3 2 1。
总结
本文围绕string的核心功能展开,重点掌握:
- 迭代器(正向 / 反向、const)与范围 for 的遍历逻辑,尤其是引用型范围 for 的修改用法;
- 简洁的
string初始化方式,以及更多方式的查询渠道; reserve对容量的调整规则(不影响 size、缩容依赖编译器);reverse对容器的反转用法(需传入迭代器范围)。
string的接口远不止这些,若需深入学习,可访问cppreference.com或cplusplus.com,结合实际代码测试,才能真正熟练掌握。