博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
C++ Primer 5th 第5章 语句
阅读量:4584 次
发布时间:2019-06-09

本文共 11813 字,大约阅读时间需要 39 分钟。

和大多数语言一样,C++提供了条件执行语句、重复执行相同代码的循环语句和由于中断当前控制流的跳转语句,表达式语句和声明语句等。

语句有简单语句和复合语句之分。简单语句但多数以分号结束,最简单的语句就是空语句,空语句中就只含有一个单独的分号。

复合语句是用花括号括起来的语句或声明,复合语句也叫块。复合语句不同于简单语句的是,复合语句具有作用域,即块作用域,块中引入的名字只能被当前块或者当前块的字块访问。复合语句是不用分号结尾的。

 

可以在if、switch、while、for语句的控制结构内定义变量,这个变量只能在当前语句内访问,语句结束,变量就消亡了。

 

if语句的语法形式是

  if (condition)

    statement

对于if的condition,必须使用括号括起来,condition可以是一个表达式,也可以是一个初始化了的变量声明,并且不允许为空。

 

switch语句的语法形式是

  switch(expression)

    {

      case value:

    }

对于switch语句,首先对expression表达式求值,expression也可以是一个初始化了的变量声明。表达式的值转换成整形。然后与每个case标签比较。

case标签的值必须是个常量表达式,且是整型类型的。

如果没有任何一个case标签能匹配switch表达式的值,在switch语句有default表达式的情况下,将默认执行该default表达式,default表达式的位置无关紧要。

 

while语句的语法形式是

  while (condition)

    statement

condition是不允许为空的,可以是个表达式,也可以是一个初始化了的变量声明。

while循环不同于for循环的一点是,while条件部分或者while循环体内定义的变量每次迭代后都会被销毁。

 

范围for语句的语法形式是

  for (declaration : expression)

    statement

expression必须是一个序列,比如花括号括起来的初始值列表{1,2,3,4,5},或者数组、vector、string等类型的对象,这些对象的特点是可以使用begin和end成员或者函数来获取其相应的迭代器。

 

do while语句中while的条件部分使用的变量必须是循环前定义的。 

 

break语句用于终止循环,break语句只能出现在迭代语句或者switch语句的内部,嵌套在循环语句的子语句也是可以的。

continue语句用于停止当前迭代的执行,重新开始下一次的迭代,但是不能终止循环,continue语句只能出现在for、while、do while循环的内部,或者循环内部的子块。

goto语句较难把控,不建议使用

 

try语句块和异常处理:

当程序的某部分检测到一个它无法处理的问题时,需要使用异常处理,异常分为两块,一块是异常的检测,一块是异常的处理。

 检测部分是发出某种信号,表明遇到故障。发出是由throw完成的,称作throw引发了异常。某种信号则是异常的类型。

异常的处理是try和catch负责的。

throw表达式引发一个异常,表达式包含关键字和一个表达式,表达式的类型就是异常的类型,用于发出某种信号。

try语句块是一个关键字加上紧随的复合语句块,必须是复合语句块,不能是一个简单语句。

try语句之后是一个或多个catch子句。catch子句包含一个关键字catch,一个括号括起来的对象声明,一个语句块。当选中某个catch子句处理完毕后,程序就跳到所有catch子句之后的地方继续执行。如果没有catch子句,程序一般会非正常退出。

另外,try语句块具有块作用域,出了该块,不能在外部访问块内引入的变量。

 

 

 

练习5.1:什么是空语句?什么时候会用到空语句?

空语句就是只含有一个单独分号的语句。当语法上需要一条语句,逻辑上不需要时,就需要使用空语句

 

练习5.2:什么是块?什么时候会用到块?

块就是用花括号括起来的语句或者声明序列,当语法上需要一条语句,但是逻辑上需要多条语句,此时就要使用块。

练习5.3:使用逗号运算符(参见4.10节,第104页)重写1.4.1节(第10页)的 while 循环,使它不再需要块,观察改写之后的代码的可读性提高了还是降低了。

#include 
using namespace std;int main(){ int i = 50, sum = 0; while (i <= 100) sum += i, ++i; return 0;}

改写后的可读性降低。

 

练习5.4:说明下列例子的含义,如果存在问题,试着修改它。

(a) while (string::iterator iter != s.end()){    /* . . . */}(b) while (bool status = find(word)){    /* . . . */}if (!status){    /* . . . */}

