string可变长字符序列
初始化:
- 默认初始化,得到空字符串
- ()直接初始化,调用构造函数,当要初始化多个值,
- (n,'c')连续n个c字符组成的字符串
- =拷贝初始化,调用拷贝构造函数,只能提供一个初始值
基本API:
IO操作:
- cin<<a忽略开头空白(\0,\n,\t),直到下一处空白位置,读取一个字符串
- cin<<a<<b读取两个字符串
- while(cin<<a){}读取若干次的字符串,直到流无效
- getline(cin,a)读取字符串,保留空白,直到遇到换行符\n,也就是读取一整行
- while(getline(cin,a))循环读取每行
size():返回size_type类型,是一个无符号整形数
==,!=:对大小写敏感,两个运算对象包含字符完全一致
>,<,>=,<=:对大小写敏感
- 当一个为另一个前缀,较短的小于较长的
- 当逐字符比较出现相异字符,比较ASCII码,较小的值小于较大的
+:两侧运算对象至少有一个为string,不能将两个形如"a" + "b"的字面值加在一起
cctype头文件,字符处理
获取string的每个字符:[size_type]下标访问,返回第size_type索引的字符引用
vector可变长序列
vector是用于存放相同类型对象的容器,是一个类模板,因此实例化模板也要遵守规则,vector<type> name;
初始化:
- 默认初始化,得到空vector
- vector<T> v(n,val)n个重复元素,每个都是val
- vector<T> v(n)n个重复元素,每个元素执行值初始化
- 列表初始化:vector<T> v {a,b,c,......}每个元素赋予对应的值
- **注意:**类内初始化,仅允许使用=或{}形式,不允许()直接初始化
基本API:
v.push_back(t)向v尾端添加一个元素t
其余api和string没有太大差异,比如==,比较的也是两个vector中对应的元素,但要注意,如果元素类型为自定义类类型,且类中没有包含operator == () ,则无法对元素比较
由下标访问后获取的元素,可以支持的运算符或api仅由自身类型决定
默认初始化 vs 值初始化
| | |
|----------------|-------------------|------------------|
| 定义 | 变量被声明但没有被显式初始化时 | 使用花括号{}
进行初始化 |
| 基本数据类型局部变量 | 值是未定义的(随机值) | 初始化为类型的默认值(如0) |
| 全局变量/静态变量 | 编译器赋予默认值(如int为0) | 同样被赋予默认值(如int为0) |
| 类类型变量 | 调用默认构造函数(如果存在) | 同样调用默认构造函数(如果存在) |
| 特殊行为 | 无特定初始化行为(局部变量未定义) | 聚合类型可能有不同行为 |
其他
isspace()是否是空白字符
toupper()改为大写形式
size_t类型,是与
iterator迭代器
只有少数的几种标准库容器才支持下标[]访问,但是所有的标准库容器都可以使用迭代器
迭代器类似于指针,但又和指针不同
迭代器类型:支持迭代器的标准库中,例如vector<type>::iterator或vector<type>::const_iterator类似于对常量指针,不能修改所指向元素的值
如果容器时const,则通过begin()或end()运算符返回的是const_iterator类型的迭代器
迭代器运算符:
获取迭代器:
begin():返回指向第一个元素的迭代器
end():返回指向尾元素下一位的迭代器,这种迭代器又叫尾后迭代器
cbegin():无论容器是否为常量都返回const_iterator
cend():同上
*解引用:获取指向的元素的引用
++,- -:移动到下一个或上一个元素
注意访问元素的成员时:(*it).empty(),迭代器需要加上括号
注意:t->箭头运算符 等价于(*t).这种两部操作形式
迭代器算数运算:
it + n或it - n:移动n个位置,仍然返回迭代器
关系运算符,比较两个迭代器的前后位置
it1 - it2:结果是两个迭代器的距离,
数组
也是用于存放相同类型对象的容器,但与vector不同的是,它的大小固定,不能向数组添加元素,这样的性质对运行时的性能较好,但是缺乏灵活性
基本操作
定义数组:type arr[n]; arr是一个含有n个类型为type元素的数组,注意不允许用auto自动推断
初始化:使用列表初始化
- 此时允许忽略数组的维度n([]空的形式)
- 但是如果指明了维度,那么元素总数量不应该超出指定维度
- 如果初始列表元素少于维度的元素,则仅通过列表初始化相应的元素,其余默认初始化
对于char类型的数组,有两种初始化的形式,一种如上列表初始化,每个元素为字符,另一种通过字符串字面值"......",这种形式会自动在结尾添加空字符串,所以要注意不能超过维度
注意:数组不允许拷贝和赋值
访问数组元素:通过下标访问,下标的类型可以为size_t类型,
**注意:**访问时要注意下标越界问题和访问非法内存问题
数组元素指针
大部分情况下,使用数组名时,会被替换为指向数组首元素的指针
对于一个指向数组元素指针,迭代器支持的操作,它全都支持,但要注意两个指针需要在同一个对象中才能进行关系运算
不过如果想作为首元素指针需要type* p = arr(替换为指向数组首元素的指针);作为尾后指针需要type* p = arr[n](索引范围为0----n-1)
但是为了放置出错,引入了标准库函数begin(arr)和end(arr)(并非容器类的成员,数组不是类)
我们说使用数组名时,会被替换为指向数组首元素的指针,因此
cpp
int* p = arr[2];->等价于 int *x = arr; p = *(x + 2);
只要指针指向的时数组中的元素,都可以执行下标运算,因此
cpp
int j = p[1]; ->等价于 *(p+1)
多维数组
数组的数组,阅读方式依旧遵守:由内而外,从右到左
int arr[m][n][j]需要从内到外阅读,arr是大小为m的数组,每个元素都是为n的数组,这些数组的元素又都是含有j个int类型的数组
初始化:{}内部嵌套{},但是内层是非必须的
访问方式:每个维度对于下标运算符[],如果[]的数量<维度,则返回数组,而非元素
当使用for处理每个元素时,注意使用&,为了避免数组自动转换为指针
C风格字符串和数组
C风格字符串即字符串字面值,存放在char类型的数组中,并以\0结尾,一般用指针操作
对C风格字符串,也就是\0结尾的数组,基本操作(注意和string操作方式有较大差异):
- strlen(p):返回从
p
指向的地址开始,直到遇到第一个空字符(\0
)之前的字符数(不包括该空字符) - strcmp(p,p1)比较这两个指针所指向的以空字符(
\0
)结尾的字符串在字典序上是否相等,如果相等返回0,如果返回正数,前面的较大,否则后面较大 - strcat(p,p1)连接操作将p1附加到p后,返回p
- strcpy(p,p1)将p1拷贝给p,返回p
注意:
如果上述传入的非\0结尾,将产生未定义
如果不使用strcmp进行比较,从而比较这两个指针,而非字符串,即比较的是指针的地址,如果两个指针指向的不是同一个C风格字符串,将产生未定义
对于想要使用strcat或者strcpy,必须提供结果数组,该数组必须足够大,容纳下所有字符包括、0,因此很容易出错
通常情况会使用string而非C风格字符串
C风格字符串和string
允许C风格字符串初始化string,允许+其中一个为C风格字符串,允许+=右侧为C风格字符串,相反的这些操作都不成立
s.c_str()将string转为C风格字符串,函数返回const char *类型的指针
数组和vector
可以用数组初始化vector,vector<type> v (begin(arr), end(arr)),包含比arr多一个的元素,因为是尾后指针