
博主名称:deM0one ⭐️C++专栏: C++ ⭐️C++string第一讲: string第一讲
文章目录
- C++string常用接口介绍、测试及模拟
-
- [一、引言:string 操作总览](#一、引言:string 操作总览)
-
- [1.1 为什么单独研究 string](#1.1 为什么单独研究 string)
- [1.2 本文知识地图](#1.2 本文知识地图)
- [1.3 重要提醒](#1.3 重要提醒)
- 二、append:向字符串末尾追加
-
- [2.1 作用](#2.1 作用)
- [2.2 常用重载(C++98 / C++11 / C++14)](#2.2 常用重载(C++98 / C++11 / C++14))
- [2.3 理解要点](#2.3 理解要点)
- 三、erase:删除字符串中的内容
-
- [3.1 作用](#3.1 作用)
- [3.2 常用重载(C++98 / C++11)](#3.2 常用重载(C++98 / C++11))
- [3.3 理解要点](#3.3 理解要点)
- 四、replace:替换字符串中的一段
-
- [4.1 作用](#4.1 作用)
- [4.2 常用重载(C++98 / C++11 / C++14)](#4.2 常用重载(C++98 / C++11 / C++14))
- [4.3 理解要点](#4.3 理解要点)
- [五、find 与 rfind:查找内容](#五、find 与 rfind:查找内容)
-
- [5.1 find:查找第一次出现的位置](#5.1 find:查找第一次出现的位置)
- [5.2 rfind:查找最后一次出现的位置](#5.2 rfind:查找最后一次出现的位置)
- [5.3 理解要点](#5.3 理解要点)
- 六、substr:截取子串
-
- [6.1 作用](#6.1 作用)
- [6.2 函数签名](#6.2 函数签名)
- [6.3 理解要点](#6.3 理解要点)
- 七、getline:按分隔符读取输入
-
- [7.1 读取方式对比](#7.1 读取方式对比)
- [7.2 典型示例:取出最后一个单词](#7.2 典型示例:取出最后一个单词)
- [7.3 理解要点](#7.3 理解要点)
- 八、补充:内联和静态的可见性
-
- [8.1 笔记要点](#8.1 笔记要点)
- [8.2 遍历代码示例(范围 for 与迭代器)](#8.2 遍历代码示例(范围 for 与迭代器))
- [九、底层理解:手写 string 的迭代器与 reserve](#九、底层理解:手写 string 的迭代器与 reserve)
-
- [9.1 用指针模拟迭代器](#9.1 用指针模拟迭代器)
- [9.2 手写 reserve:只扩容,不修改内容](#9.2 手写 reserve:只扩容,不修改内容)
- [9.3 理解要点](#9.3 理解要点)
- 十、总结
C++string常用接口介绍、测试及模拟
本文档基于学习笔记整理,内容覆盖:string 的追加、删除、替换、查找、取子串、getline 输入读取,以及内联/静态可见性和 string 的底层手写实现。
一、引言:string 操作总览
1.1 为什么单独研究 string
- string 是 C++ 中最常用的容器之一,日常处理文本离不开它
- 掌握常用成员函数,可以高效完成"增、删、改、查、截取、输入"等操作
1.2 本文知识地图
| 操作 | 成员函数 | 说明 |
|---|---|---|
| 增 | append | 在字符串末尾追加内容 |
| 删 | erase | 删除指定位置或区间的字符 |
| 改 | replace | 替换一段子串 |
| 查 | find / rfind | 查找第一次 / 最后一次出现位置 |
| 取 | substr | 截取子串 |
| 读 | getline | 按分隔符读取输入 |
1.3 重要提醒
- 笔记中特别标注:erase 和 replace 是性能杀手,使用时要注意效率
二、append:向字符串末尾追加
2.1 作用
- 在字符串当前值的末尾追加额外的字符,从而扩展字符串
2.2 常用重载(C++98 / C++11 / C++14)
cpp
string& append(const string& str);
string& append(const string& str, size_t subpos, size_t sublen);
string& append(const char* s);
string& append(const char* s, size_t n);
string& append(size_t n, char c);
template <class InputIterator>
string& append(InputIterator first, InputIterator last);
2.3 理解要点
- 可以追加:另一个 string、C 字符串、字符缓冲区、n 个相同字符、迭代器区间
- 返回
string&,支持链式调用
三、erase:删除字符串中的内容
3.1 作用
- 删除字符串的一部分,减少其长度
- 笔记要点:erase 可以指定位置删除
3.2 常用重载(C++98 / C++11)
cpp
string& erase(size_t pos = 0, size_t len = npos); // (1) 按位置 + 长度
iterator erase(iterator p); // (2) 删除单个字符
iterator erase(iterator first, iterator last); // (3) 删除迭代器区间
3.3 理解要点
- 三种删除方式:按位置长度删、按迭代器删、按区间删
- 默认从位置 0 删到字符串末尾
- 属于性能杀手之一,频繁删除要考虑效率
四、replace:替换字符串中的一段
4.1 作用
- 替换字符串中从位置 pos 开始、跨 len 个字符的部分(或区间 [i1, i2) 之间的部分)为新内容
4.2 常用重载(C++98 / C++11 / C++14)
cpp
string& replace(size_t pos, size_t len, const string& str);
string& replace(iterator i1, iterator i2, const string& str);
string& replace(size_t pos, size_t len, const string& str, size_t subpos, size_t sublen);
string& replace(size_t pos, size_t len, const char* s);
string& replace(size_t pos, size_t len, const char* s, size_t n);
string& replace(iterator i1, iterator i2, const char* s);
string& replace(iterator i1, iterator i2, const char* s, size_t n);
string& replace(size_t pos, size_t len, size_t n, char c);
string& replace(iterator i1, iterator i2, size_t n, char c);
template <class InputIterator>
string& replace(iterator i1, iterator i2, InputIterator first, InputIterator last);
4.3 理解要点
- 两种定位方式:
pos + len方式 和[i1, i2)迭代器区间方式 - 新内容可以来自 string、C 字符串、缓冲区、重复字符或迭代器区间
- 与 erase 一样是性能杀手
五、find 与 rfind:查找内容
5.1 find:查找第一次出现的位置
cpp
size_t find(const string& str, size_t pos = 0) const; // (1) string
size_t find(const char* s, size_t pos = 0) const; // (2) C 字符串
size_t find(const char* s, size_t pos, size_t n) const; // (3) 缓冲区
size_t find(char c, size_t pos = 0) const; // (4) 字符
- 从 pos 位置开始向后查找,返回第一次出现的位置
5.2 rfind:查找最后一次出现的位置
cpp
size_t rfind(const string& str, size_t pos = npos) const; // (1) string
size_t rfind(const char* s, size_t pos = npos) const; // (2) C 字符串
size_t rfind(const char* s, size_t pos, size_t n) const; // (3) 缓冲区
size_t rfind(char c, size_t pos = npos) const; // (4) 字符
- 从后往前查找,返回最后一次出现的位置
- 注意默认起始位置是
npos(表示字符串末尾)
5.3 理解要点
- 都返回
size_t下标;找不到时返回npos - 四个重载分别对应:string、C 字符串、缓冲区、单个字符
六、substr:截取子串
6.1 作用
- 生成一个子串对象,其值初始化为当前对象子串的拷贝
6.2 函数签名
cpp
string substr(size_t pos = 0, size_t len = npos) const;
6.3 理解要点
- 子串从 pos 位置开始,跨 len 个字符
- 如果到字符串末尾还不足 len 个字符,则截到字符串结尾(哪个先到取哪个)
七、getline:按分隔符读取输入
7.1 读取方式对比
cin >> str:遇到空格或换行就停止读取getline(cin, str):默认分隔符是换行,读到换行才停止getline也可以自己设定分隔符 ,例如getline(cin, str, ',')按逗号分割
7.2 典型示例:取出最后一个单词
cpp
#include <iostream>
#include <string>
using namespace std;
int main()
{
string str;
// cin >> str; // 遇空格/换行即停
getline(cin, str); // 默认以换行作为分隔符
size_t pos = str.rfind(' '); // 找到最后一个空格
cout << str.substr(pos + 1) << endl; // 截取最后一个空格之后的内容
return 0;
}
7.3 理解要点
- 综合运用了 rfind + substr:先找最后一次出现的位置,再截取其后内容
- 空格和换行默认被视为分割符
八、补充:内联和静态的可见性
8.1 笔记要点
- 内联和静态只在当前文件可见
- 这也是为什么头文件中的 inline 函数和 static 变量不会造成多文件链接冲突
8.2 遍历代码示例(范围 for 与迭代器)
cpp
// 方式一:范围 for
for (auto e : s2)
{
cout << e << " ";
}
cout << endl;
// 方式二:迭代器
string::iterator it = s2.begin();
while (it != s2.end())
{
cout << *it << " ";
++it;
}
cout << endl;
九、底层理解:手写 string 的迭代器与 reserve
9.1 用指针模拟迭代器
- 手写 string 类中,直接用
typedef char* iterator模拟迭代器:
cpp
class string
{
public:
typedef char* iterator;
iterator begin()
{
return _str; // 指向字符串开头
}
iterator end()
{
return _str + _size; // 指向有效字符的末尾
}
private:
char* _str; // 指向堆上的字符数组
size_t _size; // 有效字符个数
size_t _capacity; // 容量
};
9.2 手写 reserve:只扩容,不修改内容
cpp
void string::reserve(size_t n)
{
if (n > _capacity) // 只有 n 大于容量才需要扩容
{
char* tmp = new char[n + 1]; // 多开 1 个位置存放 '\0'
strcpy(tmp, _str); // 拷贝旧内容
delete[] _str; // 释放旧空间
_str = tmp;
_capacity = n; // 更新容量
}
}
9.3 理解要点
- 迭代器本质是"像指针的东西":
begin()返回开头指针,end()返回_str + _size - reserve 只负责扩容,不会修改已有内容
- 扩容流程:申请新空间 → 拷贝旧数据 → 释放旧空间 → 更新容量
十、总结
- string 常用操作一览:append(增)、erase(删)、replace(改)、find/rfind(查)、substr(取)、getline(读)
- erase 和 replace 是性能杀手,使用时注意场景
- find 找第一次出现,rfind 找最后一次出现,找不到返回 npos
- getline 默认以换行为分隔符,可自定义分隔符;空格和换行默认是分割符
- 内联和静态只在当前文件可见
- 通过手写 string 的 begin/end 和 reserve,能更好理解迭代器与扩容的底层原理
任何的建议和批评欢迎指出,我们共同进步!