5.1. 简单语句
5.2. 语句作用域
5.3. 条件语句(if语句, switch语句 )
5.4. 迭代语句(for语句,while语句,do while语句)
5.5. 跳转语句(break语句,continue语句,goto语句)
5.6. try语句块和一场处理(throw表达式,try语句块,异常类)
5.1 简单语句
(1)表达式语句:表达式后加上分号,令表达式执行求值过程。
(2)空语句:程序中某个地方,语法上需要一条语句但逻辑上不需要时使用空语句。(使用空语句时最好加上注释,增加代码可读性)
(3)注意分号的书写,某些非法分号可能被当作空语句改变程序的逻辑。
(4)复合语句即称为块,由花括号括起来的语句和声明序列(可能为空),在块中引入的名字仅在块内以及嵌套在块中的子块里有效。
5.2语句作用域
定义在控制结构中的变量只在相应语句的内部可见,语句结束,变量失效。
5.3条件语句
1. if 语句
if(condition)
statement1
else
statement2
(1)condition可为表达式也可为初始化后的变量声明,但必须可被转化为布尔类型。
(2)嵌套if语句可能出现悬垂else问题,即嵌套if语句中if分支多余else分支时的匹配问题。就C++而言,规定else与离它最近的尚未匹配的if分支匹配,不受缩进格式的限制。可使用花括号控制执行路径。
#include <iostream>
#include <vector>
#include <string>
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
int main(){
int sum = 0, val = 1;
while (val <= 10)
sum += val, ++val;
cout << "Sum of 1 to 10 inclusive is " << sum << endl;
const vector<string> scores = { "F", "D", "C", "B", "A", "A++" };
int grade;
string letgrade;
while (cin >> grade)
if (grade < 60){
letgrade = scores[0];
cout << letgrade << endl;
}
else{
letgrade = scores[(grade - 50) / 10];
if (grade != 100){
if (grade % 10 > 7)
letgrade += '+';
else if (grade % 10 < 3)
letgrade += '-';
}
cout << letgrade << endl;
}
system("pause");
return 0;
}
2. switch 语句
switch( ){
case 1:
…
case 1:
…
…
}
switch提供和一条便利的途径使我们能在若干固定选项中做出选择。
(1)switch语句首先对括号中表达式求值,然后将求值结果与每个case标签的值比较,若匹配成功,则从该标签后的第一条语句开始执行,直至到达switch末尾或遇到break语句为止。(break终止当前控制流)
(2)当switch表达式值和所有case未匹配,可增加default标签执行或者直接跳转到switch结构外的第一条语句。
(3)case标签必须是整型常量表达式。
(4)switch语句在执行过程中,若与某个case标签匹配成功,将从该标签往后顺序执行所有case分支,除非程序显示中断(break;)。
(5)switch的case标签中不可存在逻辑或(||),想要在多个条件下执行同一语句时,可以将多个case标签连写在一起,代表某个范围的值。
#include <iostream>
#include <vector>
#include <string>
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
int main(){
//练习5.10遇到大小写元音字母均统计,本次我们采用switch实现
int acnt = 0, ecnt = 0, icnt = 0, ocnt = 0, ucnt = 0; //定义变量分别保存每个元音字母出现个数
char let; //读取字符
while (cin >> let){
switch (let){ //判断读入的字母
case 'a':case 'A':
++acnt;
break;
case 'e': case 'E':
++ecnt;
break;
case 'i':case 'I':
++icnt;
break;
case 'o':case 'O':
++ocnt;
break;
case 'u':case'U':
++ucnt;
break;
default:
break;
}
}
cout << "a和A的个数有" << acnt << "个" << endl;
cout << "e和E的个数有" << ecnt << "个" << endl;
cout << "i和I的个数有" << icnt << "个" << endl;
cout << "o和O的个数有" << ocnt << "个" << endl;
cout << "u和U的个数有" << ucnt << "个" << endl;
system("pause");
return 0;
}
(6)一般不要省略case分支最后的break语句,若没写则最好加一段注释说明程序逻辑关系。
(7)即使不准备在default标签下做任何工作,也应定义一个default,跟上空语句或空块,表明在程序中我们充分考虑到默认情况。
(8)C++语言规定,不允许跨过变量的初始化语句直接跳转到该变量作用域内的另一个位置,所以switch执行流程中跨过含有变量定义的case标签,直接跳转到使用该变量的case标签中是非法行为。解决方法将变量定义在块内,并不在其作用域外使用该变量。
5.4 迭代语句
通常称为循环,重复执行操作直到满足某个条件才停止。while和for在执行循环体之前检查条件;do while先执行循环体,在检查条件。
1.while 语句
(1)在不确定需要迭代多少次或者想在循环结束后访问循环控制变量时,选择使用while循环。
(2)while的条件部分可以是一个表达式或者带初始化的变量声明,在循环过程中应由条件本身或循环体设法改变表达式的值,否则循环可能无法终止。
(3)while条件部分或循环体内的变量每次迭代都经历从创建到销毁的过程。
#include <iostream>
#include <vector>
#include <string>
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
int main(){
//练习5,14 从标准输入中读取string,并查找连续重复出现的单词并进行计数,对于出现多个连续重复次数相同的单词,只会输出最后一个。这点可以改进
int sum = 1;//定义变量sum统计连续重复出现单词个数
int maxsum = 1; //存放连续重复次数最多的单词
string code1,code2; //分别存放从标准输入中读取的第一个单词和下一个单词
string code; //存放连续重复次数最多的单词
if (cin >> code1) { //确保有单词输入
while (cin >> code2) { //读取下一个单词
if (code1 == code2){
++sum;
}
else if (sum > maxsum){
maxsum = sum; //将当前统计的最大次数保存
code = code1; // 将当前连续重复次数最多的单词保存
sum = 1;
}
else
sum = 1;
code1 = code2; //将下一个单词作为第一个单词继续进行比较统计
}
if (sum > maxsum){ //对最后一个单词进行处理
maxsum = sum;
code = code1;
}
cout << "在字符串中连续重复出现的单词为:" << code << ",连续出现的次数为:" << maxsum << "次" << endl;
}
else
cout << "请确保输入字符串" << endl;
system("pause");
return 0;
}
2.传统for语句
for(initializer;condition;expression)
statement
(1)initializer必须为声明语句、表达式语句或空语句中的一种,负责初始化一个值,condition作为循环控制的条件,expression负责修改initializer初始化的变量。
(2)for循环执行顺序:先执行一次initializer,获得初始值;然后判断condition,为真执行循环体的内容,否则终止循环;最后执行expression。
(3)for语句头中定义的对象只能for循环体内可见。
(4)initializer中可定义多个对象,但只能有一条声明语句。
(5)for语句头可省略掉其中任一部分或者全部:若条件被省略,则循环体内必须有语句负责退出;
3.范围for语句
for(declaration:expression)
statement
(1)expression必须是一个序列,若初始化列表、数组、vector对象或者string等对象。
(2)若需要对序列中的元素执行写操作,循环变量必须声明为引用类型。
(3)因为在范围for循环中预存来了end()的值,所以不可使用范围for循环在序列中增加或删除元素。
4.do while语句
do
statement
while(condition);
(1)**do while语句先执行循环后检查条件,**不允许在条件部分定义变量,若如此定义,变量使用在定义之前,这是不合常理的。
(2)条件后面用一个分号表示语句结束。
#include <iostream>
#include <vector>
#include <string>
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
int main(){
//练习5.19
string yn; //定义变量作为while的条件
string s1, s2; //定义变量存放读取的两个string对象
do{
cout << "请输入两个字符串" << endl;
cin >> s1 >> s2;
if (s1.size() < s2.size())
cout << s1 << "较短" << endl;
else if (s1.size() > s2.size())
cout << s2 << "较短" << endl;
else
cout << "两个字符串长度相等" << endl;
cout << "是否继续,输入y或n" << endl;
cin >> yn;
} while (!yn.empty() && yn[0] != 'n');
system("pause");
return 0;
}
5.5跳转语句
C++包括4种跳转语句:break、continue、goto和return,本章值介绍前三种。
1.break语句
(1)break语句负责终止离它最近的while、do while、for循环和switch语句,并从这些语句后的第一条语句开始执行。
(2)break语句仅出现在迭代语句和switch语句内部,作用范围仅限于最近的循环或switch。
#include <iostream>
#include <vector>
#include <string>
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
int main(){
//练习5.20
string s1, s2;//定义变量存放从标准输入中读取的string对象
if (cin >> s1){ //确保有输入
while (cin >> s2){
if (s1 == s2){
cout << "连续重复出现的单词为:" << s1 << endl;
break;
}
else
s1 = s2;
}
if (cin.eof())
cout << "没有任何单词重复出现" << endl;
}
else
cout << "无输入!" << endl;
system("pause");
return 0;
}
2.continue语句
(1)continue语句终止最近的循环中的当前迭代并立即开始下一次迭代。中断当前迭代,但仍然继续循环。
(2)continue语句只能出现在for、while和do while循环的内部,或者嵌套在此类循环里的语句或块的内部。
#include <iostream>
#include <vector>
#include <string>
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
int main(){
string s1, s2;//定义变量存放从标准输入中读取的string对象
if (cin >> s1){ //确保有输入
while (cin >> s2){
if (s1 == s2 ){
if (s1[0] >= 'A' && s1[0] <= 'Z'){ // 判断首字母是否为大写字母
cout << "连续重复出现的单词为:" << s1 << endl;
break;
}
else{
s1 = s2;
continue;
}
}
else
s1 = s2;
}
if (cin.eof())
cout << "没有任何首字母为大写字母的单词重复出现" << endl;
}
else
cout << "无输入!" << endl;
system("pause");
return 0;
}
3.goto语句
goto label; //作用:从goto语句无条件跳转到同一函数的另一条语句。
(1)label适用于识别一条语句的标识符,标签标识符独立于变量或其他标识符的名字,所以标签标识符可以和他们使用同一名字而不互相干扰;带标签语句是一种特殊语句,在它之前有一个标识符以及一个冒号。
(2)goto语句也不能跳过一个变量的初始化定义而直接使用它,但是向后跳过一个已执行的定义是合法的,跳回到变量定义之前意味着系统将销毁该变量,然后重新创建。
(3)goto语句容易噪成程序控制流混乱,最好不要使用!
5.6 try语句块和异常处理
当程序的某部分检测到一个它无法处理的问题时,需要用到异常处理。
1 . throw表达式
- 异常检测部分使用throw表达式来表示它遇到了无法处理的问题,throw引发了异常。
(1)throw表达式包含关键字throw和紧随其后的一个表达式,在紧跟一个分号,构成一条表达式语句。其表达式类型就是抛出的异常类型(本节示例异常类型为runtime_error)。
(2)runtime_error是标准库异常类型的一种,定义在stdexcept头文件中,必须初始化runtime_error的对象,提供一个string对象或一个C风格字符串,表示异常的辅助信息。
(3)抛出异常将终止当前函数,并把控制权转移给能处理该异常的代码(try语句块处理异常)。
2. try 语句块
try{
program-statments
} catch (exception-declaration) {
handle-statements
}catch (exception-declaration) {
handle-statements
}//…
(1)try语句块:try关键字后跟一个块,然后是一个或多个catch子句,catch子句包括三部分:关键字catch、括号内一个对象的声明(异常声明)和一个块。匹配某个catch子句处理异常后执行其对应的块,然后跳转到最后一个catch子句后的那条语句继续执行。
(2)try 语句块内的变量在块外部无法访问,在catch子句内也无法访问。
(3)what作为runtime_error类的一个成员函数,没有参数,返回值是runtime_error的初始值。
(4)若程序在遇到抛出异常的代码前已经经过多个try语句块,则首先搜索该异常的函数,若没有找到则沿着程序的执行路径逐层退回,直到找到合适类型的catch子句为止。如果最终都没有找到匹配的catch子句,则转到terminate标准函数,使得程序非正常退出。
(5)程序中没有try语句或者有try语句,但是没有匹配的catch子语句,均调用terminate函数终止程序执行。
#include <iostream>
#include <vector>
#include <string>
#include <stdexcept>
using std::runtime_error;
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
int main(){
int n1, n2;//定义两个变量存放从标准输入读入的的整数
cout << "请输入两个整数:" << endl;
while (cin >> n1 >> n2){//依次读取
try{
if (n2 == 0)
throw runtime_error("第二个数作为除数不能为零!"); //中断异常
cout << "n1除以n2等于:" << n1 / n2 << endl;
cout << "是否再次输入,y/n" << endl; //询问用户是否继续输入
string s;
cin >> s;
if (!cin || s[0] == 'n') //无输入或输入为n
break; //跳出while循环程序结束
else
cout << "请输入两个整数:" << endl;
}
catch (runtime_error err){
cout << err.what()
<< "是否再次输入,y/n" << endl; //询问用户是否继续输入
string s;
cin >> s;
if (!cin || s[0] == 'n') //无输入或输入为n
break; //跳出while循环程序结束
else
cout << "请输入两个整数:" << endl;
}
}
system("pause");
return 0;
}
3. 标准异常
- exception头文件定义了最通用的异常类exception,只报告异常的发生,不提供额外信息。
- stdexcept头文件定义了常用的通用类(c++primer第五版第五章P176页 表5.1),如runtime_error、exception等。
- new头文件定义了bad_alloc异常类型,在之后会详细介绍。
- type_info头文件定义了bad_cast异常类型,之后详细介绍。
(1)标准库异常类型只定义了如创建、拷贝异常类型和为其对象赋值的运算。
(2)对exception、bad_alloc和bad_cast对象,只能采用默认初始化,但对于其他类型则必须提供初值。