【C++】string类的深入介绍(1)
目录
- 【C++】string类的深入介绍(1)
 - 标准库中的string类
 - string类(了解即可)
 - string类的常用接口说明(最常用的)
 - 详细介绍string::operator[]
 
- 迭代器
 - string中的迭代器(任何容器都支持,用法都是类似的)
 - string中的反向迭代器
 - begin()、end()以及rbegin()、rend()具体指向的位置
 
- const迭代器
 - string中的Capacity
 - **max_size**
 - **capacity**
 - **clear**(清理空间但**并不释放空间**)
 - **reserve**(提前给string开空间)
 - **resize** 不单单扩容,而是**开空间加初始化**(不给初始化值默认/0)
 
作者:爱写代码的刚子
时间:2023.5.26
本篇博客主要深入介绍string类、string类的常用接口及操作,string中迭代器的使用,以及string中的部分方法。(由于篇幅有限,剩余方法以及string的深浅拷贝将在之后的博客介绍)
前言:C语言中,字符串是以’\0’结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但是这些库函数与字符串是分离开的,不太符合OOP的思想,而且底层空间需要用户自己管理,稍不留神可能还会越界访问。
C++参考网站:
C++参考
 C++官网
 如果方便地查找网页中的关键字可以使用ctrl + f进行搜索
 以C++参考网站为例,演示查找string类:
 
标准库中的string类
string类(了解即可)
- 字符串是表示字符序列的类
 - 标准的字符串类提供了对此类对象的支持,其接口类似于标准字符容器的接口,但添加了专门用于操作
