C++ STL:string类(1) |了解string|编码|常用接口|迭代器|算法查找|auto|范围for
上篇文章:
https://blog.csdn.net/2401_86123468/article/details/153867060?spm=1001.2014.3001.5501
此章节之后,就要学会看文档,有关C++的网址推荐:
非官方,但排版清晰易于查询:https://legacy.cplusplus.com/reference/
官方:https://en.cppreference.com/index.html
1.了解string类
1.1C语言中的字符串
C语言中,字符串是以'\0'结尾的一些字符的集合,为了操作方便,C标准库中提供了一些str系列的库函数,但这些库函数与字符串是分离开的,不符合OOP的思想,而且底层空间需要用户自己管理,并且有越界访问的风险,整体而言并不太方便。
1.2 使用场景
在OJ中,有关字符串的题目基本以string类的形式出现,而且在常规工作中,为了简单、方便、快捷、基本都使用string类,很少有人去使用C库中的字符串操作函数。
2.标准库中的string类
2.1string类
注意:虽然我们称string为容器,但在容器列表中,并没有string。
原因是:string类出现的要比STL早。

要想查看string类,就需要在此处:

string实现出一个basic_string的类模板:


而我们常说的string实际是被typedef出来的,string是basic_string的char。
在basic_string中,模板实例化出以下四种:

其中,string中一个字符占一个字节,使用UTF-8存储:

wstring(指宽字节),一个字符占两个字节(不同平台下,也可能是4个字节):

u16string中一个字符占两个字节,使用UTF-16存储:

u32string中一个字符占4个字节,使用UTF-32存储:

2.2编码
上述的内容,涉及到有关编码的内容,编码是值和符号的映射关联集合,之前我们接触到的编码就是ASCII。



而上述的编码只适用于欧美国家的使用,而全球统一的编码是通过Unicode表示。

在Unicode中,含有三个主要的编码集:UTF-8(以一个字节为单位)、UTF-16(以两个字节为单位)、UTF-32(以四个字节为单位)。
其中,UTF-8是接触最多的,也称之为变长编码

2.2.1gbk
我国设计的编码标准,通过两个字节表示一个汉字,同样也兼容ASCII,windows汉化全部都使用gbk标准。

如下,两个汉字和一个\0,占5个字节。

3.string常用接口说明
https://legacy.cplusplus.com/reference/string/string/
首先明确,string是basic_string的类模板,string是typedef出来的。
需要包含的头文件:

3.1string类对象的常见构造


根据第三点,显示出的npos,是指string定义的一个const静态成员变量。


析构

赋值

3.2string类对象的访问

3.2.1operator[ ]

支持普通对象和const对象

可以实现修改,也可以插入

底层逻辑实现

上述代码,通过&返回,可以修改返回对象,如果用指针,还需要解引用。

另外·,有在之前的文章讲过,C语言普通数组的越界检查是一种抽查,但在此时,得到了解决,C++转换为函数调用,包含assert断言。

3.2.2at

at的作用和operator[ ]作用相似,只不过它会抛异常。


3.3string类对象的容量操作及遍历操作
3.3.1size length


这里的size和length的结果都相同,那为什么相同的作用会有两种表达方式呢?
原因是早期设计string时就是以length设计,直到将STL引入,对于接口有相似功能的都会设计同一个名字,所以添加了size并且我们推荐size。
因为length是对于string比较合适,但对于更宽泛的就不太合适了,比如之后的二叉树,定义一个叫length的接口倒是没有size合适。

4.迭代器
4.1正向迭代器
迭代本身就是用来遍历的,在string这个类域中,有一个iterator的类型。

在一个类域里面含有另一个类型,会有两种情况:内部类或者在内部typedef定义出来的。
而iterator就是typedef定义出来的。
我们可以在iterator中定义对象:
![]()
此种行为类似于指针,那么在iterator中,又定义出begin和end:

begin是开始的位置,end是最后一个字符的下一个位置

示例:

注意:迭代器不等价于指针,只是行为像指针。
上述代码所显示的作用,迭代器产生的效果与下标+[ ] 是相同的,但是对于STL所有容器,迭代器是通用的,对于往后的vector,链表等,迭代器更适合。
链表实现简单举例:

4.2常量迭代器
迭代器有普通迭代器(iterator)和常量迭代器(const_iterator)的区分。


4.3反向迭代器



迭代器中,剩余的是由C++11新增,作用与const修饰的一样,只不过是为了规范新增,日常更多的还是使用C++98的形式

总结:
迭代器提供统一的方式遍历修改容器
算法可以泛型化,算法借助迭代器处理容器的数据。
5.算法示例
需包含头文件:#include<algorithm>
5.1查找

在数组中查找和在链表中查找,将迭代器写成模板,通过容器的迭代器区间,找到返回first,没有找到返回last。

6.auto关键字
在早期C/C++中auto的含义是:使用auto修饰的变量,是具有自动存储器的局部变量,后来这个
不重要了。C++11中,标准委员会变废为宝赋予了auto全新的含义即:auto不再是一个存储类型
指示符,而是作为一个新的类型指示符来指示编译器,auto声明的变量必须由编译器在编译时期
推导而得。
用auto声明指针类型时,用auto和auto*没有任何区别,但用auto声明引用类型时则必须加&
当在同一行声明多个变量时,这些变量必须是相同的类型,否则编译器将会报错,因为编译器实际只对第一个类型进行推导,然后用推导出来的类型定义其他变量。
auto不能作为函数的参数,可以做返回值,但是建议谨慎使用
auto不能直接用来声明数组
注意:auto会导致代码的可读性降低。



7.范围for
对于一个有范围的集合而言,由程序员来说明循环的范围是多余的,有时候还会容易犯错误。因此
C++11中引入了基于范围的for循环。for循环后的括号由冒号”:"分为两部分:第一部分是范围
内用于选代的变量,第二部分则表示被迭代的范围,自动迭代,自动取数据,自动判断结束。
范围for可以作用到数组和容器对象上进行遍历
范围for的底层很简单,容器遍历实际就是替换为迭代器,这个从汇编层也可以看到。

注意:如果要修改范围for,需要加&

如果对象比较大,并且不想让它产生拷贝,那在使用&后,尽量在前方加上const

另外,支持迭代器的容器,都可以用范围for,数组也支持(特殊处理)

范围for的底层:

本章完。
