目录
3. size 、 length、capacity、empty 函数
16.find_first_of 和 fnid _last_of
一. string 类是什么
string 在C++中是一个类模板,它的原生类型是 basic string 的这个类,只是被库实例化成了 char 类型,所以string是一个字符型的顺序表,。简而言之string 在C++中是一个类,可以创建字符顺序表,在使用这个类前,需要包上string这个头文件。( #include<string> )
二. 构造string类型的对象
2.1 定义和初始化
我们在构造string类型的对象时,可以构造不写参数,调用string类的默认构造,也可以在()中 写参数(一般是一个字符串)来进行初始化。 以下是string类型的构造函数
2.2 string对象的特点
1. 输入输出
上文说过string类型的对象是一个字符类型的顺序表,在C语言中写一个顺序表,在为其写push_back(插入元素的函数)时都要考虑到插入是否会造成下标越界和是否需要扩容的问题,但是在对string类型的对象进行插入和输出的数据时,我们可以使用流插入和流提取(<< >>)的方式对string对象进行输入输出,而且不用担心越界的问题, C++ 可以按照需求来定义string对象的大小,不存在C语言中的静态数组给我们带来的困扰。
2. 拼接
在C++中对于两个string类型的对象我们可以用 + 进行拼接操作 。利用了函数重载 operator + 来完成拼接操作让代码的可读性提高了很多。
3. 遍历
因为string类重载了[ ] 所以我们可以像使用数组一样去访问string类型的对象,重载的版本有两 个,一个是普通类型的一个是const类型的。这里设置两个版本的原因就是非const类型可以对顺序表进行读写操作,而 const 只允许读顺序表。
在遍历string对象时,一共有两种方式来遍历 ,其一就是像数组一样去遍历string对象的值,其二是利用迭代器去遍历。
(1)数组式遍历法
string类中有一个函数叫size可以返回这个对象的大小
string 对象的遍历,因为[ ]是使用引用返回,所以我们不仅可以读也可以进行写的操作
(2)迭代器遍历法
迭代器遍历,就是对数据结构中数据的一种遍历方式, intrator 本身也是一个类,用这个类创建出的对象可以把它想成一个指针,挨个往后遍历,虽然它的行为很像一个指针,但是他不是指针,此种方式也可以对对象中的数组进行读写操作,迭代器是一种很主流的遍历方法,他不仅可以遍历string 类型的对象还可以再list、哈希表等类型 的对象中进行遍历,它都是在类域中实现的,屏蔽了底层的 实现细节。
小技巧:在定义迭代器时,我们每次都需要写在哪个域中的迭代器,非常麻烦,这里可以使用auto,让编译器自己去推导我们定义对象的类型
begin函数返回第一个数据的位置,而end函数返回有效数据的下一个位置,可以理解为在\0的 位置,在这里有一点需要注意,我们在用迭代器访问对象数组里的内容时我们可以把while 循环中的判断条件写成<,因为string 对象中的数组在内存中是一块连续的空间,而 list 等其他数据结构中的各个节点并不一定是连续存储的,所以最好把 while中的判断条件写成!=,!=是一种通用的写法。
迭代器的逆序遍历方式
在reverse_iterators(迭代器)类中有rbegin 和rend 这2个函数,其作用是逆置遍历整个数组,这里的 it 的++ 就是倒着走的
const 类型的迭代器
迭代器出也是分const类型的哦,const类型的迭代器只支持读,不可以写,在定义const类型的迭代器时最好用auto,让编译器自动的帮我们去判断类型
(3)范围 for 遍历
C++中也可以用语法糖来遍历string类型对象的数组,他可以自动取数组或者容器中的元素把他赋给 ch,自动判断结束,自动加加。从底层来说 ,是编译器编译时将其替换成了迭代器,ch就是*it把值赋给了ch,不用再简引用了 ,语法糖不支持倒着遍历数组。 从底层的角度来看,范围for的方式和迭代器便利的方式其实本质上是一样的
语法糖可以通过引用的方式来修改对象数组的值
三. string 中的函数
1. 构造函数
string类型重载了很多个构造函数,我们可以往其中写参数来实现不同的功能
第三个重载的构造函数(substring) 的功能是是从pos位置开始拷贝 len 个元素。
三个参数中其中的 len有一个缺省参数 npos ,nops是string类中的静态成员函数,它是一个静态成员变 量长度是-1,它的类型是 size_t ,size t 相当于无符号整型,为什么这里是有符号的呢,因为-1 在 计算机的底层中,存储的是补码,这里会发生一个类型的转换也就是把-1转换成一个整数,就是全 1,在这里全1的无符号整数是 42亿9千万(4GB)。C++规定,如图所示,所以在这里 len 的长度等于 npos 的话,编译器就把这个数组中的元素从pos 位置开始,有多少就取出来多少
如果我们想在初始化的时候,想从pos位置开始取一直取到尾部的位置我们就可以使用这个构造函数的缺省参数来实现,如下所示。
第七个重载的构造函数(range(7))的作用是使用迭代器的区间进行初始化
2. 运算符重载
(1)= 的运算符重载
(2)+= 的运算符重载
3. size 、 length、capacity、empty 函数
(1)size和length:
string类中的capacity中有size和length两个函数,这两个函数都是返回string对象中数组中数据的 个数的(不包括\0),length函数是先出现的,后又出现size的原因是,在STL出现后size更具有通用性,length并不具有通用性,我们站在所用的容器的角度上来看时,对于线性结构我们是可以说 length的,但是树形结构说length就会描述不准确了。
(2)capacity函数:返回的是数组的容量
(3)clear函数:在这里只是清理数组中的数据,并不会释放空间
(4)empty函数:会判断数组是否为空
4. reserve 函数
(1)reserve函数的作用
reserve函数的功能是可以改变string类对象的capacity,就是说它可以提前的开空间,但是一般编译器的环境下都不可以缩小 capacity(reserve函数中的值比capacity小)。
(2)reserve的性质
如果在reserve函数中我们没有写参数的话,string类型的对象随着数据量的增大会自动的进行扩容,在不同的编译器中,扩容的方式也都是不一样的,在g++中是两倍两倍的扩容,而在vs2019中大约是1.5倍的扩容。
但是如果我们在reserve函数后面的括号中写了参数(n),那么编译器就会提前把n个空间开好,并且以后就不会再进行扩容了,)reserve在有的编译器(vscode2019)中开的空间很有可能比你需要的空间大的(你要钱妈妈可能多给一点),多给的空间用来做空间对齐。另外一种的编译器(g++)是要多少空间就给你开多少空间的。但是加了这个函数以后,无论哪种编译器都不会再对对象进行扩容了。reserve的价值就是,如果确定知道大约有多少空间,就提前开好,减少扩容,提高效率。
5. resize
resize函数的功能是改变string对象的长度(length),resize函数有两个形参,第一个形参类型是一int(n),第二个形参类型是char,其缺省参数为null。如果我们在用resize的时候只写了一个整数,那么第二个参数的值会自动使用缺省参数,自动的在最后一位的位置加 n-size个 /0,如果写了第二个实参,那么就在对象的最后加加 n-size个上实参的值。如果第二个实参n
(1 ) 比capacity大(n >capacity)那么就进行扩容,
( 2 ) 值比size大比capacity小(size < n < capacity),就正常进行插入操作
( 3 ) 如果给的值比size小 (n<size) 那么就只保留字符串的前n个字符的值。
它的特点就是把你的size整到n。输入的整数n比size大就是插入操作,如果比size小就是删除操作
6 . at 函数
at 函数和[ ]是一样的,只不过在下表越界时,会抛出一个异常,[ ]是直接断言,在越界时直接终止程序。一般情况下[ ]用的更多。
7. append 函数
在string对象需要插入一个字符串时,需要用到append函数,但是如果设计成push-back的重载函数会更方便一些。
append的应用如下所示
在插入字符串时用的更多的还是 +=重载运算符
8. assign 函数
assign 是一个 std标准库中的函数,它的作用是将一个字符串的值赋值给一个string对象,如果该对象中已经有值,那么他会将原来对象中的值给覆盖掉
9. insert
如果我想头插string类型的对象,就需要使用到insert函数,理论上而言是不需要设计与迭代器相关的函数的, 我们想头插字符使用最多的是下表中的fill和single charcter 这三个接口。
用法如下所示
10. erase
string对象的删除函数是erase,用的最多的是第一个接口
11.replace 函数
replace的作用是替换,可以把某个位置的值换成一个字符串,但是在这里并不建议使用这个函数,因为接口设计复杂繁多,需要用的时候查一下文档就好了,insert/erase/replace 能不用尽量不用因为他们都需要挪动数据,效率很低。
12.swap 函数
例题:将s2字符串的空格都换成20%的字符串输出。
如果想要把s2对象的空格变成 20% 的话可以使用string类里面的swap函数(交换s2和s3),它和std中的模板函数不一样,他不会进行深拷贝,而是直接交换string对象中指向字符串的指针 。
C++对于string一共有三个swap函数需要去区分,首先string类中有一个swap函数,它只会对于两个对象的-str、size、capacity进行交换,并不会进行函数模板的三次深拷贝,但是在全局函数中也有一个对于string类型的swap函数,它的功能和string类中的swap函数的作用是一样的。它存在的意义就是不会调用std中的swap模板函数,因为用模板函数的话会进行三次深拷贝,效率太低浪费空间和时间。
13.find 函数
在find函数中, 有若干的函数重载,从头找字符x或者字符串s第一次出现的位置,如果找不到的话就返回npos。
character:寻找字符C,从pos位置开始找,返回第一次找到的位置,找不到返回npos。
14.rfind 函数
rfind倒着开始寻找字符x第一次出现的位置
15. substr 函数
substr可以取一个子字符串,从pos位置取len个字符,len可以使用npos这个缺省参数(有多少取多少)
例题:将一个网址的协议名、域名以及其他部分分别取出来
16.find_first_of 和 fnid _last_of
( 1 ) find_first_of函数 第一个形参是一个需要查找的字符串,只要有一个字符串的元素出现了此函数就返回这个元素的位置
以下是find_first_of 函数的用法
( 2 ) find_last_of函数 相当于find_first_of 倒着查找的版本