C++ string 部分功能详解:迭代器、初始化与常用函数

C++ string 部分功能详解:迭代器、初始化与常用函数

在 C++ 中,string是处理字符串的核心容器,它封装了丰富的接口来简化字符串操作。本文将围绕string迭代器访问、初始化方式、容量调整(reserve)、反转(reverse) 四大核心功能展开,结合可直接运行的代码和结果验证建议,帮你快速掌握string的实用技巧。

一、迭代器与范围 for:遍历 string 的两种核心方式

string作为 STL 容器的一种,支持迭代器(类似指针的访问工具)和范围 for 两种遍历方式,所有的STL容器都可以用以上两种方式遍历,其中范围 for 的底层本质就是迭代器。下面通过代码详细演示两者的用法。

1.1 迭代器遍历:灵活控制访问过程

迭代器的核心作用是 “指向容器元素”,支持*解引用获取值、++移动到下一个元素,适用于所有 STL 容器(如vectorlist等)。注意:原文代码存在语法错误(如#include<iostrean漏写mmainO错写括号、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)和内容。理解sizecapacity的区别是关键:

  • size:字符串当前的元素个数(实际存储的字符数);
  • capacity:字符串在不重新分配内存的情况下,最多能存储的元素个数(底层数组的大小)。

4.1 reserve 的核心规则(原文重点)

  1. n > 当前capacity:扩容到n(或更大,取决于编译器);
  2. n < 当前capacity不强制缩容(是否缩容由编译器决定);
  3. n < 当前size:绝对不缩容(容量不能小于实际元素个数);
  4. 不改变size和字符串内容。

4.2 代码演示:reserve 的实际效果

以下代码基于原文test_string4()修正,直观展示reservesizecapacity的影响:

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:22capacity:31(编译器默认分配的容量通常略大于实际需求);
  • reserve(20)后:size:22capacity:31(不缩容);
  • reserve(40)后:size:22capacity:40(扩容到 40)。

五、reverse 函数:一键反转 string 或容器

reverse是 STL 算法库中的函数,支持对stringvector等容器进行反转,只需传入 “待反转范围” 的迭代器(左闭右开[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的核心功能展开,重点掌握:

  1. 迭代器(正向 / 反向、const)与范围 for 的遍历逻辑,尤其是引用型范围 for 的修改用法;
  2. 简洁的string初始化方式,以及更多方式的查询渠道;
  3. reserve对容量的调整规则(不影响 size、缩容依赖编译器);
  4. reverse对容器的反转用法(需传入迭代器范围)。

string的接口远不止这些,若需深入学习,可访问cppreference.comcplusplus.com,结合实际代码测试,才能真正熟练掌握。

Read more

算法王冠上的明珠——动态规划之路径问题(第一篇)

算法王冠上的明珠——动态规划之路径问题(第一篇)

目录 1. 什么叫路径类动态规划 一、核心定义(通俗理解) 二、核心特征(识别这类问题的关键) 2. 动态规划步骤 状态表示 状态转移方程 初始化 填表顺序 返回值 3. 例题讲解 3.1 LeetCode62. 不同路径 3.2 LeetCode63. 不同路径 II 3.3 LeetCodeLCR 166. 珠宝的最高价值 今天我们来聊一聊动态规划的路径类问题。 1. 什么叫路径类动态规划 路径类动态规划是 动态规划的一个重要分支,核心解决 “从起点到终点的路径相关问题”—— 比如 “路径总数”“最短路径长度”“路径上的最大 / 最小和” 等,其本质是通过 “状态递推” 避免重复计算,高效求解多阶段决策的路径问题。 一、

By Ne0inhk
【数据结构】常见时间复杂度以及空间复杂度

【数据结构】常见时间复杂度以及空间复杂度

时间复杂度与空间复杂度 * 一、复杂度的概念 * 二、时间复杂度 * 1、大O的渐进表示法 * 2、函数clock计算运算时间 * 3、常见复杂度对比 * 3.1常数项复杂度 * 3.2线性时间复杂度 * 案例1 * 案例2 * 3.3平方阶复杂度 * 3.4对数复杂度 * 3.5递归函数 * 单递归 * 双递归 * 三、空间复杂度 * 冒泡排序O(1) * 三个反置O(N) 一、复杂度的概念 * 一个算法的好坏,主要是对比两者的时间和空间两个维度,也就是时间和空间复杂度。 * 时间复杂度主要衡量一个算法运行的快慢,空间复杂度主要衡量一个算法运行需要的额外空间 二、时间复杂度 * 算法的时间复杂度是一个函数式T(N),算法中的基本操作的执行次数,为算法的时间复杂度。 * 注:编译器的不同,编译所需要的时间也不同。越新的编译器,编译的时间往往比旧的编译器快 * 当一个算法函数式为T(

By Ne0inhk
数据结构-单链表

数据结构-单链表

单链表 * 概念与结构 * 结点 * 链表的性质 * 链表的打印 * 实现单链表 * 头文件 * 源文件 * 单链表的打印 * 单链表申请新节点内存 * 尾插 * 头插 * 尾删 * 头删 * 查找 * 在指定位置之前插入数据 * 在指定位置之后插入数据 * 删除pos结点 * 删除pos之后的结点 * 销毁链表 * 链表的分类 * 代码地址 概念与结构 概念:链表是⼀种物理存储结构上非连续、非顺序的存储结构,数据元素的逻辑顺序是通过链表中的指针链接次序实现的 逻辑结构:线性 物理结构(存储结构):不一定是线性的 链表就类似一个火车,车头是哨兵位(可有可无),车厢是节点 * 将火车里的某节车厢去掉或加上,不会影响其他车厢,每节车厢都是独立存在的。 在链表⾥,每节“车厢”是什么样的呢? \color{red}{在链表⾥,每节“车厢”是什么样的呢?

By Ne0inhk
【数据结构】排序详解:从快速排序分区逻辑,到携手冒泡排序的算法效率深度评测

【数据结构】排序详解:从快速排序分区逻辑,到携手冒泡排序的算法效率深度评测

🔥@晨非辰Tong: 个人主页 👀专栏:《C语言》、《数据结构与算法入门指南》 💪学习阶段:C语言、数据结构与算法初学者 ⏳“人理解迭代,神理解递归。” 文章目录 * 引言 * 一、介绍交换排序 * 二、高效交换--快速排序“:递归版 * 2.1 介绍:创造背景以及基本思想 * 2.2 基于二叉树结构的主体框架 * 三、找基准值key的三种==递归版==实战方法 * 3.1 快排核心构成:寻找key的算法之"hoare"版本 * 3.3.1 画图理解算法 * 3.3.2 代码实战 * 3.1.3 ==**代码分析**== * 3.2

By Ne0inhk