(a) 用循环遍历string s,语法错误,while头部只能是一个表达式或者初始化了的变量声明。应该将iter放在while外面定义。

(b) while头部定义的变量只在当前循环内可见,if无法访问,应该将status的定义放在最外面。

 

练习5.5:写一段自己的程序,使用if else 语句实现把数字成绩转换为字母成绩的要求。

#include 
#include
using namespace std;int main(){ const vector
scores = {
"F", "D", "C", "B", "A", "A++"}; string lettergrade; int grade; while (cin >> grade) { if (grade < 60) lettergrade = scores[0]; else lettergrade = scores[(grade - 50) / 10]; cout << lettergrade << '\n'; } return 0;}

 

练习5.6:改写上一题的程序,使用条件运算符(参见4.7节,第134页)代替if else语句。

#include 
#include
using namespace std;int main(){ const vector
scores = {
"F", "D", "C", "B", "A", "A++"}; string lettergrade; int grade; while (cin >> grade) { (grade < 60) ? ( lettergrade = scores[0]) : (lettergrade = scores[(grade - 50) / 10]); cout << lettergrade << '\n'; } return 0;}

 

练习5.7:改写下列代码段中的错误。

(a) if (ival1 != ival2)       ival1 = ival2    else        ival1 = ival2 = 0;(b) if (ival < minval)    minval = ival;    occurs = 1;(c) if (int ival = get_value())        cout << "ival = " << ival << endl;    if (!ival)        cout << "ival = 0\n";(d) if (ival = 0)        ival = get_value();

(a) ival1 = ival2 后面缺少分号。

(b) 应该用花括号括起来。

(c) if (!ival) 应该改为else。

(d) if (ival = 0) 应该改为 if (ival == 0)。

练习5.8:什么是“悬垂else”?C++语言是如何处理else子句的?

悬垂else就是一个if语句嵌套在另一个if语句内部,使得if分支多于else分支。C++规定else与离它最近的尚未匹配的if匹配。

 

练习5.9:编写一段程序,使用一系列if语句统计从cin读入的文本中有多少元音字母。

#include 
using namespace std;int main(){ char c; size_t num = 0; while (cin >> c) { if (c == 'a') ++num; if (c == 'e') ++num; if (c == 'i') ++num; if (c == 'o') ++num; if (c == 'u') ++num; } cout << num << endl; return 0;}

 

练习5.10:我们之前实现的统计元音字母的程序存在一个问题:如果元音字母以大写形式出现,不会被统计在内。编写一段程序,既统计元音字母的小写形式,也统计元音字母的大写形式,也就是说,新程序遇到'a'和'A'都应该递增 aCnt 的值,以此类推。

#include 
using namespace std;int main(){ char c; size_t num = 0; while (cin >> c) { if (c == 'a' || c == 'A') ++num; if (c == 'e' || c == 'E') ++num; if (c == 'i' || c == 'I') ++num; if (c == 'o' || c == 'O') ++num; if (c == 'u' || c == 'U') ++num; } cout << num << endl; return 0;}

 

练习5.11:修改统计元音字母的程序,使其也能统计空格、制表符、和换行符的数量。

#include 
using namespace std;int main(){ size_t num; char ch; while (cin >> ch) { switch (ch) { case 'a': case 'A': case 'e': case 'E': case 'i': case 'I': case 'o': case 'O': case 'u': case 'U': case ' ': case '\t': case '\n': ++num; } } return 0;}

 

练习5.12:修改统计元音字母的程序,使其能统计含以下两个字符的字符序列的数量: ff、fl和fi。

#include 
using namespace std;int main(){ size_t num; string s; while (cin >> s) { if (s == "ff" || s == "fl" || s == "fi") { ++num; } } return 0;}

  

练习5.13:下面显示的每个程序都含有一个常见的编码错误,指出错误在哪里,然后修改它们。

(a) unsigned aCnt = 0, eCnt = 0, iouCnt = 0;char ch = next_text();switch (ch){    case 'a': aCnt++;    case 'e': eCnt++;    default: iouCnt++;}(b) unsigned index = some_value();switch (index) {case 1:    int ix = get_value();    ivec[ ix ] = index;    break;default:    ix = ivec.size() - 1;    ivec[ ix ] = index;}(c) unsigned evenCnt = 0, oddCnt = 0;int digit = get_num() % 10;switch (digit) {case 1, 3, 5, 7, 9:    oddcnt++;    break;case 2, 4, 6, 8, 10:    evencnt++;    break;}(d) unsigned ival = 512, jval = 1024, kval = 4096;unsigned bufsize;unsigned swt = get_bufCnt();switch (swt) {case ival:    bufsize = ival * sizeof(int);    break;case jval:    bufsize = jval * sizeof(int);    break;case kval:    bufsize = kval * sizeof(int);    break;}

