【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函数(具体用法查网站即可),但不建议缩容。