练习5.1 什么是空语句?什么时候会用到空语句?
空语句是最简单的语句,空语句由一个单独的分号构成。如果在程序的某个地方,语法上需要
一条语句但是逻辑上不需要,此时应该使用空语句,空语句什么也不做。
一种常见的情况是,当循环的全部工作在条件部分就可以完成时,我们通常会用到空语句。使用
空语句时最好加上注释,从而令代码的阅读者知道这条语句是有意省略内容的。
练习5.2 什么是块?什么时候会用到块?
块是指用花括号括起来的语句和声明的序列,也称为复合语句。一个块就是一个作用域,在
块中引入的名字只能在块内部以及嵌套在块中的子块里访问。如果在程序的某个地方,语法上
需要一条语句,但是逻辑上需要多条语句,此时应该使用块。块不需要以分号结束。
练习5.3 使用逗号运算符重写1.4.1节的while循环,使它不在需要块,观察改写之后的代码可读性提高了还是降低了
while(val<+10)
sum+=val,++val;
练习5.4 说明下列例子的含义,如果存在问题,试着修改它。
(a)while(string::iterator iter!=s.end()){/*...*/}
(b)while(bool status = find(word)){/*...*/}
if(!status){/*...*/}
(a)非法,原意while语句的控制结构当中定义一个string::itertor类型的变量iter,然后判断
iter是否达到了s的末尾,只要未到就执行循环。但该式把变量的定义和关系混合在了一起,如果
要使用iter与其他值比较,必须为iter赋初值
string::iterator iter = s.begin();
while (iter !=s.end())
{
++iter;
/*...*/
}
(b)非法,变量status定义在while循环控制结构的内部,其作用域仅限于while循环。if语句已
经位于while循环的作用域之外,status在if语句内是一个未命名的无效变量。要想在if语句中
继续使用status,需要把它定义在while循环之前。
bool status;
while (status = find(word)){/*...*/}
if (!status){/*...*/}
练习5.5 写一段自己的程序,使用if—else语句实现把数字成绩转换成字面成绩的要求。
#include<iostream>
using namespace std;
int main()
{
int grade;
cout << "please enter your grade" << endl;
cin >> grade;
if (grade < 0 || grade>100)
{
cout << "the grade is illegal" << endl;
return -1;
}
else if (grade == 100) //处理满分
{
cout << "the grade is A++" << endl;
return -1;
}
else if (grade < 60) //处理不及格
{
cout << "the grade is F" << endl;
return -1;
}
int iu = grade / 10; //成绩的十位数
int it = grade % 10; //成绩的个位数
string score, level, lettergrade;
//根据成绩的十位数字确定score
if (iu == 9)
{
score = "A";
}
else if (iu == 8)
{
score = "B";
}
else if (iu == 7)
{
score = "c";
}
else
score = "D";
//根据成绩个位数字确定level
if (it < 3)
{
level = "-";
}
else if (it > 7)
{
level = "+";
}
else
{
level = "";
}
//累加求得等级成绩
lettergrade = score + level;
cout << "the grade is:" << lettergrade << endl;
return 0;
}
练习5.6 改写上一题的程序,使用条件运算符代替if-else语句。
#include<iostream>
using namespace std;
int main()
{
int grade;
cout << "please enter your grade" << endl;
cin >> grade;
if (grade < 0 || grade>100)
{
cout << "the grade is illegal" << endl;
return -1;
}
else if (grade == 100) //处理满分
{
cout << "the grade is A++" << endl;
return -1;
}
else if (grade < 60) //处理不及格
{
cout << "the grade is F" << endl;
return -1;
}
int iu = grade / 10; //成绩的十位数
int it = grade % 10; //成绩的个位数
string score, level, lettergrade;
//根据成绩的十位数字确定score
score = (iu == 9) ? "A"
: (iu == 8) ? "B"
: (iu == 7) ? "C" : "D";
//根据成绩个位数字确定level
level = (it < 3) ? "-"
: (it > 7) ? "+" : "";
//累加求得等级成绩
lettergrade = score + level;
cout << "the grade is:" << 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)
int ival;
if (ival = get_value())
cout << "ival = " << ival << endl;
if (!ival)
cout << "ival = 0\n";
//(b)
if (ival == 0)
ival = get_value();
练习5.8 什么是“悬垂else”?C++语言是如何处理else子句的?
悬垂else是指当程序中的if分支多于else分支时,如何为else寻找与之匹配的if分支的问题
c++规定,else与离它最近的尚未分配的if匹配,从而消除了二次性。
练习5.9 编写一段程序,使用一系列if语句统计从cin读入的文本中有多少元音字母
#include<iostream>
using namespace std;
int main()
{
unsigned int vowelcnt = 0;
char ch;
cout << "please enter a text" << endl;
while (cin>>ch)
{
if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
++vowelcnt;
}
cout << "in your text you entered have " << vowelcnt << " vowelcent" << endl;
return 0;
}
练习5.10 我们之前实现的统计元音字母的程序存在一个问题:如果元音字母以大写形式出现,不会被统计在内。编写一段程序,即统计元音字母的小写形式,也统计大写形式,也就是说,新程序遇到‘a’和‘A’都应该递增acnt的值,依次类推。
#include<iostream>
using namespace std;
int main()
{
unsigned int acnt = 0, ecnt = 0, icnt = 0, ocnt = 0, ucnt = 0;
char ch;
cout << "please enter a text " << endl;
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 << "the number of a is " << acnt << endl;
cout << "the number of e is " << ecnt << endl;
cout << "the number of i is " << icnt << endl;
cout << "the number of o is " << ocnt << endl;
cout << "the number of u is " << ucnt << endl;
return 0;
}
5.11 修改统计元音字母的程序,使其也能统计空格,制符表和换行符的数量
#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 << "please enter a text " << endl;
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' ':
++spacecnt;
break;
case'\t':
++tabcnt;
break;
case'\n':
++newlinecnt;
break;
}
}
cout << "the number of a is " << acnt << endl;
cout << "the number of e is " << ecnt << endl;
cout << "the number of i is " << icnt << endl;
cout << "the number of o is " << ocnt << endl;
cout << "the number of u is " << ucnt << endl;
cout << "the number of space is " << spacecnt << endl;
cout << "the number of tab is " << tabcnt << endl;
cout << "the number of newline is " << newlinecnt << endl;
return 0;
}
5.12 修改统计元音字母的程序,使其能统计以下含有两个字符的字符串列的数量:ff,f1和fi
#include<iostream>
using namespace std;
int main()
{
unsigned int ffcnt = 0, flcnt = 0, ficnt = 0;
char ch, prech = '\0';
cout << "please enter a text" << endl;
while (cin>>ch)
{
bool bl = true;
if (prech == 'f')
{
switch (ch)
{
case'f':
++ffcnt;
bl = false;
break;
case'l':
++flcnt;
bl = false;
break;
case'i':
++ficnt;
bl = false;
break;
}
}
if (!bl)
{
prech = '\0';
}
else
{
prech = ch;
}
}
cout << "the number of ff is " << ffcnt << endl;
cout << "the number of fl is " << flcnt << endl;
cout << "the number of fi is " << ficnt << endl;
return 0;
}
练习5.13 下面显示的每个程序都含有一个常见的编程错误,指出错误在哪里,然后修改它们
//(a)
#include<iostream>
using namespace std;
int main()
{
unsigned int acnt = 0, ecnt = 0, ioucnt = 0;
char ch = new_text();
switch (ch)
{
case'a':
acnt++;
break; //每个分支都缺少break语句
case'e':
ecnt++;
break;
default:
ioucnt++;
break;
}
return 0;
}
//(b)
unsigned index = some_value();
int ix; //ix需要定义在switch语句之前
switch (index)
{
case 1:
ix = get_value();
ivec[ix] = index;
break;
default:
ix = ivec.size() - 1;
ivec[ix] = index;
break;
//(c)
unsigned evencnt = 0, oddcnt = 0;
int digit = get_num() % 10;
switch (digit)
{
case 1: //c++g规定一个case标签只能对应一个值
case 3:
case 5:
case 7:
case 9:
oddcnt++;
break;
case 2:
case 4:
case 6:
case 8:
case 10:
evencnt++;
break;
}
//(d)
const unsigned ival = 512, jval = 1024, kval = 4096;
unsigned bufsize;
unsigned swt = get_bufcnt();
switch (swt)
{
//c++规定,case标签的内容只能是整型常量表达式
case ival:
bufsize = ival * sizeof(int);
break;
case jval:
bufsize = jval * sizeof(int);
break;
case kval:
bufsize = kval * sizeof(int);
break;
}
练习5.14:编写一段程序,从标准输入中读取若干string对象并查找连续重复的单词。所谓连续重复出现的意思是:一个单词后面紧跟这个单词本身。要求记录重复出现的最大次数以及对应的单词。如果这样的单词存在,输出重复出现的最大次数;如果不存在,输出一条信息说明任何单词都没有连续出现过。
#include<iostream>
#include<string>
using namespace std;
int main()
{
//定义三个字符串变量,分别表示
//当前操作的字符串,前一个字符串,当前出现次数最多的字符串
string currstring, prestring = "", maxstring;
//定义两个整型变量,分别表示:
//当前连续出现的字符串数量,当前出现次数最多的字符串数量
int currcnt = 1, maxcnt = 0;
while (cin >> currstring) //检查每个字符串
{
//如果当前字符串与前一个字符串一致,更新状态
if (currstring == prestring)
{
++currcnt;
if (currcnt > maxcnt)
{
maxcnt = currcnt;
maxstring = currstring;
}
}
//如果当前字符串与前一个字符串不一致,重置currcnt
else
{
currcnt = 1;
}
//更新prestring以便于下一次循环使用
prestring = currstring;
}
if (maxcnt > 1)
{
cout << "出现最多的字符串是:" << maxstring << ",次数是:" << maxcnt << endl;
}
else
{
cout << "每个字符串都只出现了一次" << endl;
}
return 0;
}
练习5.15:说明下列循环的含义并改正其中的错误
int ix; //ix定义在for语句内部,所以其作用域仅限于for语句。在if语句中ix已经失效,因此程序无法编译通过
for (ix = 0; ix != sz; ++ix) {/*...*/ }
if (ix != sz)
//...
int ix;
for(ix = 0;ix!=sz;++ix){/*...*/ }
//两处错误,一是变量ix未经初始化就直接使用,
//二是for语句的控制结构缺少一句话,在语法上是错误的
for(int ix = 0;ix!=sz;++ix){/*...*/ }
//当初始情况下ix!=sz时,由题意可以ix和sz一直同步增长,循环的终止条件不会满足,所以该循环是一个死循环
练习5.16:while循环特别适用于那种保持不变,反复执行操作的情况,例如,当未达到文件末尾时不断读取下一个值。for循环则更像是在按步骤迭代,它的索引值在某个范围内依次变化。根据每种循环的习惯用法各自编写一段程序,然后分别用另一种循环改写。如果只能使用一种循环,你倾向于使用哪种?为什么?
//从标准输入流读取数据的程序一般使用while循环,其形式是:
char ch;
while (cin >> ch)
{
/*....*/
}
//因为这项功能事实上不太要求我们严格跟踪循环变量的变化过程,所以改写成for循环后稍显冗余
for (; cin >> ch; )
{
/*...*/
}
//上面for循环控制结构中,第一条语句和第三条语句都是空语句,额外添加一个循环控制变量(比如int i)是没有意义的
//整数累加求和的程序一般使用for循环,其形式是:
int icount = 0;
for (int i = 0; i < 10; ++i)
{
icout += i;
}
//使用while循环改写后的形式是:
int icount = 0,i=0;
while (i < 10)
{
icount += i;
++i;
}
//在大多数情况下,两种循环试试可以相互转换
练习5.17:假设有两个包含整数的vector对象,编写一段程序,检验其中一个vector对象是否是另一个的前缀。为了实现这一目标,对于两个不等长的vector对象,只需挑出长度较短的那个,把它的所有元素和另一个vector对象比较即可。例如,如果两个vector对象的元素分别是0,1,1,2和0,1,1,2,3,5,8,则程序的返回结果应该为真。
#include<iostream>
#include<vector>
using namespace std;
int main()
{
vector<int>v1 = { 0,1,1,2 };
vector<int>v2 = { 0,1,1,2,3,5,8 };
vector<int>v3 = { 3,5,8 };
vector<int>v4 = { 3,5,0,9,2,7};
auto it1 = v1.cbegin(); //定义v1的迭代器
auto it2 = v2.cbegin(); //定义v2的迭代器
auto it3 = v3.cbegin(); //定义v3的迭代器
auto it4 = v4.cbegin(); //定义v4的迭代器
//设定循环条件:v1和v2都尚未检查完
while (it1 != v1.cend() && it2 != v2.cend())
{
//如果当前位置的两个元素不相等,则肯定没有前缀关系,退出循环
if (*it1 != *it2)
{
cout << "v1和v2之间不存在前缀关系" << endl;
break;
}
++it1; //迭代器移动到下一个元素
++it2; //迭代器移动到下一个元素
}
if (it1 == v1.cend())
{
cout << "v1是v2的前缀" << endl;
}
if (it2 == v2.cend())
{
cout << "v2是v1的前缀" << endl;
}
return 0;
}
练习5.18:说明下列循环的含义并改正其中的错误
//do-while语句的循环体必须是一条语句或者一个语句块,所以循环体的内容应该用花括号括起来
do
{
int v1, v2;
cout << "please enter two numbers to sum:";
if (cin >> v1 >> v2)
{
cout << "sum is: " << v1 + v2 << endl;
}
} while (cin);
//do——while语句不允许在循环体内定义变量
int ival;
do
{
ival = get_response();
} while (ival);
//do——while语句条件部分的变量必须定义在循环体之外
int ival;
do
{
ival = get_response();
} while (ival);
练习5.19:编写一段程序,使用do-while循环重复地执行下述任务:首先提示用户输入两个string对象,使用挑出较短的那个并输出它。
#include<iostream>
#include<string>
using namespace std;
int main()
{
do {
cout << "Please enter two strings" << endl;
string str1, str2;
cin >> str1 >> str2;
if (str1.size() < str2.size())
cout << "The shorter string is " << str1 << endl;
else if (str1.size() > str2.size())
{
cout << "The shorter string is " << str2 << endl;
}
else
{
cout << "Two strings are equal in length" << endl;
}
} while (cin);
return 0;
}
练习5.20:编写一段程序,从标准输入中读取string对象的序列直到连续出现两个相同的单词或者所有单词都读完为止。使用while循环一次读取一个单词,当一个单词连续出现两次时使用break语句终止循环。输出连续循环出现的单词,或者输出一个消息说明没有任何单词是连续重复出现的。
#include<iostream>
#include<string>
using namespace std;
int main()
{
string currstring, prestring;
bool bl = true;
cout << "Please enter a string" << endl;
while (cin>>currstring)
{
if (currstring == prestring)
{
bl = false;
cout << "The string that appears consecutively is " << currstring << endl;
break;
}
prestring = currstring;
}
if (bl)
{
cout << "No consecutive strings" << endl;
}
return 0;
}
练习5.21 修改5.5.1节(第171页)练习题的程序,使其找到的重复单词必须以大写字母开头。
#include<iostream>
#include<string>
using namespace std;
int main()
{
string currstring, prestring;
bool bl = true;
cout << "please enter a string" << endl;
while (cin>>currstring)
{
if (!isupper(currstring[0]))
continue;
if (currstring == prestring)
{
bl = false;
cout << "The string that appears consecutively is " << currstring << endl;
break;
}
prestring = currstring;
}
if (bl)
cout << "No consecutive strings" << endl;
return 0;
}
5.22 本节的最后一个例子跳回到begin,其实使用循环能更好地完成该任务。重写这段代码,注意不再使用goto语句。
int sz;
do
{
sz = get_size();
} while (sz<=0);
练习5.23:编写一段程序,从标准输入读取两个整数,输出第一个数除以第二个数的结果。
#include<iostream>
using namespace std;
int main()
{
cout << "Please enter the dividend and the divisor in turn" << endl;
int ival1, ival2;
cin >> ival1 >> ival2;
if (ival2 == 0)
{
cout << "Divisor cannot be zero" << endl;
return -1;
}
cout << "The result of dividing the two numbers is " << ival1 / ival2 << endl;
return 0;
}
练习5.24 修改你的程序,使得当第二个数是0时抛出异常。先不要设定catch字句,运行程序并真的为除数输入0,看看会发生什么?
#include<iostream>
#include<stdexcept>
using namespace std;
int main()
{
cout << "Please enter the dividend and the divisor in turn" << endl;
int ival1, ival2;
cin >> ival1 >> ival2;
if (ival2 == 0)
{
throw runtime_error("Divisor cannot be zero");
}
cout << "The result of dividing the two numbers is " << ival1 / ival2 << endl;
return 0;
}
练习5.25:修改上一题的程序,使用try语句块捕捉异常。catch字句应该为用户输出一条提示信息,询问其是否输入新数并重新执行try语句块的内容。
#include<iostream>
#include<stdexcept>
using namespace std;
int main()
{
cout << "Please enter the dividend and the divisor in turn" << endl;
int ival1, ival2;
while (cin >> ival1 >> ival2)
{
try
{
if (ival2 == 0)
{
throw runtime_error("Divisor cannot be zero");
}
cout << "The result of dividing the two numbers is " << ival1 / ival2 << endl;
}
catch (runtime_error err)
{
cout << err.what() << endl;
cout << "Need to continue(y or n)?";
char ch;
cin >> ch;
if (ch != 'y' && ch != 'Y')
break;
}
}
return 0;
}