(a) 每个case缺少break语句。

case 'a': aCnt++;

break;
case 'e': eCnt++;
break;
default: iouCnt++;
break;

(b) default标签中的ix 未定义。修改为

int ix;

unsigned index = some_value();
switch (index)
{
case 1:
ix = get_value();
ivec[ ix ] = index;
break;
default:
ix = ivec.size() - 1;
ivec[ ix ] = index;
}

(c) case标签错误,变量名错误。修改为

unsigned evenCnt = 0, oddCnt = 0;

int digit = get_num() % 10;
switch (digit)
{
case 1:case 3:case 5:case 7:case 9:
oddcnt++;
break;
case 2:case 4:case 6:case 8:case 10:
evencnt++;
break;
}

(d) case 标签必须是整型常量表达式。修改为

constexpr unsigned ival = 512, jval = 1024, kval = 4096;

unsigned bufsize;
unsigned swt = get_bufCnt();
switch (swt)
{
case ival:
bufsize = ival * sizeof(int);
break;
case jval:
bufsize = jval * sizeof(int);
break;
case kval:
bufsize = kval * sizeof(int);
break;
}

练习5.14:编写一段程序,从标准输入中读取若干string对象并查找连续重复出现的单词。所谓连续重复出现的意思是:一个单词后面紧跟着这个单词本身。要求记录连续重复出现的最大次数以及对应的单词。如果这样的单词存在,输出重复出现的最大次数;如果不存在,输出一条信息说明任何单词都没有连续出现过。例如:如果输入是:

how now now now brown cow cow

那么输出应该表明单词now连续出现了3次。

#include 
using namespace std;int main(){ string s1, s2; if (cin >> s1) { int cnt = 1; while (cin >> s2) { if (s1 == s2) ++cnt; else {   cout << s1 << "occurs " << cnt << " times" << endl; s1 = s2; cnt = 1; } } cout << s1 << "occurs " << cnt << " times" << endl; } return 0;}

 

练习5.15:说明下列循环的含义并改正其中的错误。

(a) for (int ix = 0; ix != sz; ++ix) { /* ... */ }if (ix != sz)// . . .(b) int ix;for (ix != sz; ++ix) { /* ... */ }(c) for (int ix = 0; ix != sz; ++ix, ++sz) { /*...*/ }

(a) if不可以访问for的局部变量ix,应该将ix放在for的前面定义

(b) for的语法格式错误,应改为for( ; ix != sz; ++ix)

(c) 死循环,ix != sz 恒成立,不应该使用 ++ix,++sz

 

练习5.16:while 循环特别适用于那种条件不变、反复执行操作的情况,例如,当未达到文件末尾时不断读取下一个值。for 循环更像是在按步骤迭代,它的索引值在某个范围内依次变化。根据每种循环的习惯用法各自编写一段程序,然后分别用另一种循环改写。如果只能使用一种循环,你倾向于哪种?为什么?

#include 
using namespace std;int main(){ int i = 0, sum = 0; while (i <= 100) { sum += i; ++i; } for (int i = 0; i != 100; ++i) { sum += i; } return 0;}

如果只能使用一种,我倾向于for循环,因为for循环头部提供更多的选项,可以更多的控制循环,相对while循环来说更强大易用。

 

练习5.17:假设有两个包含整数的vector对象,编写一段程序,检验其中一个vector对象是否是另一个的前缀。为了实现这一目标,对于两个不等长的vector对象,只需挑出长度较短的那个,把它的所有元素和另一个vector对象比较即可。例如,如果两个vector对象的元素分别是0、1、1、2 和 0、1、1、2、3、5、8,则程序的返回结果为真。

#include 
#include
using namespace std;int main(){ vector
v1{
0, 1, 1, 2}, v2{
0, 1, 1, 2, 3, 5, 8}; if (v1.size() < v2.size()) { for (size_t i = 0; i != v1.size(); ++i) { if (v1[i] != v2[i]) cout << "not equal\n"; } } else { for (size_t i = 0; i != v2.size(); ++i) { if (v1[i] != v2[i]) cout << "not equal\n"; } } return 0;}

 

