# 字符串、向量和数组
#
命名空间的 using
声明
我们使用的库函数都有一个对应的命名空间,通常需要在声明或初始化变量时指定命名空间。为了简化这个操作,我们可以使用using
进行声明:
|
|
头文件中不应该包含
using
声明,这样使用了该头文件的源文件也会使用这个声明,会带来风险。
#
标准库类型 string
标准库类型 string
表示可变长的字符序列,使用 string
类型必须首先包含 string
头文件:
|
|
#
定义和初始化 string
对象
初始化 string
对象的方式:
方式 | 解释 |
---|---|
string s1 |
默认初始化,s1 是个空字符串 |
string s2(s1) |
s2 是s1 的副本 |
string s2 = s1 |
等价于s2(s1) ,s2 是s1 的副本 |
string s3("value") |
s3 是字面值“value”的副本,除了字面值最后的那个空字符外 |
string s3 = "value" |
等价于s3("value") ,s3 是字面值"value"的副本 |
string s4(n, 'c') |
把s4 初始化为由连续n 个字符c 组成的串 |
拷贝初始化(copy initialization):使用 =
将一个已有的对象拷贝到正在创建的对象。
直接初始化(direct initialization):通过括号给对象赋值。
#
string
对象的操作
string
的操作:
操作 | 解释 |
---|---|
os << s |
将s 写到输出流os 当中,返回os |
is >> s |
从is 中读取字符串赋给s ,字符串以空白分割,返回is |
getline(is, s) |
从is 中读取一行赋给s ,返回is |
s.empty() |
s 为空返回true ,否则返回false |
s.size() |
返回s 中字符的个数 |
s[n] |
返回s 中第n 个字符的引用,位置n 从0计起 |
s1+s2 |
返回s1 和s2 连接后的结果 |
s1=s2 |
用s2 的副本代替s1 中原来的字符 |
s1==s2 |
如果s1 和s2 中所含的字符完全一样,则它们相等;string 对象的相等性判断对字母的大小写敏感 |
s1!=s2 |
同上 |
< , <= , > , >= |
利用字符在字典中的顺序进行比较,且对字母的大小写敏感(对第一个不相同的位置进行比较) |
读取 string
对象:
- 使用
IO
操作符>>
读取:忽略开头的空白(空格符、换行符、制表符等),从第一个真正的字符开始读起,直到遇到下一个空白。 - 使用
getline()
函数读取:将一整行读取为string
对象,包括空白。
s.size()
返回 string::size_type
类型,是 无符号 类型的值,不能和 int
混用。
s1 + s2
使用时,必须保证至少其中一个为 string
类型。例如:string s = "hello" + "world"
错误,其 +
两边都为字符串字面值。
字符串字面值 和 string
是不同的类型。
#
处理 string
对象中的字符
C++
修改了 c
的标准库 ctype.h
为 cctype
,其中定义了一组标准函数:
函数 | 解释 |
---|---|
isalnum(c) |
当c 是字母或数字时为真 |
isalpha(c) |
当c 是字母时为真 |
iscntrl(c) |
当c 是控制字符时为真 |
isdigit(c) |
当c 是数字时为真 |
isgraph(c) |
当c 不是空格但可以打印时为真 |
islower(c) |
当c 是小写字母时为真 |
isprint(c) |
当c 是可打印字符时为真 |
ispunct(c) |
当c 是标点符号时为真 |
isspace(c) |
当c 是空白时为真(空格、横向制表符、纵向制表符、回车符、换行符、进纸符) |
isupper(c) |
当c 是大写字母时为真 |
isxdigit(c) |
当c 是十六进制数字时为真 |
tolower(c) |
当c 是大写字母,输出对应的小写字母;否则原样输出c |
toupper(c) |
当c 是小写字母,输出对应的大写字母;否则原样输出c |
遍历字符串:
|
|
str[idx]
中的 idx
为 string::size_type
类型,如果使用 int
会隐式转换为该类型。
#
标准库类型 vector
标准库类型 vector
表示对象的集合,其中给所有对象的类型都相同。因为 vector
容纳着其他对象,所以称其为 容器(container),使用 vector
必须包含其头文件:
|
|
vector
同时也是 类模板(class template),模板本身不是类或函数,但可以使用模板创建类,这个过程称为 实例化(instantiation)。
当使用模板时,需要指出编译器应把类或函数实例化成何种类型:
|
|
vector
是模板,vector<int>
是类型。
#
定义和初始化 vector
对象
初始化vector
对象的方法:
方法 | 解释 |
---|---|
vector<T> v1 |
v1 是一个空vector ,它潜在的元素是T 类型的,执行默认初始化 |
vector<T> v2(v1) |
v2 中包含有v1 所有元素的副本 |
vector<T> v2 = v1 |
等价于v2(v1) ,v2 中包含v1 所有元素的副本 |
vector<T> v3(n, val) |
v3 包含了n个重复的元素,每个元素的值都是val |
vector<T> v4(n) |
v4 包含了n个重复地执行了值初始化的对象 |
vector<T> v5{a, b, c...} |
v5 包含了初始值个数的元素,每个元素被赋予相应的初始值 |
vector<T> v5={a, b, c...} |
等价于v5{a, b, c...} |
#
vector
对象的操作:
vector
支持的操作:
操作 | 解释 |
---|---|
v.emtpy() |
如果v 不含有任何元素,返回真;否则返回假 |
v.size() |
返回v 中元素的个数 |
v.push_back(t) |
向v 的尾端添加一个值为t 的元素 |
v[n] |
返回v 中第n 个位置上元素的引用 |
v1 = v2 |
用v2 中的元素拷贝替换v1 中的元素 |
v1 = {a,b,c...} |
用列表中元素的拷贝替换v1 中的元素 |
v1 == v2 |
v1 和v2 相等当且仅当它们的元素数量相同且对应位置的元素值都相同 |
v1 != v2 |
同上 |
< ,<= ,> , >= |
以字典顺序进行比较 |
# 迭代器介绍
除了下标运算符外,迭代器(iterator) 也可以访问对象中的元素,所有标准库的容器都支持迭代器。类似于指针类型,迭代器也提供了对对象的间接访问。
# 使用迭代器
拥有迭代器的类型都具有 begin
和 end
成员,其中 begin
成员返回指向第一个元素的迭代器:
|
|
end
成员返回指向容器“尾元素的下一个位置(one past the end)”的迭代器,即 end
指向容器的 尾后(off the end) 元素。这样的迭代器通常没有意义,只是作为标记,被称为 尾后迭代器(off-the-end iterator) 或 尾迭代器(end iterator)。
若容器为空,则
begin
和end
都返回尾后迭代器。
标准容器迭代器的运算符:
运算符 | 解释 |
---|---|
*iter |
返回迭代器iter 所指向的元素的引用 |
iter->mem |
等价于(*iter).mem |
++iter |
令iter 指示容器中的下一个元素 |
--iter |
令iter 指示容器中的上一个元素 |
iter1 == iter2 |
判断两个迭代器是否相等 |
泛型编程:尽量使用
!=
来对迭代器进行判断
迭代器也拥有自己的类型:
|
|
如果容器中的值为常量,则 begin
和 end
返回 const_iterator
,否则返回 iterator
。
解引用和成员访问:解引用迭代器可以获得迭代器所指的对象,如果该对象是一个类,则可以进一步访问其成员:
|
|
# 迭代器运算
string
和 vector
的迭代器提供了额外的运算符,支持迭代器的关系运算和跨过多个元素,这些运算称为 迭代器运算(iterator arithmetic):
运算符 | 解释 |
---|---|
iter + n |
迭代器加上一个整数值仍得到一个迭代器,迭代器指示的新位置和原来相比向前移动了若干个元素。结果迭代器或者指示容器内的一个元素,或者指示容器尾元素的下一位置。 |
iter - n |
迭代器减去一个整数仍得到一个迭代器,迭代器指示的新位置比原来向后移动了若干个元素。结果迭代器或者指向容器内的一个元素,或者指示容器尾元素的下一位置。 |
iter1 += n |
迭代器加法的复合赋值语句,将iter1 加n的结果赋给iter1 |
iter1 -= n |
迭代器减法的复合赋值语句,将iter2 减n的加过赋给iter1 |
iter1 - iter2 |
两个迭代器相减的结果是它们之间的距离,也就是说,将运算符右侧的迭代器向前移动差值个元素后得到左侧的迭代器。参与运算的两个迭代器必须指向的是同一个容器中的元素或者尾元素的下一位置。 |
> 、>= 、< 、<= |
迭代器的关系运算符,如果某迭代器 |
当两个迭代器指向同一个容器时,它们可以进行加减操作得到距离,这个距离的类型为 difference_type
类型,是带符号整数型。
# 数组
数组可以看做 vector
的低配版,其 长度固定。
# 定义和初始化内置数组
数组的声明和定义形如 a[d]
,其中 a
是数组的名字,d
是数组的维度(大于 0):
|
|
字符数组具有一定特殊性,使用字符串初始化字符数组时在结尾处必须增加一个空字符:
|
|
不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值:
|
|
# 访问数组元素
数组的下标为 size_t
类型,是一种机器相关的无符号类型,它被设计得足够大以便能够表示内存中任意对象的大小。
下标存在越界导致缓冲区溢出等情况,这种情况需要程序员自行检查。
# 指针和数组
使用数组时,编译器会将其转换成指针。使用取地址符可以获取数组的元素的指针,如果是取数组的指针,则默认返回数组第一个元素的指针:
|
|
#
C
风格字符串
字符串字面值是一种通用结构的实例,这种结构是 C++
由 C
继承而来的 C
风格字符串(C-style character string) 。
按此习惯书写的字符串存放在字符数组中并以 空字符结束(null terminated)。
在
C++
程序中尽量不要使用C
风格字符串,容易引起安全漏洞且不方便。
C标准库String函数,定义在<cstring>
中:
函数 | 介绍 |
---|---|
strlen(p) |
返回p 的长度,空字符不计算在内 |
strcmp(p1, p2) |
比较p1 和p2 的相等性。如果p1==p2 ,返回0;如果p1>p2 ,返回一个正值;如果p1<p2 ,返回一个负值。 |
strcat(p1, p2) |
将p2 附加到p1 之后,返回p1 |
strcpy(p1, p2) |
将p2 拷贝给p1 ,返回p1 |
# 多维数组
严格来说,C++
语言中没有多维数组,所谓的多维数组实际是数组的数组。
|
|
#
使用范围 for
语句处理多维数组
|
|