第三章 字符串、向量和数组
3.1 命名空间的using声明: using namespace std;
3.2 标准库类型string
3.2.1 定义和初始化string对象
1)直接初始化
2)拷贝初始化
3.2.2 string对象上的操作
1)读写string对象: string对象会自动忽略开头的空白(空格符、换行符、制表符等)并从第一个真正的字符开始读起, 直到遇见下一处空白
2)读取未知数量多string对象: while(cin << word)
3)使用getline读取一整行: while(getline(cin, line))
函数从给定的输入流中读取内容(不会自动忽略开头的空白, 空白照样读取), 直到遇见换行符为止, (注意换行符也被读取进来了), 然后把所读的内容存入那个string对象中(注意不存换行符, 换行符实际上被丢弃了)
4)string的empty和size操作
empty函数: line.empty() (若line为空, 则empty函数返回0
size函数: line.size() (size函数返回值(类型为size_type(无符号))为line中字符的个数, (肯定包括空白符咯
5)比较string对象: 相等性运算符(==和!=)和关系运算符(<、<=、>、>=)
6)为string对象赋值: 直接用单等号, 产生类似c语言中strcpy的效果
7)两个string对象相加: 直接用加号, 产生类似c语言中strcat等效果
8)字面值和string对象相加, 必须确保每个加法运算符两侧的运算对象至少有一个是string(此处牵涉到连续输入输出的知识
3.2.3 处理string对象中的字符
1)#include <cctype>头文件
2)处理每个字符? for语句: for(auto c : string)
3)使用for语句改变字符串中的字符: for(auto &c : string) (因为下面涉及到函数传参, 而且要通过形参改变实参, 所以要把循环变量定义为引用形式, 这样才能直接控制那一块内存, 去改变实参
4)只处理一部分字符: 使用下标执行迭代或直接计算得到某个下标值直接访问
3.3 标准库类型vector
头文件#include <vector>
它表示对象的集合, 其中所有对象的类型都相同, 集合中的每个对象都有一个与之相应的索引, 索引用于访问对象
3.3.1 定义和初始化vector对象 : (它小尖括号里是string你老老实实用“”双引号的字符串初始化好吗?!
1)不初始化, 定义一个空vector
2)列表初始化vector对象
3)创建指定数量的元素
4)值初始化 只提供元素数量而略去初始值时, 库会创建一个值初始化的元素初值
5)列表初始化还是元素数量?
3.3.2 向vector对象中添加元素: 用v.push_back(); 而不是直接单等号赋值 (这里不能用范围for循环来向vector对象添加元素
3.3.3 其他vector操作
v.empty()
v.size()
v.push_back(t)
v[n]
v1 = v2
v1 = { a, b, c }
v1 == v2
< <= > >=
1)计算vector内对象的索引
2)不能用下标形式添加元素, 只能用push_back来添加元素, (vector对象的下标运算符可用于访问已存在的元素而不能用于添加元素
确保下标合法的一种有效手段就是尽可能使用范围for语句
3)计算vector对象内的索引
3.4 迭代器介绍
3.4.1 使用迭代器
begin成员负责返回指向第一个元素(或第一个字符(考虑string类型))的迭代器
end成员负责指向容器“尾元素的下一位置”的迭代器, 该迭代器也称为尾后迭代器
如果容器为空, 则begin和end返回的是同一个迭代器
1)迭代器运算符
*iter 返回迭代器iter所指元素的引用 (就是返回对象的引用而不是对象的值
item->mem 解引用iter并获取该元素的名为mem的成员, 等价于(*iter).mem
++iter 令iter指示容器的下一个元素
iter1 == iter2 判断两个迭代器是否相等, 如果两个迭代器指示的是同一个元素或者它们是同一个容器的尾后迭代器, 则相等
和指针类似, 试图解引用一个非法迭代器都是未定义行为
2)将迭代器从一个元素移动到另一个元素
迭代器的递增是将迭代器“向前移动一个位置”
end返回的迭代器并不实际指向某个元素, 所以不能对其进行递增或解引用的操作
3)泛型编程 for循环中使用 != 而非 < (某些情况
4)迭代器类型
5)begin和end操作符
6)结合解引用和成员访问操作
7)某些对vector对象的操作会使迭代器失效
已知限制: 1.不能在范围for循环中push_back
2.任何一种可能改变vector对象容量的操作, 比如push_back, 都会使该vector对象的迭代器失效
3.4.2迭代器运算
3.5 数组
3.5.1 定义和初始化内置数组
1)定义数组
编译时, 数组的维度应该是已知的, 即数组的维度必须是一个常量表达式
和内置类型的变量一样, 如果在函数内部定义了某种内置类型的数组, 那么默认初始化会令数组含有未定义的值
定义数组的时候必须指定数组的类型, 不允许用auto关键词
2)显式初始化数组元素
3)字符数组的特殊性 (字符串字面值的结尾处还有一个空字符
4)不允许拷贝和赋值(vector可以噢
5)理解复杂的数组声明
3.5.2 访问数组元素
1)通过范围for语句和下标来访问
2)检查下标的值
3.5.3 指针和数组
1)指针也是迭代器
2)标准库函数begin和end
虽然我们能通过计算得到尾后指针, 但这种用法极容易出错, 为了让指针的使用更简单安全, 我们可以使用库函数begin和end, (这两函数不是vector的成员函数!). 正确的使用形式是将数组作为它们的参数
int *pbeg = begin(arr);//指向arr首元素的指针
int *plend = end(arr); //指向arr尾后元素的下一位置的指针
3)指针运算
int *pbeg = arr;
int *pend = arr + sz;
指针之间也是可以比较的, 但如果两个指针分别指向不相关的对象, 则不能比较它们; 如果指向同一对象则可以用来遍历数组元素
4)解引用和指针运算的交互
理解 *(arr + 4) 与 *arr + 4 是完全不一样的
5)下标和指针
在很多情况下使用数组的名字其实用的是一个指向数组首元素的指针
注意区别: 内置的下标运算符所用的索引值并不是无符号类型(p[-2]合法), 这点与vector和string不一样
3.5.4 C风格字符串
1)C标准库string函数
2)比较字符串 用strcmp函数
如果用普通的关系运算符和相等性运算符, 那么实际上比较的是两个指向不同对象的char型指针, 会产生未定义行为
3)目标字符串的大小由调用者指定
使用strcpy和strcat时, 我们需要提供一个足够容纳结果字符串和末尾的空字符的字符数组, 这个数组的大小容易估算错误 (所以还是string类型的直接相加好诶嘿嘿
3.5.5 与旧代码的接口
1)混用string对象和C风格字符串
可以用字符数组初始化string
在c_str函数(返回类型为const char*的指针)的帮助下, string也可以用来初始化字符数组
2)使用数组初始化vector对象
vector<int> vInt(begin(arr), end(arr));//用库函数begin和end就可以, (它们的参数是数组名
vector<int> vInt(arr + 1, arr + 4);//也可以用数字的一部分来初始化vector, 此时vector里有三个元素
3.6 多维数组
1)多维数组的初始化
2)多维数组的下标引用
3)使用范围for语句处理多维数组
如何理解外层循环auto是个啥? : 尝试把二维数组理解成一维数组, 二维数组内层的一维数组理解成一维数组的元素, 那你的循环遍历的不就是元素吗? 我管你这个元素是整型元素还是数组
除了最内层的循环之外, 其他所有循环的控制变量都应该是引用类型, (防止数组的
退化成指针, 使内层循环实际要对一个指针遍历, 而这显然是非法的
4)指针和多维数组
二维数组的数组名退化成指针后是指向第一个一维数组的数组指针, 对该数组指针再解引用得到第一个一维数组, 第一个一维数组退化成指针后是指向一维数组第一个元素的整型指针, 再对该整型指针解引用之后得到一维数组第一个元素
5)类型别名简化多维数组的指针
using int_arr = int[4];//将“4个整型组成的数组”命名为int_arr;
故指向4个整型元素构成的数组的数组指针类型为 int_arr *;
术语表
begin 是string和vector的成员, 返回指向第一个元素的迭代器. 也是一个标准库函数, 参数为数组名, 返回指向该数组首元素的指针
缓冲区溢出(buffer overflow) 一种程序故障, 主要原因是试图通过一个越界的索引访问容器内容, 容器类型包括string、vector和数组等
C风格字符串 以空字符结束的字符数组
容器 是一种类型, 其对象容纳了一组给定类型的对象. vector是一种容器类型. vector是一种容器类型
拷贝初始化(copy initialization) 使用赋值号(=)的初始化形式
difference_type 由string和vector定义的一种带符号整数类型, 表示两个迭代器之间的距离
直接初始化(direct initialization) 不使用赋值号(=)初始化形式
empty 是string和vector的成员, 返回一个bool值, 当对象的大小为0时返回真, 否则返回假
end 是string和vector的成员, 返回一个尾后迭代器. 也是一个标准库函数, 参数为数组名, 返回指向该数组尾元素的下一位置的指针
getline 在string头文件中定义的一个函数, 以一个istream对象和一个string对象为输入参数. 该函数首先读取输入流的内容直到遇到换行符停止, 然后将读入的数据存入string对象, 最后返回istream对象, 换行符读入但不保留(被丢弃)
索引(index) 是下标运算符使用的值, 表示要在string对象、vector对象或者数组中访问的一个位置
迭代器(iterator) 是一种类型, 用于访问容器中的元素或者在元素之间移动
迭代器运算
以空字符结束的字符串(null-terminated)
尾后迭代器(off-the-end iterator) end函数返回的迭代器, 指向一个并不存在的元素, 该元素位于容器尾后元素的下一位置
指针运算
push_back 是vector的成员, 向vector对象的末尾添加元素
范围for语句(range for) 一种控制语句, 可以在值的一个特定集合迭代(?)
size 是string和vector的成员, 分别返回字符的数量和元素的数量, 返回值的类型是size_type
值初始化(value initialization)