/*第五章 语句*/
**语句是按顺序执行的
**提供一组控制流语句支持更复杂的执行路径
5.1 简单语句
1. 表达式语句:执行表达式并丢弃求值结果。以分号结束
2. 空语句:单独的分号
**语法上需要但是逻辑上不需要
**使用空语句应该使用注释
3. 别多写分号也别不写分号
4. 复合语句(块):用花括括的语句和声明的序列,一个块就是作用域
**块不以分号做结束
**语法上需要一条语句,但是逻辑上需要多条语句时使用
5.2 语句作用域
5.3 条件语句
**两种按条件执行的语句:if语句、switch语句
1. if语句
**判断一个指定条件是否为真,根据判断结果决定是否执行另外一条语句
**两种形式:含有else分支、没有else分支
**语句形式:
**if(condition)
** statement
**if(condition)
** statement
**else
** statement2
2. 嵌套if语句
3. 悬垂else:如何判断给定else与哪个if相匹配
**if分支多于else分支时的匹配问题
**C++规定与最近的尚未匹配的if相匹配
**注意使用花括,并用花括控制执行路径
5.3 switch语句
**提供了一条便利的途径使得可以在若干固定选项中做出选择
**先对函数括表达式求值,表达式可以是初始化声明
**表达式值转换成整数类型与case标签(case关键字和对应值)进行比较
1. 表达式与case标签匹配成功,程序将从case第一条语句执行直到switch结尾或者遇到break语句为止
**必须显式中断控制流才能停止
2. 表达式与所有case标签都没有匹配,将直接跳出switch语句
3. case值不能相同,会引发错误。case标签必须是整型常量表达式!!!!!!!!!
4. 一般省略break应该注释说明原因
5. default标签:case标签没有匹配,执行default标签内语句
**不执行也定义,表明已经考虑默认情况
**不应孤立出现,即使只有一个默认标签,上一句应为空语句或空块
6. switch内部变量定义
**如果略过代码中含有变量定义时发生问题
**如果在某处一个带有初值的变量位于作用域之外,在另一处该变量位于作用域之内,则从前一处跳转到后一处
**行为非法
**C++规定不允许跨过变量的初始化语句直接跳转到该变量作用域内的另一个位置
**使用块控制变量的作用域,不同case标签内的变量定义和使用应该注意作用域的影响
5.4 迭代语句
**迭代语句通常称为循环,重复执行直到满足某个条件退出
**while和for语句在执行循环体之前检查条件
**而do-while语句限制性循环体然后检查条件
5.4.1 while语句
1. 语法形式:
**while(condition)
** statement;
2. 条件部分可以是一个表达式或者一个带初始化的变量声明
3. 当不知道要循环的次数时,使用while循环比较合适
5.4.2 传统的for语句
1. 语法形式:
**for(init-statement; condition; expression) //for语句头
** statement
3. 传统for循环执行流程
**循环开始,执行一次init-statement
**判断condition,条件为假直接退出循环
**条件为真,执行循环体
**最后执行expression
4. for语句头多重定义:可以定义多个对象,但是init-statement只能由一条声明语句
**所有变量基础类型必须相同
5. for语句头可以省略任何一个部分
**分号必须保留表示空语句
5.4.3 范围for语句
**C++11 新标准引入,可以遍历容器所有元素
1. 语法形式:
**for(declaration:expression)
** statement
2. expression必须是一个序列
3. declaration定义一个变量,序列中每一个元素都必须能转换成该变量类型(auto最省心)
**每次迭代都会重新定义循环控制变量,每次auto都根据元素决定类型
4. 范围for语句中增加容器元素,会导致容器end成员函数无效,for语句预存的end()值不匹配
5.4.4 关于do-while语句
**先执行一次循环体后检查条件
1. 语法形式:
**do
** statement
**while(condition);
**while判断后必须以分号结束
2. 先执行后判断条件,因此不允许在条件语句中声明定义变量
5.5 跳转语句
**跳转语句中断当前执行过程
**break、continue、goto、return
5.5.1 break语句
**负责终止离它最近的while、do-while或者switch语句
5.5.2 continue语句
**终止最近的循环中的当前迭代并立即开始下一次迭代
**只能出现在循环语句作用域内
**仅作用于最近的循环
5.5.3 goto语句
**从goto语句无条件跳转同一函数内的另一条语句
**不要再程序中使用goto语句,可读性差,难以修改
1. 语法形式:
**goto label;
2. 不能将程序从变量作用域之外转移到作用域之内
3. 向后跳过一个已经执行的定义是合法的,向前跳回定义之前,系统销毁变量并重新定义
5.6 try语句块和异常处理
**异常:运行时的反常行为,超出正常功能范围
**常见有失去数据库连接、遇到意外输入等
**程序应该进行异常检测
**检测出问题的部分发出某种信号表明遇到故障无法继续运行
**无须知道故障在何出得以结局
**程序含有可能引发异常的代码,也有专门的代码处理问题
**throw表达式表示检测到异常
**try语句块处理异常
**异常类用于在throw和try子句传递异常据题信息
5.6.1 throw表达式
**表示检测到异常
**异常检测部分使用throw引发一个异常
**语法形式:关键字throw+表达式,表达式类型为抛出的异常类型
5.6.2 try语句块
1. 语法形式:
**try{
program-statements //组成正常逻辑的语句序列
}catch (exception-declaration){ //关键字 异常声明 语句序列
handler-statements
}catch (exception-declaration){
handler-statements
}
2. 编写处理代码
**what()成员函数返回值是C风格字符串(const char*),返回初始化一个具体对象时所用的string对象的副本
3. 函数在寻找处理代码过程中退出
**复杂系统中遇到抛出异常代码前,执行路径可能已经经过多个try语句块
**寻找异常处理代码与函数调用链正好相反
**抛出异常后首先在该异常函数搜索,未匹配则终止函数并在调用函数的函数中查找,逐层退回
**最终没有任何匹配,程序转到terminate标准库函数,函数与系统有关,执行导致程序非正常退出
4. 没有try语句块,程序也按类似方法处理
**要处理异常并继续执行的程序,需要时刻清除异常何时发生,异常发生后程序应如何确保对象有效、资源无泄漏、程序处于
**合理状态等等
5.6.3 标准异常
**标准库定义一组类,用于报告标准库函数遇到的问题,分别定义在4个头文件中
1. exception头文件定义最通用的异常类exception,只报告异常发生不提供额外信息
2. stdexcept头文件定义几种常用异常类
3. new头文件定义bad_alloc异常类
4. type_info头文件定义bad_cast异常类
5. 只能默认初始化exception、bad_alloc、bad_cast,不允许赋值。其他类则只能用初始值初始化,初始值含有错误信息
6. 异常类只定义一个成员函数,返回值提供异常信息
*/
#include <iostream>
#include <string>
#include <cstddef>
#include <vector>
using namespace std;
/*练5.5:写一段自己的程序,使用if-else语句实现数字成绩转换成字母成绩的要求*/
int main5_5()
{
const vector<string> scores = {"F", "D", "C", "B", "A", "A++"};
string lettergrade;
int grade = 0;
cout << "请输入分数:" << endl;
while(cin >> grade && grade >= 0 && grade <= 100)
{
if(grade < 60)
{
lettergrade = scores[0];
}
else
{
lettergrade = scores[(grade - 50)/10];
if(grade % 10 > 7)
{
lettergrade += '+';
}
else if(grade % 10 <3)
{
lettergrade += '-';
}
}
cout << lettergrade << endl;
}
return 0;
}
/*练习题5.6:改写上一题的程序,使用条件运算符代替if-else语句*/
int main5_6()
{
const vector<string> scores = {"F", "D", "C", "B", "A", "A++"};
string lettergrade;
int grade = 0;
cout << "请输入分数:" << endl;
while(cin >> grade && grade >= 0 && grade <= 100)
{
(grade > 60) ? (lettergrade = scores[(grade - 50)/10]): (lettergrade = scores[0]);
((grade % 10) > 7) ? (lettergrade += '+') : ((grade % 10) <3) ? (lettergrade += '-') : lettergrade;
}
cout << lettergrade << endl;
return 0;
}
/*练习题5.9:编写一段程序,使用一系列if语句统计从cin读入的文本中有多少元音字母*/
int main5_9()
{
unsigned int acnt = 0, ecnt = 0, icnt = 0, ocnt = 0, ucnt = 0;
char ch;
while(cin >> ch)
{
if(ch == 'a')
++acnt;
if(ch == 'e')
++ecnt;
if(ch == 'i')
++icnt;
if(ch == 'o')
++ocnt;
if(ch == 'u')
++ucnt;
}
cout << acnt << " " << ecnt << " " << icnt << " " << ocnt << " " << ucnt << endl;
return 0;
}
/*练习题5.10:考虑大写元音字母,也统计对应字母计数*/
int main5_10()
{
unsigned int acnt = 0, ecnt = 0, icnt = 0, ocnt = 0, ucnt = 0;
char ch;
while(cin >> ch)
{
switch(ch)
{
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;
}
}
cout << acnt << " " << ecnt << " " << icnt << " " << ocnt << " " << ucnt << endl;
return 0;
}
/*练习题5.11:修改统计元音字母的程序,使其也能统计空格、制表符和换行符的数量*/
int main5_11()
{
unsigned int acnt = 0, ecnt = 0, icnt = 0, ocnt = 0, ucnt = 0, bcnt = 0, excnt = 0, linecnt = 0;
char ch;
while(cin.get(ch))
{
switch(ch)
{
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;
case ' ':
++bcnt;
break;
case '\t':
++excnt;
break;
case'\n':
++linecnt;
break;
}
}
cout << acnt << " " << ecnt << " " << icnt << " " << ocnt << " " << ucnt << " " << bcnt << " " << excnt << " " << linecnt << endl;
return 0;
}
/*练习题5_12:修改程序使其能统计一下含有两字符的字符序列的数量:ff fl fi*/
int main5_12()
{
unsigned int acnt = 0, ecnt = 0, icnt = 0, ocnt = 0, ucnt = 0, bcnt = 0, excnt = 0, linecnt = 0, ff = 0, fl = 0, fi = 0;
char ch;
while(cin.get(ch))
{
switch(ch)
{
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;
case ' ':
++bcnt;
break;
case '\t':
++excnt;
break;
case'\n':
++linecnt;
break;
case 'f':
{
cin.get(ch);
switch(ch)
{
case 'f':++ff;break;
case 'l':++fl;break;
case 'i':++fi;break;
}
}
}
}
cout << linecnt << "ff: " << ff << "fl: "<< fl << "fi: "<< fi << endl;
return 0;
}
/*练习题5.13:(d)case标签必须时整型常量表达式*/
/*练习题5_14: 编写一段程序,从标准输入中读取若干string对象并查找连续重复的单词*/
int main5_14()
{
int cnt = 0, cnt_temp = 1, i = 0;
vector<string> str;
string temp;
cout << "请输入一组string类型对象:" << endl;
while (cin >> temp)
{
str.push_back(temp);
cout << str[i] << endl;
i++;
}
auto beg = str.cbegin();
if (beg == str.cend())
{
cout << "no data!" << endl;
return -1;
}
auto next = beg + 1;
while (beg != (str.cend()-1)) //beg如果判断end(),对于next会溢出
{
if (*beg == *next)
++cnt_temp;
else cnt_temp = 1;
if (cnt_temp > cnt)
{
cnt = cnt_temp;
}
beg = next;
next = beg + 1;
}
if (cnt > 1)
{
cout << cnt << endl;
}
else
cout << "没有连续出现的单词!" << endl;
return 0;
}
/*练习5.17: 假设两个包含整数的vector对象,编写一段程序,检验其中一个vector是否是另一个vector对象的前缀*/
int main5_17()
{
int temp;
vector<int> ivec1,ivec2;
cout << "请分别输入两组int类型的数字:" << endl;
while(cin >> temp)
{
ivec1.push_back(temp);
}
fflush(stdin);
cin.clear();
while(cin >> temp)
{
ivec2.push_back(temp);
}
if(ivec1 < ivec2)
{
auto it1 = ivec1.cbegin(),it2 = ivec2.cbegin();
for(; it1 != ivec1.cend() && (*it1) != (*it2); ++it1, ++it2)
{
;
}
if(it1 == ivec1.cend())
{
cout << "ivec1是ivec2的前缀" << endl;
return 0;
}
}
else if(ivec1 > ivec2)
{
auto it1 = ivec1.cbegin(),it2 = ivec2.cbegin();
for(; it2 != ivec2.cend() && (*it1) != (*it2); ++it1, ++it2)
{
;
}
if(it2 == ivec2.cend())
{
cout << "ivec2是ivec1的前缀" << endl;
return 0;
}
}
cout << "没有前缀的对象存在" << endl;
return 0;
}
/*练习5.19:编写一段程序,使用do-while循环重复执行下述任务:首先提示用户输入两个string对象,然后挑出较短那个并输出它*/
int main5_19()
{
string reply;
do{
cout<<"输入两个string对象"<<endl;
string str1,str2;
cin>>str1>>str2;
if(str1.size()>str2.size())
cout<<str2<<endl;
else
cout<<str1<<endl;
cout<<"do you want to continue('n' to quit):"<<endl;
cin>>reply;
}
while(reply[0]!='n');
cout << "thank you!" << endl;
return 0;
}
/*练习5.20:编写一段程序,从标准输入读取string对象的序列直到连续出现两个相同的单词或者所有单词都读完为止*/
int main5_20()
{
vector<string> str;
string temp;
size_t index = 0;
bool flag = false;
cout << "请输入string类型对象:" << endl;
while (cin >> temp)
{
str.push_back(temp);
++index;
if (str.size() > 1)
{
if (str[index-1] == str[index - 2]) //使用下标,但是计算下标很麻烦。也可以使用迭代器?
{
flag = !flag;
break;
}
}
}
(flag) ? (cout << "连续重复出现的单词是: " << str[index - 1]) : (cout << "没有连续重复出现的单词!");
return 0;
}
/*练习题5.21:修改5.20练习题的程序,使其找到的重复单词必须以大写字母开头*/
int main5_21()
{
vector<string> str;
string temp;
size_t index = 0;
bool flag = false;
cout << "请输入string类型对象:" << endl;
while (cin >> temp)
{
str.push_back(temp);
++index;
if (str.size() > 1)
{
if (str[index-1] == str[index - 2]) //使用下标,但是计算下标很麻烦。也可以使用迭代器?
{
auto it = str.begin();
if(isupper((*it)[0]))
{
flag = !flag;
break;
}
else continue;
}
}
}
(flag) ? (cout << "连续重复出现的单词是: " << str[index - 1]) : (cout << "没有连续重复出现的单词!");
return 0;
}
/*练习题5.23:编写一段程序,从标准输入读取两个整数,输出第一个数除以第二个数的结果*/
int main5_23()
{
int i1,i2;
cout << "请输入两个整数:" << endl;
cin >> i1 >> i2;
cout << "除法结果是:" << i1/i2 << endl;
return 0;
}
/*练习题5.24:修改你的程序,使得当第二个数是0的时候抛出异常。先不要设定catch子句运行程序查看结果*/
int main5_24()
{
int i1, i2;
cout << "请输入两个整数:" << endl;
while (cin >> i1 >> i2)
{
if (!i2)
throw runtime_error("第二个数不能为0!");
cout << "除法结果是:" << i1 / i2 << endl;
}
return 0;
}
/*练习题5_25:修改程序,使用try语句块去捕获异常,catch子句应该为用户输出一
**条提示信息询问是否需要输入新数并重新执行try语句块内容*/
int main5_25()
{
int i1, i2;
cout << "请输入两个整数:" << endl;
while (cin >> i1 >> i2)
{
try{
if (!i2)
throw runtime_error("第二个数不能为0!");
cout << "除法结果是:" << i1 / i2 << endl;
}catch(runtime_error err){
string answer;
cout << err.what() << "是否重新输入两个整数('n' to quit):" << endl;
cin >> answer;
if(answer[0] == 'n'){
cout << "程序退出!";
break;
}
cout << "请输入两个整数:" << endl;
continue;
}
cout << "请输入两个整数:" << endl;
}
return 0;
}
int main()
{
main5_25();
}
C++_Primer_Plus学习笔记-第五章
最新推荐文章于 2022-07-15 16:33:04 发布