3. 字符串、向量和数组
目录
3. 字符串、向量和数组
3.1 命名空间的using声明
3.2 标准库类型string
3.2.1 定义和初始化string对象
3.2.2 string对象上的操作
cin/cout, getline, s.empty(), s.size(), s[], s1+s2, s1 = s2, ==/!=/<=/>/>=
3.2.3 处理string对象中的字符
isalnum(), isalpha(), isdigit(), islower(), isupper(), tolower(), toupper()
3.3 标准库类型vector
3.3.1 定义和初始化vector对象
3.3.2 向vector对象中添加元素 push_back
3.3.3 其它vector操作
v.empty(), v.size(), v.push_back(), ==/!=/<=/>/>=
3.4 迭代器介绍
v.begin(), v.end()
3.4.1 使用迭代器
*item, item->mem, ++item, --item, ==/!=
3.4.2 迭代器运算
+/-/+=/-=, >=/>/<=/<
3.5 数组
3.5.1 定义和初始化内置数组
3.5.2 访问数组元素
3.5.3 指针和数组
3.5.4 C风格字符串(最好不要使用)
3.5.5 与旧代码的接口
3.6 多维数组
3.1 命名空间的using声明
using namespce std;
// 之后可以自由使用cin,cout,endl......
using std::cin; using std::cout; using std::endl;
// std中cin,cout,endl不需要声明其它内容依旧需要声明
3.2 标准库类型string
可变长的字符序列,使用前需要包含string头文件:
3.2.1 定义和初始化string对象
直接初始化:不通过等号(=)初始化一个变量
拷贝初始化:通过等号(=)初始化一个变量,编译器把等号右侧的初始值拷贝到新创建的对象中
3.2.2 string对象上的操作
读写string对象:
1. cin>>/cout<<:读取操作时,string会自动忽略开头的空白,直到遇到下一处空白为止
2. 读取未知数量的string对象时可以使用while循环:
3. getline读取一整行:参数为一个输入流和一个string对象,从输入流读取直到换行符为止(换行符也被读取),然后把读取的内容存到string对象中(不存储换行符),最后返回流参数:
string的empty和size操作:
empty函数根据string对象是否为空返回一个布尔值:
size函数返回string对象的长度(string对象中字符的个数):
size函数返回的是一个string::size_type类型的值,该值是一个无符号类型的值并且能够存放下任何string对象的大小。
比较string大小:
==/!=:判断两个string对象是否相等(长度相同而且包含的字符也相同)
<=/>/>=:判断大小,依照大小写敏感的字典顺序进行判断:
- 如果两个string对象长度不同,较短string对象每个字符与较长string对象对应位置字符相同,则较短string对象<较长string对象;
- 如果两个string对象在某些对应的位置上不一致,则string对象比较的结果是string对象中第一对相异字符比较的结果。
为string对象赋值:允许将一个对象的值赋给另外一个对象(str1 = str2;)
两个string对象相加:连接两个string对象得到一个新的string对象
字面值和string对象相加:
3.2.3 处理string对象中的字符
处理string对象中每个字符可以使用范围for语句:
1. 输出str中的每个字符
auto c定义变量c用于访问对象str中的元素
2. 统计str中标点符号的数量
3. 改变字符串中的字符 (小写改为大写)
想要改变string对象中字符的值,需要把循环变量定义为引用类型
4. 处理一部分字符(下标、迭代器)
下标运算符([ ])接收的输入参数是string::size_type类型的值,表示要访问的字符位置,返回值是该位置上字符的引用。string对象的下标从0记起,s[0]是第1个字符,s[1]是第2个字符,s[s.size()-1]是最后一个字符。
把第一个字符改成大写(输出“Some string”)
把第一个单词改成大写(输出“SOME string”)
3.3 标准库类型vector
用于表示某种类型对象的集合,vector中所有对象的类型都相同。vector又被称为容器,使用前需要包含头文件:
vector是C++中的一个类模板class template(除了类模板还有函数模板),模板本身不是类或者函数,可以看作编译器生成类或函数需要的一份说明,编译器根据模板创建类或函数的过程称为实例化。对于类模板需要提供额外信息指定模板实例化成什么样的类:
使用时一般先定义一个空的vector对象,在运行时向其中添加具体值。
3.3.1 定义和初始化vector对象
拷贝初始化:使用=的初始化
列表初始化:使用{}括起来的初始元素被赋值给vector对象
- 使用拷贝初始化时,只能提供一个初始值;
- 如果提供的是一个类内初始值,则只能使用拷贝初始化或使用列表初始化;
- 如果提供的是初始元素值的列表,只能使用列表初始化(只能用花括号不能用圆括号)
3.3.2 向vector对象中添加元素 push_back
但是不能在范围for循环中向vector对象添加元素。
3.3.3 其它vector操作
第一个循环把控制变量i定义成引用类型,这样可以通过i改变v中每个元素的值;
另外要注意只能对确知已存在的元素执行下标操作。
3.4 迭代器介绍
- 除了通过下标访问string对象或者vector对象的元素,还可以通过迭代器;
- 除了vector之外的其它标准库定义的容器也都可以使用迭代器,但是只有少数几种才支持下标;
- string对象不属于容器类型(虽然支持很多与容器类型类似的操作),也支持使用迭代器;
- 迭代器的对象是容器中的元素(或string中的字符),可以通过迭代器访问某个元素,也可以从一个元素移动到另一个元素;
- 有效的迭代器指向某个元素(或者容器中尾元素的下一位置),其他情况属于无效的迭代器。
3.4.1 使用迭代器
1. 可以通过(s.begin()!=s.end())检查s是否为空
2. 通过++it将迭代器移动到下一个元素(*it的意思是解引用,先解引用it,然后将结果传入toupper函数得到该字母对应大写形式,再把这个大写字母重新赋值给it所只是的字符)
3. 泛型编程(这种编程风格在标准库提供的所有容器上都有效):
- 在for循环的判断中使用!=而不使用<;
- 使用迭代器而不是用下标;
4. 迭代器类型:就像不知道string和vector的size_type成员是什么类型一样,一般也不知道迭代器的精确类型,可以使用iterator(读写)和const_iterator(只读)表示迭代器类型。
5. begin和end返回的类型由对象是否为常量决定,如果对象是常量(const vector
6. 解引用(*)迭代器可以获得迭代器所指的对象,当其对象为类的时候,可以进一步访问它的成员。C++定义了箭头运算符,把解引用和成员访问两个操作结合在一起,it->mem和(*it).mem表达相同的意思。(对于字符串向量也可以用it->empty()表达(*it).empty())
7. 任何可能改变vector对象容量的操作(比如push_back)都会使该vector对象的迭代器失效。
3.4.2 迭代器运算
1. 计算vector对象中间位置元素
2. 使用迭代器二分搜索
mid所指的元素可以通过*mid得到。
3.5 数组
数组是一种类似于标准库类型vector的数据结构:
- 相同点:都是存放类型相同的对象的容器,这些对象本身没有名字需要通过所在位置访问;
- 不同点:数组的大小确定不变,不能随意向数组中增加元素。
3.5.1 定义和初始化内置数组
数组的声明形如a[d],a是数组的名字,d是数组的维度,维度说明了数组中元素的个数,编译的时候维度应该是已知的(维度必须是一个常量表达式)。
1. 定义数组的时候必须指定数组的类型,不能使用auto关键字,和vector一样数组的元素应为对象,不存在引用的vector也不存在引用的数组。
2. 显示初始化数组元素:对数组进行列表初始化时可以忽略数组的维度,如果指明了维度,初始值的总数量不应超过维度大小。
3. 字符数组:可以通过字符串字面值对字符数组初始化,注意字符串字面值结尾处还有一个空字符,空字符也会被拷贝到字符数组。
4. 不允许拷贝和赋值:不能将数组的内容拷贝/赋值给其他数组。
5. 存放指针的数组的声明
3.5.2 访问数组元素
可使用范围for语句以及下标访问数组元素
3.5.3 指针和数组
使用数组的时候编译器一般会转换成指针,在用到数组名字的地方,编译器会自动将其替换为一个指向数组首元素的指针:
当使用数组作为auto的初始值时,得到的类型是指针而不是数组:
也可以使用指针作为迭代器,遍历数组中的元素
或者使用begin和end函数获得数组首个/尾后指针
指向数组元素的指针同样可以执行迭代器运算:
解引用指针即可获得指针指向的值:
3.5.4 C风格字符串(最好不要使用)
包含在cstring头文件中,传入此类函数的指针必须指向以空字符作为结束的数组:
3.5.5 与旧代码的接口
- 字符数组可以替代字符串字面值;
- string对象不能直接初始化指向字符的指针;
- 可以使用数组初始化vector对象
但是尽量不使用数组,使用标准库类型。
3.6 多维数组
多维数组是数组的数组,一个维度表示数组本身大小,另外一个维度表示其元素大小。
1. 多维数组的初始化:
2. 多维数组的下标引用:
row是一个含有4个整数的数组的引用,将其绑定到ia的第二行。
3. 使用范围for语句处理多维数组:
将循环的控制变量声明成引用类型可以避免数组被自动转成指针 (使用范围for语句处理多维数组时,除了最内层的循环意外,其它所有循环的控制变量都应该是引用类型)
4. 指针和多维数组:
程序使用多维数组的名字时也会将其自动转换成指向数组首元素的指针,多维数组实际上是数组中的数组,所以多维数组名表示的指针是指向第一个内层数组的指针。
- 外层循环:p指针指向ia第一个内层数组,依次迭代直到ia的全部3行处理完;
- 内层循环:q指针指向p当前所在行的第一个元素(*p是一个含有4个整数的数组)
或者使用begin和end标准库函数:
5. 类型别名简化多维数组的指针:通过设定类型别名简化声明多维数组的流程



