【C++STL之string类概述
一、前言
本文我们就要来说一说STL中的string类,这也是我们在写C++代码的时候使用最多的
1、C语言中的字符串
首先要来谈的一点就是为什么要学习string类
string
意为字符串,那回忆一下我们在C语言阶段所学习的字符串,是以'
因此,在C++中专门搞出了一个与字符串相关的类,我们知道C++是面向对象的,我们可以在类内去写各种成员函数来对外提供操作字符串的接口,这个类就是string
类
2、string类的使用场景
那这个string有什么实际的应用场景呢,这可多了去了,如果经常刷题的同学应该瞬间能反应过来
- 从下面的两道OJ题就可以看出有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷,基本都使用string类,很少有人去使用C库中的字符串操作函数
字符串转整形数字
字符串相加
二、初步认识string类
1、概述
string类的文档介绍
- 我们来到string类的文档中可以看到它确实是一个类,而且是由一个模版类
basic_string
所实例化出来的
- 如果你有学习过 C++模版 的话就可以知道这个类即为【类模版】
- 然后由这个类模版就实例化出了很多的模版类,其中就包含我们本文所要学习的string类
那有同学问,下面的这几个【wstring】、【u16string】、【u32string】是什么呢?
- 这一块的话要涉及到编码相关的知识,如果读者对这一块没什么接触的话就当了解一下
对于编码而言我们谈到最多的就是 ASCLL码 ,它的全称叫做【美国信息交换标准代码】,总共包含了像大小写的中英字母、数字、标点符号等等共128个,用来表示老美的的一些文章字符完全足够了。
而对于ASCLL码来说,是存在一个东西叫做映射表,即一个ASCLL码值就对应一个字符
我们可以到VS中来观察一下,其实在内存中所存放的都是ASCLL码,只不过呢在显示的时候却转换为了表中所对应的字符。这个63 64 65 66
其实是十六进制的写法,转换为十进制即为97 98 99 100
,那它们所对应的字符即为a b c d
如果有同学还是不相信的话可以看看下面这个,我给
str[0]
这个位置放了数值为97,但是呢其为一个string类的对象,所以里面所存放的都是字符,可以看到在打印出来后的结果就是97所对应的ASCLL码值a
但是呢对于我们的一些中文汉字却是远远不够的,例如说下面这个”比特”
,我通过【sizeof】打印出了其在内存中所占字节数,发现有5B,这是为什么呢?原因就在于汉字的存储规则不是按照ASCLL码来的,而是专属于我国的一套编码字符集叫做GBK。在【GB2312-80】中就存储了很多有关汉字的规则
一般来说一个汉字对应的2个字节,这里的”比特”
是因为最后还有一个
最后对这个string类的特性做一个总结:
basic_string
模板类的别名,typedef basic_string string;
⚠ 在使用string类时,必须包含#include
头文件以及using namespace std
2、常用接口细述
对string类大体有个了解后我们就要去学着使用这个类里面的一些函数了
1)string类对象的默认成员函数
函数名称 | 功能说明 |
---|---|
constructor | 构造函数 |
destructor | 析构函数 |
operator= | 赋值重载 |
==① 构造函数==
- 点进第一个成员函数
Constructor
就可以看到存在7个重载,其中我框出来的三个是重点,要着重记忆,其余的了解一下即可
- 我将上面的函数整理了一下,方便观看
string(); // 构造一个空字符串
string (const char* s); // 用C-string来构造string类对象
string (const char* s, size_t n); // 用C-string的前n个字符来构造string类对象
string (size_t n, char c); // 生成n个c字符的字符串
string (const string& str); // 利用原先的字符串做拷贝构造
// 拷贝str字符串中从pos位置开始的len个字符
string (const string& str, size_t pos, size_t len = npos);
- 然后我们到VS里演示一下
- 前面的几个都好理解,来讲一下最后的这一个,可以看到在函数形参这一块给出了一个缺省值叫做
npos
,可能有的同学不清楚这个npos
是什么东西
// 拷贝str字符串中从pos位置开始的len个字符
string (const string& str, size_t pos, size_t len = npos);
- 这个我们也可以到文档中来查看一下,发现它是【无符号整数的最大值】
- 那这个值究竟是多少呢,我们可以将其打印出来看看
- 也可以到Linux平台下来查看发现不太一样,因为在Linux下使用的是g++编译器,它们底层所定义的规范是不一样的
💬 但是呢,无论这个数值是多少,其实影响都不大,因为我要说明的是即便我们不给出这个参数的话,编译器默认就是从当前的这个【pos】位置开始一直到字符串末尾
- 继续通过文档来观察一下,
substring
指的就是子串的意思,意思即为 从pos位置的len个长度去拷贝字符串的一部分(如果str字符串太短或者len为npos则直接到达字符串的末尾)
那现在的话你应该可以明白最后的这个参数我为何没有传递却拷贝到了后面的所有字符
- 接下去呢我们来讲一下赋值重载,这个我们在讲 类的六大成员函数 有提到过这个,它只能出现在类内但是不可以出现在类外,否则会产生一个冲突
==赋值重载==
string& operator= (const string& str); // 将一个string对象赋值给到另一个
string& operator= (const char* s); // 将一个字符串赋值给到string对象
string& operator= (char c); // 将一个字符赋值给到string对象
- 同样,我们到VS中来做一个测试,可以看到这三种方式都可以构成一个string的对象,不过照这么来看后面的这两种似乎没多大用处,用的最多的还是第一种
2)string类对象的常见容量操作
接下去我们来讲一讲有关string类中有关容量的一些操作
函数名称 | 功能说明 |
---|---|
size | 返回字符串有效字符长度 |
length | 返回字符串有效字符长度 |
capacity | 返回空间总大小 |
maxsize | 返回字符串的最大长度 |
clear | 清空有效字符 |
empty | 检测字符串释放为空串,是返回true,否则返回false |
reverse | 为字符串预留空间 |
resize | 将有效字符的个数该成n个,多出的空间用字符c填充 |
shrink_to_fit | 收缩到合适大小 |
① size、length、capacity
- 首先要来讲的是【size】和【capacity】,这其实就和我们在顺序表中所介绍的意思差不多,前者表示当前字符串已经存放了多少数据,后者表示当前这个字符串可容纳的空间数
- 我们到VS下通过调试来观察一下,可以看到现在这个
str
没有任何的数据,而VS为我们开出了大小默认为15的空间,其实这里应该是16,只不过最后的
- 然后去构建出一个具体的字符串来进行观察,发现
size
的值发生了一个变化。不仅如此,我还打印了一下这个字符串的length
属性,观察到其和size
是一样的
- 然后我们点进到这两个函数的定义中可以发现它们的定义竟然是一样的
- 我们在文档的时候,一定会有一种很奇怪的感觉,在C++的容器里面为什么没有
string
呢?这里要追溯到STL的一个诞生历史,其实对于string
这个类,是不属于STL的,因为它是在STL之前就已经存在了的,属于C++标准库里的内容
- 像下面这样来看的话,STL是属于标准库中的一部分,
string
也是属于标准库的一部分,但是呢二者却没有什么直接的关联。在最早期string
的长度接口是定义为【length】的,到后面STL出了之后才改为了【size】,但是这一块我们需要去考虑到一个历史追溯的问题,所以不能将这个接口给删除,因而我们才看到一模一样的两个接口实现
💬 后续我们在使用到时候直接用【size】即可,因为其他STL库中的接口使用的也是【size】
追究完这个【size】之后,我们再来谈谈这个【capacity】
- 我们使用的是下面这段代码进行测试
void TestCapacity()
{
string s;
size_t sz = s.capacity();
cout