《C++ Primer》第5章 语句
5.3节 条件语句
练习5.5:写一段自己的程序,使用if-else语句实现把数字成绩转换成字母成绩的要求。
【出题思路】
练习if-else语句的基本语法结构。
【解答】
满足题意的程序如下所示:
#include <iostream>
using namespace std;
int main()
{
int grade;
cout << "请输入您的成绩:";
cin >> grade;
if(grade < 0 || grade > 100)
{
cout << "该成绩不合法" << endl;
return -1;
}
if(100 == grade)
{
cout << "等级成绩是:" << "A++" << endl; //处理满分的情况
return -1;
}
if(grade < 60)
{
cout << "等级成绩是:" << "F" << endl; //处理不级格的情况
return -1;
}
int iU = grade / 10; //成绩的十位数
int iT = grade % 10; //成绩的个位数
string score, level, lettergrade;
//根据成绩的十位数字确定score
if(9 == iU)
score = "A";
else if(8 == iU)
score = "B";
else if(7 == iU)
score = "C";
else
score = "D";
//根据成绩的个位数字确定level
if(iT < 3)
level = "-";
else if(iT > 7)
level = "+";
else
level = "";
//累加求得等级成绩
lettergrade = score + level;
cout << "等级成绩是:" << lettergrade << endl;
return 0;
}
运行结果:
练习5.6:改写上一题的程序,使用条件运算符(参见4.7节,第134页)代替if-else语句。
【出题思路】
条件运算符可以实现与if-else语句类似的功能,当有嵌套的条件表达式时,注意其满足右结合律。
【解答】
改写了score和level的求值形式,得到满足题意的程序如下所示:
#include <iostream>
using namespace std;
int main()
{
int grade;
cout << "请输入您的成绩:";
cin >> grade;
if(grade < 0 || grade > 100)
{
cout << "该成绩不合法" << endl;
return -1;
}
if(grade == 100) //处理满分的情况
{
cout << "等级成绩是:" << "A++" << endl;
return -1;
}
if(grade < 60) //处理不级格的情况
{
cout << "等级成绩是:" << "F" << endl;
return -1;
}
int iU = grade / 10; //成绩的十位数
int iT = grade % 10; //成绩的个位数
string score, level, lettergrade;
//根据成绩的十位数字确定score
score = (9 == iU) ? "A" : (8 == iU) ? "B" : (7 == iU) ? "C" : "D";
//根据成绩的个位数确定level
level = (iT < 3) ? "-" : (iT > 7) ? "+" : "";
//累加求得等级成绩
lettergrade = score + level;
cout << "等级成绩是:" << lettergrade << endl;
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();
【出题思路】
理解if语句的语法规则。
【解答】
(a)if语句的循环体应该是一条语句,需要以分号结束,程序修改为:
if(ival1 != ival2)
ival1 = ival2;
else ival1 = ival2 = 0;
(b)if语句的循环体只能是一条语句,本题从逻辑上来说需要做两件事,一是修改minval的值,二是重置occurs的值,所以必须把这两条语句放在一个块里。程序修改为:
if(ival < minval)
{
minval = ival;
occurs = 1;
}
(c)ival是定义在if语句中的变量,其作用域仅限于第一个if语句,要想在第二个if语句中也使用它,就必须把它定义在两个if语句的外部。程序修改为:
int ival;
if(ival = get_value())
cout << "ival = " << ival << endl;
if(!ival)
cout << "ival = 0\n";
(d)程序的原意是判断ival的值是否是0,原题使用赋值运算符的结果是把0赋给了ival,然后检验ival的值,这样使得条件永远不会满足。程序修改为:
if(ival == 0)
ival = get_value();
练习5.8:什么是“悬垂else”?C++语言是如何处理else子句的?
【出题思路】
理解悬垂else的定义,以及C++是如何处理悬垂else的。
【解答】
悬垂else是指当程序中的if分支多于else分支时,如何为else寻找与之匹配的if分支的问题。C++规定,else与离它最近的尚未匹配的if匹配,从而消除了二义性。
练习5.9:编写一段程序,使用一系列if语句统计从cin读入的文本中有多少元音字母。
【出题思路】
if语句和switch语句是分支语句的两种形式,一般来说可以互相转化。
【解答】
满足题意的程序如下所示:
#include <iostream>
using namespace std;
int main()
{
unsigned int vowelCnt = 0;
char ch;
cout << "请输入一段文本:" << endl;
while(cin >> ch)
{
if('a' == ch)
++vowelCnt;
if('e' == ch)
++vowelCnt;
if('i' == ch)
++vowelCnt;
if('o' == ch)
++vowelCnt;
if('u' == ch)
++vowelCnt;
}
cout << "您输入的文本中共有 " << vowelCnt << " 个元音字母" << endl;
return 0;
}
运行结果:
练习5.10:我们之前实现的统计元音字母的程序存在一个问题:如果元音字母以大写形式出现,不会被统计在内。编写一段程序,既统计元音字母的小写形式,也统计大写形式,也就是说,新程序遇到'a'和'A'都应该递增aCnt的值,以此类推。
【出题思路】
要实现本题的要求,只需更新switch语句的case分支即可。
【解答】
本题的关键是在适当位置添加break;语句。其中,表示同一个字母的大小写的case标签之间不写break;,因为它们要做的操作是一样的;而不同字母的case分支最后要写上break;。满足题意的程序如下所示:
#include <iostream>
using namespace std;
int main()
{
unsigned int aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0;
char ch;
cout << "请输入一段文本:" << endl;
while(cin >> ch)
{
switch(ch)
{
case 'a':
case 'A':
++aCnt;
break;
case 'e':
case 'E':
++eCnt;
break;
case 'i':
case 'I':
++eCnt;
break;
case 'o':
case 'O':
++oCnt;
break;
case 'u':
case 'U':
++uCnt;
break;
default:
break;
}
}
cout << "元音字母 a 的数量是:" << aCnt << endl;
cout << "元音字母 e 的数量是:" << eCnt << endl;
cout << "元音字母 i 的数量是:" << iCnt << endl;
cout << "元音字母 o 的数量是:" << oCnt << endl;
cout << "元音字母 u 的数量是:" << uCnt << endl;
return 0;
}
运行结果:
练习5.11:修改统计元音字母的程序,使其也能统计空格、制表符和换行符的数量。
【出题思路】
继续扩充case标签即可。其中,读入字符的语句应该使用cin.get(ch),而不能使用>>,因为后者会忽略本题所要统计的特殊符号。
【解答】
满足题意的程序如下所示:
#include <iostream>
using namespace std;
int main()
{
unsigned int aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0;
unsigned int spaceCnt = 0, tabCnt = 0, newlineCnt = 0;
char ch;
cout << "请输入一段文本:" << endl;
while(cin >> ch)
{cout << "ch==========" << ch << endl;
switch(ch)
{
case 'a':
case 'A':
++aCnt;
break;
case 'e':
case 'E':
++eCnt;
break;
case 'i':
case 'I':
++eCnt;
break;
case 'o':
case 'O':
++oCnt;
break;
case 'u':
case 'U':
++uCnt;
break;
case ' ':
++spaceCnt;
break;
case '\t':
++tabCnt;
break;
case '\n':
++newlineCnt;
break;
default:
break;
}
}
cout << "元音字母 a 的数量是:" << aCnt << endl;
cout << "元音字母 e 的数量是:" << eCnt << endl;
cout << "元音字母 i 的数量是:" << iCnt << endl;
cout << "元音字母 o 的数量是:" << oCnt << endl;
cout << "元音字母 u 的数量是:" << uCnt << endl;
cout << "空格的数量是:" << spaceCnt << endl;
cout << "制表符的数量是:" << tabCnt << endl;
cout << "换行符的数量是:" << newlineCnt << endl;
return 0;
}
练习5.12:修改统计元音字母的程序,使其能统计以下含有两个字符的字符序列的数量:ff、fl和fi。
【出题思路】
为了统计字符序列的情况,必须记录前一个字符的内容。
【解答】
我们的设定是一个字符只会被统计一次。如果用户输入的序列是xxxxxfflxxx,则统计结果是ff:1次、fl:0次、fi:0次。如果用户输入的序列是xxxxxfiffffflxxx,则统计结果是ff:2次、fl:1次、fi:1次。满足题意的程序如下所示:
#include <iostream>
using namespace std;
int main()
{
unsigned int ffCnt = 0, flCnt = 0, fiCnt = 0;
char ch, prech = '\0';
cout << "请输入一段文本:" << endl;
while(cin >> ch)
{
bool b1 = true;
if('f' == prech)
{
switch(ch)
{
case 'f':
++ffCnt;
break;
case 'l':
++flCnt;
break;
case 'i':
++fiCnt;
break;
}
}
if(!b1)
prech = '\t';
else
prech = ch;
}
cout << "ff的数量是:" << ffCnt << endl;
cout << "fl的数量是:" << flCnt << endl;
cout << "fi的数量是:" << fiCnt << endl;
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;
}
【出题思路】
switch语句有几个语法要点:必须在必要的地方使用break;语句,应该把变量定义在块作用域内,case标签只能有一个值且不能是变量。
【解答】
(a)的错误是在每个case分支中都缺少了break;语句,造成的后果是一旦执行了前面的case分支,必定还会继续执行接下来的其他case分支。举例说明,如果ch的内容是字符'a',则aCnt、eCnt和iouCnt的值都会增加;如果ch的内容是字符'e',则eCnt和iouCnt的值都会增加,这显然与程序的预期是不相符的。修改后的程序如下所示:
unsigned aCnt = 0, eCnt = 0, iouCnt = 0;
char ch = next_text();
switch(ch){
case 'a':
aCnt++;
break;
case 'e':
eCnt++;
break;
default:
iouCnt++;
break;
}
(b)的错误是在case分支中定义并初始化了变量ix,同时在default分支中使用了该变量,此时如果控制流跳过case分支而直接到达default分支,则会试图使用未经初始化的变量,因而该程序无法通过编译。解决办法是,把ix的定义放置在switch语句之前。修改后的程序如下所示:unsigned index = some_value();
int ix;
switch(index){
case 1:
ix = get_value();
ivec[ix] = index;
break;
default:
ix = ivec.size() - 1;
ivec[ix] = index;
(c)的错误是在同一个case标签中放置了多个值,而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标签的内容,C++规定,case标签的内容只能是整型常量表达式。修改后的程序如下所示:
const 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;
}