基础知识回顾
输入输出流
iostream库包含两个基础类型istream和ostream,分别表示输入流和输出流,cout和输出运算符实现向流写入数据,cin和输入运算符实现从流读取数据。
注释
C++程序中的注释有单行注释(//开头)和多行注释(/* */)两种,多行注释的注释界定符不能嵌套。
数量不定的输入数据的读取
C++提供多种不同的控制流语句,如顺序语句、循环语句和条件语句,输入流结合while循环可以实现数量不定的输入数据的读取,如下:
#include<iostream>
using namespace std;
int main()
{
int sum=0,value=0;
while(cin >> value)
sum+=value;
cout << "Sum is: " << sum << endl;
return 0;
}
while循环判断的条件是istream对象是否有效,当遇到文件结束符(end-of-file,该例中是Ctrl+Z)或遇到一个无效的输入(如该例中读入的值不是要给整数)时,istream对象的状态会变为无效,处于无效状态的istream会使条件变为假。
变量
C++中的变量要先声明类型,变量类型决定了存储该变量所需要的内存空间,可以通过sizeof运算符获取存储所需的内存空间。
有符号类型的第一个位是符号位,无符号类型的所有比特都用来存储值。
类型转换
- 非布尔类型转换为布尔类型
- 布尔类型转换为非布尔类型
- 浮点类型转换为整型
- 整型转换为浮点类型
标识符
由字母、数字、下划线组成,必须以字母或下划线开头,不能以数字开头。
作用域
- 全局作用域
- 块作用域
作用域嵌套的情况
- 内层作用域:局部变量
- 内层作用域以外的外层作用域:全局变量
引用(reference)
引用为对象起了另外一个名字,引用必须被初始化,一旦初始化完成,引用将和它的初始值变量一直绑定在一起,无法重新绑定。
int ival=1024;
int &refVal=ival;
refVal是指向int类型变量ival的引用。
int (&arrRef)[10]=arr;
arrRef是指向包含10个元素的数组的引用
指针
指针可以先后指向不同的对象
指针存放指向对象的地址
解引用获得指针指向的对象的值
指向指针的指针
int ival=1024;
int *pi=&ival;
int **ppi=π
pi是指向int类型变量的指针
ppi是指向int类型指针的指针
指向指针的引用
int i=42;
int *p;
int *&r=p;
r是对指针p的引用
string对象
- 赋值:直接初始化和拷贝初始化
- empty()
- size()
- 下标访问
- 连接
- 判断相等
- 判断不相等
- 比较大小
- 处理字符串中的字符(大小写、数字等)
vector对象
可变长度的数组,每个元素的类型必须相同,可以是由向量组成的向量。
向vector中添加元素push_back
string word;
vector<string> text;
while(cin >> word)
{
text.push_back(word);
}
常用操作:
- v.empty() 是否为空
- v.size() 元素的个数
- v.push_back 向尾端添加元素
- v[n] 下标访问
- 判断相等和不相等
- 判断大小
迭代器iterator
所有标准库容器都可以使用迭代器,只有少数几种才同时支持下标访问。严格来说,string对象不属于容器类型,但string支持很多与容器类型类似的操作。
迭代器类似于指针类型,提供了对对象的间接访问,可以进行解引用操作,可以进行++和–操作,也可以+n或者-n,也可以判断是否相等。
begin成员指向第一个元素,end成员指向最后一个元素的下一位置。
auto b=v.begin(),e=v.end();
将string对象的字符变为大写
for(auto it=s.begin();it!=s.end()&&!isspace(*it);++it)
*it=toupper(*it);
C++定义了迭代器的减法运算,两个迭代器相减的结果表示它们之间的距离,C++没有定义迭代器的加法运算,所以二分搜索程序中用的是mid=beg+(end-beg)/2
而不是mid=(begin+end)/2
。
所有标准库容器的迭代器都定义了==和!=,但是它们中的大多数都没有定义<运算符。
const_iterator和常量指针差不多,只能读不能修改指向的元素。
读入一个整数并把它们存入一个vector对象,将每队相邻整数的和输出,使用迭代器实现:
#include<iostream>
#include<vector>
using namespace std;
int main()
{
int value;
vector<int> vec;
while(cin >> value)
{
vec.push_back(value);
}
for(vector<int>::iterator it=vec.begin();it!=vec.end()-1;++it)
{
cout << *it << "+" << *(it+1) << "=" << *it+*(it+1) << endl;
}
return 0;
}
数组
数组不允许拷贝赋值
复杂的数组声明:
int *ptrs[10]; //由指针组成的数组
int (*parray)[10]=&arr; //指向包含十个元素的数组的指针
int (&arrRef)[10]=arr; //指向包含是个元素的数组的引用
数组可以通过下标和指针来访问,指针也是迭代器。
函数
每个C++函数都包括一个或多个函数,其中一个必须是main函数,操作系统通过调用main来运行C++程序。
一个函数的定义包括四部分:
- 返回类型return type
- 函数名function name
- 形参列表parameter list
- 函数体function body
main函数的返回类型必须为int。
形参和函数体内部定义的变量统称为局部变量,仅在函数的作用域内可见。
要想让局部变量的生命周期贯穿函数调用及之后的时间,可以将局部变量定义成static类型。
参数的类型:
- 值作为参数
- 指针作为参数
- 引用作为参数
- const型的形参
熟悉C的程序员常常用指针类型的形参访问函数外部的对象,C++中建议使用引用类型的形参代替指针。
顺序容器
vector和array相比,前者可变大小,后者固定大小,后者不能添加或删除元素。
vector和string非常相似,后者专门用于保存字符。
vector和deque相比,后者是双端队列,后者在头尾插入/删除的速度很快,前者在尾部以外插入和删除的速度可能很慢。
list是双向链表,只支持双向顺序访问,在任何位置进行插入/删除的速度都很快。
forward_list是单向链表,只支持单向顺序访问,在任何位置进行插入/删除的速度都很快。
类型 | 访问方式 | 插入/删除速度快 |
---|---|---|
vector | 快速随机访问 | 尾部 |
array | 快速随机访问 | 不能插入和删除 |
string | 快速随机访问 | 尾部 |
deque | 快速随机访问 | 头部和尾部 |
list | 双向顺序访问 | 任何位置 |
forward_list | 前向顺序访问 | 任何位置 |
使用vector是最好的选择,除非有其他理由。
如果要求在中间插入/删除元素,选择list或forward_list。
如果要求在头尾插入/删除元素,选择deque。
- 顺序容器的构造
- 顺序容器的插入元素
- 顺序容器的删除元素
关联容器map
map是映射,从key到value的映射,字典是map的一个典型实例。
编写一个能对文章内每个字眼的出现次数加以分析的程序,可以建立一个map,带有string key和int value:
map<string,int> words;
//输入key/value最简单的方式
words["vermeer"]=1;
对于字符统计程序,可以采用以下方式
string tword;
while(cin >> tword)
words[tword]++;
其中的表达式words[tword]
会取出与tword相应的value。如果tword不在map内,它会直接被放到map内,并获得默认值0,稍后出现的increment运算符会将其值加1。
map对象的成员first对应key,second对应value,以下的for循环使用迭代器的间接访问打印所有字符串及其出现次数。
map<string,int>::iterator it=words.begin();
for(;it!=words.end();++it)
cout << "key: " << it->first
<< "value: " << it->second << endl;
关联容器set
set由一群key组成(无重复)。如果我们想知道某值是否存在于某个集合内,就可以使用set。例如在图遍历算法中,可以使set存储每个遍历过的节点,在移到下一节点前,可以先查阅set,判断该节点是否已经遍历过。在字符统计程序中,如果不想统计某些词汇的出现次数,可以设计一个用来排除字符串的set。
#include<set>
#include<string>
set<string> word_exclusion;
while(cin >> tword)
{
if(word_exclusion.count(tword))
continue;
words[tword]++;
}