练习5.18:说明下列循环的含义并改正其中的错误。

(a) do        int v1, v2;        cout << "Please enter two numbers to sum:" ;        if (cin >> v1 >> v2)            cout << "Sum is: " << v1 + v2 << endl;    while (cin);(b) do {        // . . .    } while (ival = get_response());(c) do {        ival = get_response();    } while (ival);

(a) 语法错误,do后面,while前面的语句应该用花括号括起来

(b) 语法错误,do while条件使用的表达式规定必须是在循环前定义!

(c) 语法错误,do while条件使用的表达式规定必须是在循环前定义!

练习5.19:编写一段程序,使用do while 循环重复地执行下述任务:首先提示用户输入两个string对象,然后挑出较短的那个并输出它。

#include 
using namespace std;int main(){ string s1, s2; char c; do { cout << "input two strings:"; cin >> s1 >> s2; if (s1.size() > s2.size()) cout << s1 << endl; else cout << s2 << '\n' << "More ? Enter 'y' or 'n' " << endl; cin >> c; } while (c != 'n'); return 0;}

 

练习5.20:编写一段程序,从标准输入中读取string对象的序列直到连续出现两个相同的单词或者所有单词都读完为止。使用while循环一次读取一个单词,当一个单词连续出现两次时使用break语句终止循环。输出连续重复出现的单词,或者输出一个消息说明没有任何单词是连续重复出现的。

#include 
using namespace std;int main(){ string s1, s2; if (cin >> s1) { while (cin >> s2) { if (s1 == s2) { cout << s2; break; } else { s1 = s2; } } } return 0;}

 

练习5.21:修改5.5.1节练习题的程序,使其找到的重复单词必须以大写字母开头。

#include 
using namespace std;int main(){ string s1, s2; if (cin >> s1) { while (cin >> s2) { if (s1 == s2 && isupper(s2[0])) { cout << s2 << endl; break; } else { s1 = s2; } } } return 0;}

 

练习5.22本节的最后一个例子跳回到 begin,其实使用循环能更好的完成该任务,重写这段代码,注意不再使用goto语句。

#include 
using namespace std;int main(){ int sz = get_size(); while (sz <= 0) sz = get_size(); return 0;}

 

练习5.23:编写一段程序,从标准输入读取两个整数,输出第一个数除以第二个数的结果。

#include 
using namespace std;int main(){ int i1, i2; cin >> i1 >> i2; if (i2 == 0) throw "ERROR! Division by zero!"; cout << i1 / i2 << endl; return 0;}

 

练习5.24:修改你的程序,使得当第二个数是0时抛出异常。先不要设定catch子句,运行程序并真的为除数输入0,看看会发生什么?

程序终止。

练习5.25:修改上一题的程序,使用try语句块去捕获异常。catch子句应该为用户输出一条提示信息,询问其是否输入新数并重新执行try语句块的内容。 

#include 
using namespace std;int main(){ int i1, i2; while (cin >> i1 >> i2) { try { if (i2 == 0) throw string("ERROR! Division by zero!"); } catch (string s) { cout << s << endl; cout << "Try again? 'Y' or 'N'"; char c; cin >> c; if (!cin || c == 'n') break; else continue; } cout << i1 / i2 << endl; } return 0;}

 

转载于:https://www.cnblogs.com/pluse/p/5106712.html

你可能感兴趣的文章
C#基础-第6章:类型和成员基础
查看>>
TextView实现多个TextView对象的走马灯效果
查看>>
感悟成功
查看>>
学员管理示例:Ajax删除学生
查看>>
线程组和未处理的异常
查看>>
Oracle管理监控之为11g asm磁盘组添加磁盘
查看>>
javasrcipt中的for in 循环
查看>>
ThetaSome_ThetaAll子查询
查看>>
BZOJ1499 单调队列+DP
查看>>
用鼠标键盘来控制你的Android手机——同屏显示简单教程
查看>>
文件上传
查看>>
js面向对象
查看>>
在CentOS下面编译WizNote Qt Project
查看>>
android list view 实现动态加载
查看>>
NFS工作原理
查看>>
nginx配置用户认证
查看>>
Kubernetes的Cron Job
查看>>
41岁中兴员工:这可能是我第5次失业_中兴被美国制裁的思考
查看>>
go工程组织规范
查看>>
排序---冒泡排序
查看>>