单字节字符字符串的设计特性。 - string类是使用char(即作为它的字符类型,使用它的默认char_traits和分配器类型(关于模板的更多信
息,请参阅basic_string)。 - string类是basic_string模板类的一个实例,它使用char来实例化basic_string模板类,并用char_traits
和allocator作为basic_string的默认参数(根于更多的模板信息请参考basic_string)。 - 注意,这个类独立于所使用的编码来处理字节:如果用来处理多字节或变长字符(如UTF-8)的序列,这个类的所有成员(如长度或大小)以及它的迭代器,将仍然按照字节(而不是实际编码的字符)来操作。
 
总结:
- string是表示字符串的字符串类
 - 该类的接口与常规容器的接口基本相同,再添加了一些专门用来操作string的常规操作。
 - string在底层实际是:basic_string模板类的别名,typedef basic_string<char, char_traits, allocator> string;
 - 不能操作多字节或者变长字符的序列。
 
- 在使用string类时,必须包含#include头文件以及using namespace std;
 
string类的常用接口说明(最常用的)
学会查文档对C++的学习是非常重要的!(以下使用参考网站为例):
 
 这里只列举的部分,大家学习的时候一定要学会查文档!
- string类对象的常见构造
 
| (constructor)函数名称 | 功能说明 | 
|---|---|
| string()(重点) | 构造空的string类对象,即空字符串 | 
| string(const char* s)(重点) | 用C-string来构造string类对象 | 
| string(size_t n,char c) | string类对象中包含n个字符c | 
| string(const string&s)(重点) | 拷贝构造函数 | 
- string类对象的容量操作
 
| 函数名称 | 功能说明 | 
|---|---|
| size(重点) | 返回字符串有效字符长度 | 
| length | 返回字符串有效字符长度 | 
| capacity | 返回空间总大小 | 
| empty(重点) | 检测字符串释放为空串,是返回true,否则返回false | 
| clear(重点) | 清空有效字符 | 
| reserve(重点) | 为字符串预留空间 | 
| resize(重点) | 将有效字符的个数改成n个,多出的空间用字符c填充 | 
注意:
- size()与length()方法底层实现原理完全相同,引入size()的原因是为了与其他容器的接口保持一
 
致,一般情况下基本都是用size()。- clear()只是将string中有效字符清空,不改变底层空间大小。
 - resize(size_t n) 与 resize(size_t n, char c)都是将字符串中有效字符个数改变到n个,不同的是当字符个数增多时:resize(n)用0来填充多出的元素空间,resize(size_t n, char c)用字符c来填充多出的元素空间。注意:resize在改变元素个数时,如果是将元素个数增多,可能会改变底层容量的大小,如果是将元素个数减少,底层空间总大小不变。
 - reserve(size_t res_arg=0):为string预留空间,不改变有效元素个数,当reserve的参数小于
 
string的底层空间总大小时,reserver不会改变容量大小。
- string类对象的访问及遍历操作
 
| 函数名称 | 功能说明 | 
|---|---|
| operator(重点) | 返回pos位置的字符,const string类对象调用 | 
| begin + end | begin获取一个字符的迭代器 + end获取最后一个字符下一个位置的迭代器 | 
| rbegin + rend | rbegin返回一个逆向迭代器,指向字符串的最后一个字符+rend返回一个逆向迭代器,指向字符串的开头(第一个字符的前一个位置)。 | 
| 范围for | C++11支持更简洁的范围for的新遍历方式 | 
- string类对象的修改操作
 
| 函数名称 | 功能说明 | 
|---|---|
| push_back | 在字符串后尾插字符c | 
| append | 在字符串后追加一个字符串 | 
| operator+=(重点) | 在字符串后追加字符串str | 
| c_str(重点) | 返回C格式字符串 | 
| find + npos(重点) | 从字符串pos位置开始往后找字符c,返回该字符在字符串中的位置 | 
| rfind | 从字符串pos位置开始往前找字符c,返回该字符在字符串中的位置 | 
| substr | 在str中从pos位置开始,截取n个字符,然后将其返回 | 
注意:
- 在string尾部追加字符时,s.push_back© / s.append(1, c) / s += 'c’三种的实现方式差不多,一般情况下string类的+=操作用的比较多,+=操作不仅可以连接单个字符,还可以连接字符串。
 - 对string操作时,如果能够大概预估到放多少字符,可以先通过reserve把空间预留好。
 
- string类非成员函数
 
| 函数 | 功能说明 | 
|---|---|
| operator+ | 尽量少用,因为传值返回,导致深拷贝效率低 | 
| operator>>(重点) | 输入运算符重载 | 
| operator<<(重点) | 输出运算符重载 | 
| getline(重点) | 获取一行字符串 | 
| relational operators(重点) | 大小比较 | 

-  
需要注意的一个小点:
在对string类使用<<的运算符重载进行比较时,我们一定要注意==<<的优先级较高(相较于普通的运算符)==,所有我们进行比较时要带上括号!

 -  
正确使用:

 -  
  
- npos静态变量的介绍:
 
 

 npos不是-1,而是整形的最大值(因为npos是无符号整型)
 
- 其他一些重要的修饰符和字符串操作:

append(追加字符串)以及push_back(尾插一个字符)等一些函数已经实现了自动扩容(C++的好处,本质是字符管理的顺序表),但是建议使用 += ,因为 += 重载了这两种方法(例:string str;str += ('0' + val);(直接将整型val转成字符串))
(注意有些情况+=不能替代append)
下面是append具体信息:

 
具体用法查文档即可
详细介绍string::operator[]
示例:
 
上述代码中str和a虽然都是字符串,但是str的实现逻辑是调用string::operator,而a的实现逻辑是*(a+1);(在clion编译器中编译器跳过了第9行的a[1];语句,没有执行(编译器的优化))
迭代器
string中的迭代器(任何容器都支持,用法都是类似的)
示例:
 
- iterator是像指针一样的类型,有可能是指针,有可能不是指针(封装的指针)。(其实iterator的底层是用指针来实现的)
 - 范围for(底层替换为迭代器,可以查看反汇编代码,一个类支持迭代器就支持范围for)

 
以上代码中若要进行对str2的修改可以使用引用:
 
- 链表中使用迭代器

iterator提供了一种统一的方式,访问和修改容器的数据。算法通过迭代器去处理容器中的数据 - 迭代器可以和容器进行配合
以reverse函数举例:

由于reverse提供了list模版,所以可以对链表实现逆置。
当然,也可以使用范围for来替代迭代器:

 
string中的反向迭代器

 而范围for不能反向遍历
begin()、end()以及rbegin()、rend()具体指向的位置
如下图所示
 
const迭代器
注意auto在自动识别类型时并不带上常量属性!
 
- 如果我们想要使迭代器带上常量属性需要加上const_

此时使用迭代器时不能改变存储在容器中的数据。
附:其他迭代器补充:

可以去作者提供的C++参考网站上去查询函数的具体用法(建议多查找网站) 
string中的Capacity

- string类中有两种表示字符串长度的方法(size()和length()),这里只推荐使用size(),因为有些STL不支持length()(比如map)
 
max_size
max_size在不同的编译器上的结果不同。(所以使用时需谨慎,因为STL只是规范,它有许多不同的版本(大同小异),导致结果不同)
 演示:
 clion下:
 
- Linux下:

 
capacity
同max_size,在不同的编译器下的结果并不相同!
 clion下:
 
 Linux下:
 
 同时不同的编译器的扩容机制也不相同:
 演示:
 clion下:
 
Linux下:
 
clear(清理空间但并不释放空间)
clion下:
 
 Linux下:
 
 所以clear()并不会释放空间
reserve(提前给string开空间)

 clion下:
 clion即使清理了数据,也不会进行缩容
 
Linux下:
 如果清理了数据使用reserve就会进行缩容,缩为0
 
 如果没有清理数据也进行缩容,缩小到size大小
 
不同的编译器reserve的效果不同,同时还与clear函数有关,clion下没实现缩容,而Linux的g++编译器下会实现缩容(使用clear清理数据后会缩到0,如果没有清理数据则会缩小到size大小)。
resize 不单单扩容,而是开空间加初始化(不给初始化值默认/0)

 resize如果给的值比原来string的size小,并不会缩容,capacity不会改变,空间没销毁,但是字符串的长度改变了 因为缩容是有代价的,所以resize不会改变空间,以免之后还要开空间
- 如果想要实现缩容可以用shrink_to_fit函数(具体用法查网站即可),但不建议缩容。
 



















