一、string
1. 初始化string对象的方式
string s1; //默认空串
string s2(s1); //s2是s1的副本
srting s3 = s1; //等价于s2(s1)(拷贝初始化)
string s4 = "value" //是字面值"value"的副本
string s5("value") //同上(直接初始化)
string s6(n, 'c') //把s4初始化为由n个连续字符c组成的串(直接初始化)
使用等号是拷贝初始化,不使用等号是直接初始化。
2. 操作
os<<s //将s写到输出流os中,返回os
is>>s //从is中读取字符串赋给s,字符串以空白分隔,返回is
getline(is,s) //从is中读取一行赋给s,返回is
s.empty() //s为空返回true,否则返回false ,返回bool类型
s.size() //返回s中字符的个数
s[n] //返回s中第n个字符的引用,位置n从0计起
s1+s2 //返回s1和s2连接后的结果
s1 = s2 //用s2中的副本替代s1中原来的字符
s1 == s2 //判s1和s2等不等
s1!=s2 //对大小写敏感
<, <=, >, >= //利用字符在字典中的顺序进行比较
3. 读写string对象
读入时遇见空白字符则停止读入,开头的空白忽略不计。
getline会读入一整行,不算空白。触发getline的换行符最后被丢弃了,最后得到的string类型不含换行符。
4. string::size_type
其实size_type是size()函数的返回类型,它是一个无符号类型的值,而且能够存放下任何string对象的大小。
C++11新标准中,允许编译器通过auto或decltype来推断变量的类型。故可以靠此来对size_type进行一个定义。
5. 字面值和string对象相加
必须确保每个加法运算符(+)的两侧的运算对象至少有一个是string。
string s1 = "hello";
string s = s1 + "world"; //正确
string s = "hello" + "world"; //错误
字符串字面值和string是不同的类型。
6. cctype头文件中的函数(注意这里的 c 是字符)
isalnum(c) //c全为数字或数字式时为真
isalpha(c) //c全为字母时为真
iscntrl(c) //c是控制字符时为真
isdigit(c) //当c是数字时为真
isgragh(c) //当c不是空格但可打印时为真
islower(c) //当c不是小写字母时为真
isprint(c) //当c是可打印字符时为真
ispunct(c) //当c是标点符号时为真
isspace(c) //当c是空白时为真
isupper(c) //当c为大写字母时为真
isxdigit(c) //当c是十六进制数字时为真
tolower(c) //c输出对应的小写字母
toupper(c) //输出对应的大写字母
7. 基于范围内的for语句
遍历给定序列中的每个元素并对序列中的每个值执行某种操作。
for (declaration:expression)
statement
每次迭代,declaration部分的变量会被初始化为expression部分的下一元素值。
8. 处理部分字符
a)使用下标(使用下标之前最好要判是否空,否则会有严重后果。无论何时都注意检查合法性)
b)使用迭代器
二、头文件格式
C++中兼容了C的标准库,C中这些标准库的形式为name.h,C++中将这些文件命名为cname。
原因:
1. 更符合C++的命名要求。
2. 在名为cname的头文件中定义的名字从属于命名空间std,而定义在名为.h的头文件则不是。
3. 可以很明白地记住什么是从C中继承过来的。
三、标准库类型vector
1. 特点
标准库类型vector表示对象的集合,其中所有对象的类型都相同。集合中的每个对象都有一个与之对应的索引,索引用于访问对象。vector能容纳绝大多数类型的对象作为其元素,但是因为引用不是对象,所以不存在包含引用的vector。(如果不确定元素的确切个数,使用vector而不使用数组)
2. 实例化
编译器根据模板创建类或函数的过程称为实例化。
当使用模板时,需要指出编译器应把类或函数实例化成何种类型。
3. 初始化vector对象
vector<T> v1; //空vector,执行默认初始化
vector<T> v2 = v1; //v2中包含v1所有元素的副本
vector<T> v2(v1); //与上等价
vector<T> v3(n, value); //包含n个元素,每个元素的值都是value
vector<T> v4(n); //包含n个元素
vector<T> v5{a,b,c,d…}; //包含列表中初始值的个数,并且每个元素被赋予相应的初始值
vector<T> v5 = {a,b,c,d…}; //与上等价
使用圆括号,可以说提供的值是用来构造vector对象的;
使用花括号,表述成我们想列表初始化该vector对象。
4. vector的一些常用操作
vector<T> v;
T t;
v.push_back(t); //将t插入到v的尾端
v.empty(); //判空
v.size(); //返回v中元素的个数
v[n]; //返回v中第n个元素的引用
v1 = v2; //用v2中的元素拷贝替换v1中的元素
v1 = {a,b,c,d…}; //用列表中的元素拷贝替换v1中的元素
v1 == v2; //判等
v1 != v2; //判不等
<,<=,>,>= //按照字典顺序比较
5. 注意
vector不能用下标形式添加元素,只可用下标访问已存在的元素。
确保下标合法的一种有效手段就是尽可能使用范围for语句。
四、迭代器
1. 所有标准库容器都可以使用迭代器。
2. 迭代器支持的运算符
*iter //返回迭代器所指元素的引用
iter->mem //解引用iter并获取该元素的名为mem的成员,等价于*iter.mem
++iter //令iter指示容器中的下一个元素
--iter //令iter指示容器中的上一个元素
iter1 == iter2 //判等
iter1 != iter2 //判不等
迭代器运算
iter + n
iter - n
iter += n
iter -= n
iter1 - iter2 //两迭代器之间的距离,注意是没有加法运算的迭代器之间。
>, >=, <, <= //实质是比较两迭代器间的位置
3. 迭代器的类型
vector<int>::iterator it1; //知道类型的定义方式、可读写
string::iterator it2;
vector<int>::const_iterator it3;
string::const_iterator it4; //只读
4. begin和end
begin:返回指向的第一个元素的迭代器。
end:返回容器“尾元素的下一个元素”的迭代器。
如果容器为空,则begin和end返回的是同一个迭代器,都是尾后迭代器。
begin的具体返回类型由对象是否是常量决定,如果对象是常量,begin和end返回const_iterator;如果不是常量,返回iterator。(选用auto自行决定返回类型比较保险)
5. 迭代器的限制
某些对容器的操作会导致迭代器失效。(即任何一种可能改变vector对象容量的操作)
使用了迭代器的循环体,都不能向迭代器所属的容器添加元素。
五、数组
1. 数组的大小固定(使用下标访问时必须严格检查是否在合理范围内)
以下是数组练习题,可知,维度必须是一个常量表达式!
unsigned buf_size = 1024;
int ia[buf_size]; // 不合法, 维度必须是一个常量表达式,这里buf_size是一个变量
int ia[4 * 7 - 14]; // 合法
int ia[txt_size()]; // 不合法, 维度必须是一个常量表达式,txt_size()函数返回的也是一个变量
char st[11] = "fundamental"; // 不合法, 这个字符串的大小是12
2. 字符数组的特殊性:可以使用字符串字面值进行初始化,但是结尾处有一处空字符。
char a1[] = {'C', '+', '+'}; //无空字符
char a2[] = "C++" //结尾默认生成空字符'\0',(为了容纳空字符,故如果规定大小的话,大小必须为4以上)
3. 不允许拷贝和赋值
不能将数组的内容拷贝给其他数组作为其初始值,也不能用数组为其他数组赋值。
//错误示范
int a[] = {o,1,2}; //正确
int b[] = a; //错误
a2 = a; //错误
4. 数组的指针与引用(**多理解)
int *ptrs[10]; //ptrs是含有10个整型指针的数组
int &refs[10] = ...; //错误:不存在引用的数组
int (*Parray)[10] = &arr; //Parray指向一个含有十个整数的数组
int (&arrRef)[10] = arr; //arrRef引用一个含有10个整数的数组
理解时,就数组而言,由内向外阅读>从右向左阅读,更好理解一点。从数组的名字开始按照由内向外的顺序阅读。
5. 相比于vector来说,数组的缺点
- 不能向数组增加元素,数组大小固定,不灵活。
- vector可以更好地支持标准库std。
6. 指针+数组
string nums[] = {"one", "two", "three"};
string *p = &nums[0]; //p指向nums的第一个元素
string *p2 = nums; //等价如上
int ia = {0,1,2,3,4};
auto ia2(ia); //ia2是一个整型指针,指向ia的第一个元素
auto ia2(&ia[0]) //等价如上
指针也是迭代器
允许使用递增运算符将指向数组元素的指针向前移动到下一个位置上
int arr[] = {0,1,2,3,4,5,6};
int *p = arr; //p指向arr[0]
++p; //p指向arr[1]
可以得到数组尾元素之后的并不存在的元素的地址,之后作用类似于尾后迭代器
int *e = &arr[10]; //arr是大小为10的数组
标准库函数begin和end
int ia[] = {0,1,2,3};
int *beg = begin(ia); //首元素指针
int *en = end(ia); //尾后指针
注意尾后指针不能进行解引用和递增操作。
7. 指针的运算(与迭代器一样的)
p + n
p - n
p += n
p -= n
p1 - p2 //两指针之间的距离,注意是没有加法运算的指针之间。
>, >=, <, <= //实质是比较两指针间的位置
*p //返回指针所指元素的引用
p->mem //解引用p并获取该元素的名为mem的成员,等价于*p.mem
++p //令p指示数组中的下一个元素
--p //令p指示数组中的上一个元素
p1 == p2 //判等
p1 != p2 //判不等
只要指针指的是数组中的元素,都可以进行下标运算。
int *p = &ia[2]; //p指向索引为2的元素
int j = p[1]; //p[1]等价于*(p+1), 即ia(3)
int k = p[-2]; //p[-2]是ia[0]表示的那个元素
六、C风格字符串
1. C标准库Sring函数
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
//不负责验证字符串参数
七、多维数组
1. 初始化
int ia[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
int ia[3][4] = {{0,1,2,3},{4,5,6,7},{8,9,10,11}};
int ia[3][4] = {{0},{4},{8}}; //显式地初始化每行的第一个元素
int ia[3][4] = {0,3,6,9}; //显式地初始化第1行,其他元素执行值初始化
2. 使用范围for语句处理多维数组
除了最内层的循环外,其他所有循环的控制变量都应该是引用类型。
3. 指针和多维数组
int ia[3][4]; //大小为3的数组,每个元素是含有四个整数的数组
int (*p)[4] = ia; //p指向含有4个整数的数组
p = &ia[2]; //p指向ia的尾元素
int *ip[4]; //整型指针的数组
int (*ip)[4]; //指向含有四个整数的数组
以上,这个区别总是有点没搞懂。再多理解。