这篇主要讲string类下不同类型中一些比较常用的接口(并不会讲全部接口)。
1.Iterators
Iterators类型下除了我们上一篇所讲的begin和end接口外,还需要了解的还有rbegin和rend:
与begin和end的用法一样,区别就是begin和end是从左到右,而regin和rend是从右向左,rbegin返回的是最后一个数据,而rend返回的是第一个数据的前一个位置。
用图形来演示过程就如上图所示。
2.Capacity
2.1length
length与之前的size一样,都是可以返回字符串的长度:
但是它的用途并没有size广泛,因为length能做到的size一样能做到,并且size能做到的length不一定能做到,比如:如果想知道到一个二叉树有多大,我们需要的肯定是二叉树结点的个数,而不是二叉树的长度,这点size能做到,但是length就做不到。
2.2capacity
这个得到的就是string类底层第一次开辟的容量大小:
可以看出在vs编译器下,底层数组第一次开辟容量为15。
当然,如果你存入的数据大于现在的数组容量,底层也是会扩容的:
通过这段程序我们可以观察到在vs编译器下,每次扩容后数组的容量是多少。
其实不同的编译器下扩容的规则是不一样的,在vs编译器下除了第一次扩容外,其余每次扩容都是之前容量的1.5倍大小,而在linux编译器下,每次扩容都是之前容量的2倍,扩容规则是由编译器来决定的。
2.3reserve
这个接口是可以主动控制底层数组容量的大小:
虽然可以扩容,但是不一定扩容后的大小就是我们所规定的,因为底层可能会因为其他的原因会多扩一些容量,不已经我们传多少,它就扩容多少。
既然能扩容,那就能缩容:
按常理来说,既然能扩容那应该就能缩容,但事实并不是如此,用reserve缩容是做不到的,可能有人会觉得是因为比初始容量才无法缩容,那我们再看:
事实就是我们扩容后再缩容也是做不到的,也就是说reserve一般就用来扩容。
其实这个也与编译器有关,在vs编译器下是坚决不缩容的,但在其他编译器下不一定。
2.4resize
这个接口顾名思义就是改变size的,不过改变size也分为三种情况:
2.4.1.size < resize < capacity(插入数据):
当前resize的大小就是位于这个区间,在具体的大小后面,要加上你要插入的数据,因为你要改变size的大小,那就要插入数据。
根据程序运行的结果可以看出确实插入了数据,也确实改变了size的大小。
2.4.2resize > capacity(扩容+插入数据):
此时我们resize的大小已经超出了初始容量。那么我们要插入数据就必然要扩容,程序运行后我们观察到确实发生了扩容,并且也成功将数据插入进去。
2.4.3resize < size(删除数据):
此时resize的大小已经小于原先size的大小,那么就要删除数据。
我们再调用resize接口就只需要传大小即可,接口只会截取前n个数据来改变size的大小。
3.Element access
这个类型除去我们之前讲过的[]符号重载,还需要了解的就是at:
at和[]符号重载功能几乎是一样的,唯一不同的就是在越界时at是抛异常,而[]符号重载是assert断言。
这就是at越界时抛得异常。
4.Modifiers
4.1push_back
没错,就是之前学习顺序表时的尾插,因为string类底层也是数组,所以也是能够尾插的:
push_back能够每次尾插一个字符。
4.2append
与push_back不同的是,append是追加,在结尾追加一个字符串:
功能上与push_back几乎没什么区别,一个是尾插一个字符,一个是追加一个字符串。
4.3+=符号重载
这个接口可以说是集合了push_back和append,既可以尾插一个字符,也可以追加一个字符串:
所以我们在日常使用时一般都是用+=符号重载,即简洁,功能也完善。push_back和append就是+=符号重载的下位替代。
4.4insert
insert的功能就是在指定位置之前插入一个串:
注意是在指定位置之前,并不是在指定位置之后,当然也可以这样操作:
也可以在指定位置之前插入n个字符。
第一个位置也是支持迭代器的,写迭代器的话后面是可以传一个字符,如果是指定位置,需要传一个字符串。
注意:要谨慎使用insert,因为底层要挪动数据覆盖插入,效率不高。
4.5erase
erase的功能就是删除指定位置的字符:
erase也是支持迭代器的,如上图所示,通过erase删除了字符串的第一个字符。
当然也是支持删除指定位置之后的n个字符,后面的参数如果不传的话,默认是删除指定位置之后的所有字符:
注意:要谨慎使用erase,因为底层要挪动数据覆盖删除,效率不高。
4.6replace
replace的功能就是替换指定位置之后的n个字符:
第三个参数可以是字符,也可以是字符串,replace的应用如下所示:
上面这个例子就是把所有的空格替换成%%,replace的基本应用就是如此。
注意:要谨慎使用replace,因为底层要挪动数据覆盖,效率不高。
5.String operations
5.1c_str
这个接口的功能我用下面这个例子来演示:
我们知道文件名就是一个字符串,当我们要打开一个文件时,第一个参数时const char*这个指针,但是我们文件名是一个字符串,这时c_str的功能就体现出来了,就是返回文件对应的const char*这个指针,这样我们通过这种操作就可以打开当前的文件。
再通过fgetc就可以打印出当前文件的所有内容。
并且在windows下这个功能是不分大小写的:
即使我改成大写,照样能访问当前这个文件。
5.2find和substr
find的功能是查找某个字符并返回字符所在的下标(默认是从下标为0的位置开始查找),substr的功能是取出指定位置后的n个字符并返回一个string对象,n个字符就保存在string对象中。
这两个接口放在一起将会比较好理解,如下所示:
上面这个例子就是返回当前文件的后缀,我们通过find找到'.'这个字符,得到它的位置,再通过substr打印出后缀。
substr第二个参数不写的话,是默认取出后面的所有字符,结果和上面的是一样的。
还有一个rfind功能和find一样,不过rfind默认是从结尾开始查找的,与find相反。
两者第二个参数就是从指定位置开始查找,不写的话就是默认值。
以上就是string类(中)的内容。