文章目录
- 前言
- 一、认识string
-
- [1.1 string 是什么](#1.1 string 是什么)
- [1.2 string相关资料](#1.2 string相关资料)
- 二、编码对于string的作用
-
- [2.1 编码是什么](#2.1 编码是什么)
- [2.2 编码与string的联系](#2.2 编码与string的联系)
- 三、默认构造函数
-
- [3.1 构造函数](#3.1 构造函数)
- [3.2 赋值运算符重载](#3.2 赋值运算符重载)
- [3.3 析构函数](#3.3 析构函数)
- 四、三种常用遍历
-
- [4.1 operator[ ]](#4.1 operator[ ])
-
- [4.1.1 size()](#4.1.1 size())
- [4.1.2 operator[ ]的使用](#4.1.2 operator[ ]的使用)
- [4.2 iterator迭代器](#4.2 iterator迭代器)
-
- [4.2.1 迭代器是是什么](#4.2.1 迭代器是是什么)
- [4.2.2 关于迭代器的用法](#4.2.2 关于迭代器的用法)
- [4.2.3 迭代器遍历操作](#4.2.3 迭代器遍历操作)
- [4.3 auto范围for](#4.3 auto范围for)
- 五、容量相关接口
-
- [5.1 查询容量](#5.1 查询容量)
- [5.2 修改容量](#5.2 修改容量)
-
- [5.2.1 string 的数据存储](#5.2.1 string 的数据存储)
- [5.2.2 reserve()接口](#5.2.2 reserve()接口)
- [5.2.3 resize()](#5.2.3 resize())
- [5.2.3 clear()接口](#5.2.3 clear()接口)
- [5.2.4 empty()接口](#5.2.4 empty()接口)
- [5.2.5 shrink_to_fit()接口](#5.2.5 shrink_to_fit()接口)
- 总结
前言
C++历久弥新的元素有什么?我可以大胆的说其中就有STL库的伟大功劳,那么STL库是什么、它又有什么呢?今天我们将学习STL库中的string,通过该容器看管中窥豹,见识STL的伟大。
一、认识string
1.1 string 是什么
C++ 的 string 类是C++ 标准库(STL)提供的一个专门用于处理字符串的封装类,定义在 头文件中,属于 std 命名空间 (一定要包头文件)。
它相当于一个工具箱,在你对字符类型的数据处理时可以随意使用里面的工具即"函数方法",省略了我们造工具的过程。
- 核心组成:
数据成员:存储字符的数组、当前字符串长度、已分配的内存容量等
成员函数:操作字符串的方法(size()、find()、replace() 等)
重载运算符:让 +、==、[] 等运算符能直接用于字符串操作(这是它最方便的特性之一) - 核心特性:
初始化时,根据字符串长度分配内存
拼接 / 扩容时,自动重新分配更大的内存,拷贝原有内容,释放旧内存
销毁时,自动释放占用的内存(无需手动 free/delete)
接下来让我们从各个角度来认识吧
1.2 string相关资料
接下来**C++string文档**(点击跳转)文件很有用,下面的讲解也会根据这个cplusplus文档来讲解。
二、编码对于string的作用
2.1 编码是什么
&emsp ;编码 就是把一种信息,按照固定规则,转换成另一种统一格式的符号 / 数字 / 代码,方便存储、传输、识别、使用。如我们常用的ASCII码就是一种编码

c但可以发现这个编码只支持了英文与数字的转换,为了改变这种现象,又出现了许多编码,如:GBK(中文编码)、万国码(UTF-系列)等等,实现了数字与语言的对应。
2.2 编码与string的联系
三、默认构造函数
3.1 构造函数

| 编号 | 语法 | 说明 | 使用方法 |
|---|---|---|---|
| 1 | string() | 默认构造 | 无参构造,即创造空字符串 |
| 2 | string (const string& str) | 拷贝构造 | 用已有的string对象进行构造 |
| 3 | string (const string& str, size_t pos, size_t len = npos) | 字串构造 | 从已有string对象的pos下标取len长度构造**(超出长度则取到末尾),不传长度视为全部(默认npos为-1)** |
| 4 | string (const char* s) | C语言字符串构造 | 以 "\n"为结尾 的字符数组 |
| 5 | string (const char* s, size_t n) | C语言字串构造 | 从字符数组的pos下表取len长度构造,与上同理 |
| 6 | string (size_t n, char c) | 字符构造 | 以某一字符c,连续n个构造 |
| 7 | template string (InputIterator first, InputIterator last) | 迭代器构造 | 指向char的指针构造(迭代器底层为指针) |
| 8 | string (initializer_list il) | 初始化列表构造 | 用{ }里的字符构造 |
| 9 | string (string&& str) noexcep | 移动构造 | 转移已有资源构造新对象 |
标红的构造方法为常用方法,其他知道即可,并且编号8、9是C++11新出的两种方法,涉及到初始化列表和右值以及异常的使用(今后的章节将会讲解)。
3.2 赋值运算符重载

| 编号 | 语法 | 说明 | 使用方法 |
|---|---|---|---|
| 1 | string& operator= (const string& str) | 字符串赋值 | 用string对象赋值 |
| 2 | string& operator= (const char* s) | C语言字符串赋值 | 使用以 "\n "结尾的 C 字符串(如 "Hello")赋值。 |
| 3 | string& operator= (char c) | 字符赋值 | 以单个字符赋值 |
| 4 | string& operator= (initializer_list il) | 初始化列表赋值 | 初始化列表构造 |
| 5 | string& operator= | 移动赋值 | 将已有的资源转移 |
编号5为C++11新语法,现在不需要了解
3.3 析构函数

在对象的生命周期结束时自动调用,释放资源。
四、三种常用遍历
4.1 operator[ ]
operator[ ] 的实现还需要其他接口的帮助,让我们先来了解一下这些接口。
4.1.1 size()

调用size()接口就可以取出该字符串的长度了,当然文档里还有个length接口,其实与size用法一致,size是后来实现为和其他容器一致。
4.1.2 operator[ ]的使用

函数返回值为字符串对象pos下标的字符引用
cpp
string s1("hello world")
for(int i = 0;i < s1.size();i++)
{
cout >> s1[i] >> " ";
}
4.2 iterator迭代器
4.2.1 迭代器是是什么
迭代器是一种用于遍历容器(集合、序列)元素的对象,提供统一接口,能依次访问集合中的每一个元素,且不暴露容器内部结构。
STL里的每个容器都有它独有的迭代器,实现底层不尽相同,这里底层为指针,后面不同在做讲解,与其他类型定义变量的语法相同,都是类型+变量名。
4.2.2 关于迭代器的用法

| 函数名 | 属性 | 返回值 | 说明 |
|---|---|---|---|
| begin() | 无 | iterator | 返回指向容器第一个元素的正向迭代器 |
| end() | 无 | iterator | 返回指向容器最后一个元素后一个位置的正向迭代器 |
| rbegin() | 反向 | reverse_iterator | 返回指向容器最后一个元素的反向迭代器(从后往前) |
| rend() | 反向 | reverse_iterator | 返回指向容器第一个元素前一位置的反向迭代器 |
| cbegin() | const只读 | const_iterator | 返回指向容器第一个元素的正向只读迭代器 |
| cend() | const只读 | const_iterator | 返回指向容器最后一个元素后一个位置的正向只读迭代器 |
| crbegin() | const只读 、反向 | const_reverse_iterator | 返回指向容器最后一个元素的反向只读迭代器 |
| crend() | const只读 、反向 | const_reverse_iterator | 返回指向容器第一个元素前一位置的反向只读迭代器 |
蓝色标出的是日常中常用的迭代器,需要着重记忆。
4.2.3 迭代器遍历操作
cpp
string::iterator it = s1.begin();
for(;it != s1.end();it++)
{
cout << *it << " ";
}
里面代码底层实现是依靠重载实现的,格式与我们之前的遍历几乎一致,今后这个方式将会一直陪伴我们的学习。
4.3 auto范围for
C++11引进的新语法,作用为自动推导类型。
自动推导变量类型,不用手动写 int、char、string 等类型
cpp
//for(auto& e:arr)
for(auto e: arr)
{
cout << e << " ";
}
在引用的情况下可以直接对e存储的数据直接进行修改,底层就是迭代器,具有自动迭代、自动判断的特点。(因此所有容器都支持范围for)
如图,在反汇编中可以发现调用了封装的begin与end

auto 不要随便作为函数的返回值与参数
五、容量相关接口
5.1 查询容量


| 编号 | 函数名 | 返回值 | 作用 |
|---|---|---|---|
| 1 | length() | size_type | 返回字符串的有效长度(最后索引 - 0索引 + 1) |
| 2 | size() | size_type | 与length()相同,因为兼容性并为统一STL标准存在 |
| 3 | max_size() | size_type | 返回字符串的最大长度(实际上与返回值的字节数有关) |
| 4 | capacity() | size_type | 查看字符串目前最大容量,判断是否扩容 |
容量的接口常用的只有size和capacity,其他的了解即可。
5.2 修改容量
想要修改容量就必须先知道string的存储方式,才能对其的容量做出修改操作。
5.2.1 string 的数据存储
了解其底层就离不开它的存储方式,下图就是监视窗口中其显示的变量部分,我们讲解其中部分变量 来了解底层的方法。

| 名称 | 类型 | 作用 |
|---|---|---|
| _Buf | char[16] | 字符串的临时存储位置,当size小于16时存在buff中,大于则废弃 |
| _Ptr | char* | 当字符串size大于16时,字符串存储位置 |
| _Mysize | size_t | 字符串的真实长度 |
| _Myres | size_t | 字符串现在最大的容量(当size等于其时,扩容) |
当然在操作系统不同时,底层的扩容逻辑不同,如:VS是1.5倍,Linux的g++是2倍。

5.2.2 reserve()接口

- 作用:
- 直接修改
_Myres变量,提前开好设置好的空间,实际空间会大于等于输入空间(vs有整数对齐功能),而g++不会 - 当目前容量大于设定容量,编译器会发起不具有强制性的缩容请求,不同编译器处理情况不同,vs不会缩,容而g++会缩容。
| 情况 | 变化 |
|---|---|
| n < size | vs和g++ 都不缩容 |
| size < n < capacity | vs不缩容,g++缩容 |
| n > capacity | 两者都扩容 |
5.2.3 resize()

- 作用:
- 将字符长度设置为输入的变量n个长度。
- 如果n小于当前字符串的size时,就会将size设置为n,并且移除n长度后的内容
- 如果n大于size且小于capacity时,就会将size设置为n,并且在原来的末尾插入空字符(\0)使达到n的长度
- 如果n大于capacity时,会先扩容再续写。
5.2.3 clear()接口

删除string的存储的内容,并把size设置为0,一般不会影响capacity。
5.2.4 empty()接口

判断是否为空接口
判断string是否为空,为空返回true。
5.2.5 shrink_to_fit()接口

缩减capacity使其等于size (不计算\n),同reverse将n 小于 capacity时相似都是非强制性的请求,可能会使得capacity大于size
总结
这就是本节的全部内容了,string是第一个接触到的STL容器,所以讲的比较详细,在后面容器的讲解则会省略所以的共同内容,感谢您的阅读,在本篇我们学会了string的默认函数、遍历方法、迭代器、容量接口,接下来我们将学会更多内容。