C++primer第五版 字符串、向量和数组重要知识点

1. 标准库类型string

(1)string对象上的操作

string对象会自动忽略开头的空白(即空格符、换行符、制表符等)并从第一个真正的字符开始读起,直到遇见下一处空白位置。

(2)使用getline读取一整行

getline函数的参数是一个输入流和一个string对象,函数从给定的输入流中读入内容,直到遇到换行符为止(注意换行符也被读进来了),然后把所读的内容存入到那个string对象中去(注意不存换行符)。使用方法如下

string line;
getline(cin,line);

(3)string的empty和size操作

empty函数根据string对象是否为空返回一个对应的布尔值,size函数返回string对象的长度。使用方法如下

string line;
while(getline(cin,line)) //每次读入一整行,遇到空行直接跳过
	if(!line.empty())
		cout << line << endl;
string line;
while(getline(cin,line)) //每次读入一整行,输出其中超过80个字符的行
	if(!line.size() > 80)
		cout << line << endl;

(4)处理string对象中的字符

cctype头文件中的函数

isalnum(c)              当c是字母或数字时为真

isalpha(c)               当c是字母时为真

iscntrl(c)                 当c是控制字符时为真

isdigit(c)                 当c是数字时为真

isgraph(c)               当c不是空格但可以打印时

islower(c)               当c是小写字母时为真

isprint(c)                 当c是可打印字符时为真(即c是空格或c具有可视形式)

ispunct(c)               当c是标点符号时为真(即c不是控制字符、数字、字母、可打印空白中的一种)

isspace(c)              当c是空白时为真(即c是空格、横向制表符、纵向制表符、回车符、换行符、进纸符中的一种)

isupper(c)               当c是大写字母时为真

isxdigit(c)                当c是十六进制数字时为真

tolower(c)               如果c是大写字母,输出对应的小写字母,否则原样输出c

toupper(c)               如果c是小写字母,输出对应的大写字母,否则原样输出c

(5)使用基于范围的for语句

如果想对string对象中的每个字符做点什么操作,则可以使用范围for语句,这种语句遍历给定序列中的每个元素,并对序列中的每个值执行某种操作。例如

string str("some string"); //初始化
//每行输出str中的一个字符
for(auto c:str)  //对于str中的每个字符
	cout << c << endl;  //输出当前字符,后面紧跟一个换行符

以上只是输出字符,如果是想要改变string对象中字符的值,必须把循环变量定义为引用类型。例如

(顺便提一下,如果在函数中需要改变实参的值,也需要使用引用。)

string s("some string"); //初始化
//转换成大写形式
for(auto &c:s)  //对于s中的每个字符(注意,c是引用)
	c=toupper(c)  //c是一个引用,因此赋值语句将改变s中字符的值
cout << s << endl;  //输出字符串内容

特别提醒,范围for是C++11标准,我用的VC6.0不支持此种用法,还有某些较低的vs版本也不支持此种用法。不过我们可以采用下标执行随机访问。

2. 标准库类型vector

标准库类型vector表示对象的集合,其中所有对象的类型都相同,vector也常被称作容器。

要想使用vector,必须包含适当的头文件,即

#include <vector>

(1)定义和初始化vector

常用方法如下

vector<T> v1;  //v1是一个空vector,它潜在的元素是T类型的,执行默认初始化
vector<T> v2(v1);  //v2中包含v1的所有副本
vector<T> 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...}  //等价于上一行

其中T为某种数据类型。特别强调的是,要注意括号中的是初始值还是元素数量。初始化的真实含义依赖于传递初始值时用的是花括号还是圆括号。

(2)向vector对象中添加元素

当vector对象包含的元素较多时,通过列表初始化把所有元素都一一罗列出来就不合适了。此时,更好的处理方法是先创建一个空vector,然后在运行时再利用vector的成员函数push_back向其中添加元素。它负责把一个值当成vector对象的尾元素“压到(push)”vector对象的“尾端(back)”。用法如下

vector<int> v2; //创建一个空vector对象
for(int i=0;i!=100;++i)  
	v2.push_back(i);  //依次把整数值放到v2尾端
//循环结束后v2有100个元素,值从0到99

(3)其他vector操作

v.empty()    如果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相等当且仅当它们的元素数量相同且对应位置的元素值相同

<,<=,>,>=     以字典顺序进行比较

3. 迭代器

string对象的字符或vector对象的元素除了可以使用下标运算符来访问,还有另外一种更通用的机制也可以实现同样的目的,这就是迭代器。我们认定某个类型是迭代器当且仅当它支持一套操作,这套操作使得我们能访问容器的元素或者从某个元素移动到另外一个元素。

(1)迭代器类型

一般来说迭代器的精确类型我们无需知道,而实际上,那些拥有迭代器的标准库类型使用iterator和const_iterator来表示迭代器的类型,例如

vector<int>::iterator it;  //it能读写vector<int>的元素
string::iterator it2;  //it2能读写string对象中的字符
vector<int>::const_iterator it3;  //it3只能读元素,不能写元素
string::const_iterator it4;  //it4不能读字符,只能写字符

(2)使用迭代器

有迭代器的类型同时拥有返回迭代器的成员,比如,这些类型都拥有名为begin和end的成员。其中begin成员负责返回指向第一个元素(或第一个字符),end成员负责返回指向容器(或string对象)尾元素的下一位置的迭代器。例如

//由编译器决定b和e的类型
//b表示v的第一个元素,e表示v尾元素的下一位置
auto b=v.begin(), e=v.end(); //b和e类型相同

注意,在VC6.0下编译时会报错,因为auto类型符是C++11的标准,VC6.0并不支持,一般情况下我们是可以知道vector对象的数据类型,因此直接将auto替换成具体的数据类型即可。但是改完auto之后编译还是会出问题,必须将b改成 *b,如下:

int b=v.begin(); //报错
int *b=v.begin(); //正确

(3)某些对vector对象的操作会使迭代器失效

已知的一个限制是不能再范围for循环中向vector对象添加元素,另外一个限制是任何一种可能改变vector对象容量的操作,比如push_back,都会使vector对象的迭代器失效。也就是说,但凡使用了迭代器的循环体,都不要向迭代器所属的容器添加元素。

4. 数组

(1) 定义和初始化内置数组

数组的维度必须是一个常量表达式。

定义数组的时候必须指定数据类型,不允许用auto关键字由初始值的列表推断类型。

可以用字符串字面值对数组进行初始化。但是需要注意,字符串字面值的结尾处还有一个空字符,这个空字符也会像字符串的其他字符一样被拷贝到字符数组中去。例如

char a1[]={'c','+','+','\0'};  //列表初始化,含有显示的空字符
char a2[]="c++";  //自动添加表示字符串结束的空字符
const char a3[6]="Daniel";  //错误,没有空间存放末尾的空字符,数组元素应改为7

不能将数组的内容拷贝给其他数组作为初始值,也不能用数组为其他数组赋值。

(2)指针和数组

使用数组的时候,编译器一般会把它转换成指针。通常情况下,使用取地址符来获取指向某个对象的指针。

指针也是迭代器。可以获取数组尾元素之后的那个并不存在的元素的地址。例如

int array[]={0,1,2,3,4,5,6,7,8,9};
int *e=&array[10];  //指向array尾元素的下一位置的指针

但要注意,尾后指针不指向具体的元素,因此,不能对尾后指针执行解引用或递增操作。只有当指针指向了一个元素,才允许解引用该指针。

在很多情况下,使用数组的名字其实用的是一个指向数组首元素的指针。

(3)C标准string函数

以下为C风格字符串的函数

strlen(p)    返回p的长度,空字符不计算在内

strcmp(p1,p2)   比较p1和p2的相等性。如果p1==p2,返回0;如果p1>p2,返回一个正值;否则返回一个负值

strcat(p1,p2)    将p2附加到p1之后,返回p1

strcpy(p1,p2)   将p2拷贝给p1,返回p1

(4)多维数组

初始化如下

int ia[3][4]={{0,1,2,3},{4,5,6,7},{8,9,10,11}};
//大小为3的数组,每个元素是含有4个整数的数组

要使用范围for语句处理多维数组,除了最内层的循环外,其他所有循环的控制变量都应该是引用类型。

当程序使用多维数组的名字时,会自动将其转换成指向数组首元素的指针。

猜你喜欢

转载自blog.csdn.net/elma_tww/article/details/82152252