《C++ Primer》第5章 语句
5.5节 跳转语句
练习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) { /* ... */ }
【出题思路】
理解for循环的语法规则,特别是for循环控制结构中三条语句的作用。理解循环控制变量与循环终止条件的关系,从而能够判断循环是否会无限执行下去。
【解答】
(a)的错误是在for语句中定义了变量ix,然后试图在for语句之外继续使用ix。因为ix定义在for语句的内部,所以其作用域仅限于for语句。在if语句中ix已经失效,因此程序无法编译通过。修改后的程序如下:
int ix;
for(ix = 0; ix != sz; ++ix) { /* ... */}
if(ix != sz)
// ...
(b)的错误有两个,一是变量ix未经初始化就直接使用,二是for语句的控制结构缺少一句话,在语法上是错误的。修改后的程序如下:
int ix;
for(ix = 0; ix != sz; ++ix) { /* ... */ }
(c)的错误是一旦进入循环,程序就会无休止地执行下去。也就是说,当初始情况下ix != sz时,由题意可知ix和sz一直同步增长,循环的终止条件永远不会满足,所以该循环是一个死循环。修改后的程序如下:
for(int ix = 0; ix != sz; ++ix) { /* ... */ }
练习5.16:while循环特别适用于那种条件保持不变、反复执行操作的情况,例如,当未达到文件末尾时不断读取下一个值。for循环则更像是在按步骤迭代,它的索引值在某个范围内依次变化。根据每种循环的习惯用法各自编写一段程序,然后分别用另一种循环改写。如果只能使用一种循环,你倾向于使用哪种呢?为什么?
【出题思路】
一般情况下,while循环和for循环可以互相转换,不论哪种循环形式关键点都有三个:循环控制变量的初始值、循环控制变量的变化规则、循环终止条件。编写循环语句时除了要满足应用需求,还必须时刻关注循环控制变量和循环终止条件,谨防写出死循环。
【解答】
从标准输入流读取数据的程序一般使用while循环,其形式是:
#include <iostream>
using namespace std;
int main()
{
int forCount = 0;
for(int i = 0; i < 10; ++i)
{
forCount += i;
}
cout << "forCount=============" << forCount << endl;;
int whileCount = 0, j = 0;
while(j < 10)
{
whileCount += j;
++j;
}
cout << "whileCount============" << whileCount << endl;
return 0;
}
运行结果:
练习5.17:假设有两个包含整数的vector对象,编写一段程序,检验其中一个vector对象是否是另一个的前缀。为了实现这一目标,对于两个不等长的vector对象,只需挑出长度较短的那个,把它的所有元素和另一个vector对象比较即可。例如,如果两个vector对象的元素分别是0、1、1、2和0、1、1、2、3、5、8,则程序的返回结果应该为真。
【出题思路】
使用while循环实现两个vector对象的逐元素比较。
【解答】
满足题意的程序如下所示:
#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()) //如果v1较短
{
cout << "v1是v2的前缀" << endl;
}
if(it2 == v2.cend()) //如果v2较短
{
cout << "v2是v1的前缀" << endl;
}
//v3 v4之间不存在前缀关系
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(int ival = get_response());
(c) do {
int ival = get_response();
}while(ival);
【出题思路】
理解do-while循环的语法规则。do-while与while的最主要区别是:do-while语句至少会执行一次循环体;而while有可能一次都不执行循环体。
【解答】
(a)的含义是每次循环读入两个整数并输出它们的和。因为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);
(b)的含义是当get_response的返回值不为0时执行循环体。因为do-while语句不允许在循环条件内定义变量,所以该程序是错误的。修改后的程序是:
int ival;
do {
ival = get_response()
}while(ival);
(c)的含义是当get_response的返回值不为0时执行循环体。因为出现在do-while语句条件部分的变量必须定义在循环体之外,所以该程序是错误的。修改后的程序是:
int ival;
do {
ival = get_response();
}while(ival);
练习5.19:编写一段程序,使用do-while循环重复地执行下述任务:首先提示用户输入两个string对象,然后挑出较短的那个并输出它。
【出题思路】
把题目要求的任务写在do-while循环体中即可,该程序至少会执行一次比较操作。把字符串定义成string对象,调用size函数即可得到string对象的长度。
【解答】
满足题意的程序如下所示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
do{
cout << "请输入两个字符串:" << endl;
string str1, str2;
cin >> str1 >> str2;
if(str1.size() < str2.size())
cout << "长度较小的字符串是:" << str1 << endl;
else if(str1.size() > str2.size())
cout << "长度较小的字符串是:" << str2 << endl;
else
cout << "两个字符串等长" << endl;
}while(cin);
return 0;
}
运行结果:
练习5.20:编写一段程序,从标准输入中读取string对象的序列直到连续出现两个相同的单词或者所有单词都读完为止。使用while循环一次读取一个单词,当一个单词连续出现两次时使用break语句终止循环。输出连续重复出现的单词,或者输出一个消息说明没有任何单词是连续重复出现的。
【出题思路】
break语句是一种跳转语句,负责终止离它最近的while、do-while、for和switch语句,并把程序的控制权交给这些语句之后的第一条语句。
【解答】
满足题意的程序如下所示:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string currString, preString;
bool b1 = true;
cout << "请输入一组字符串:" << endl;
while(cin >> currString)
{
if(currString == preString)
{
b1 = false;
cout << "连续出现的字符串是:" << currString << endl;
break;
}
preString = currString;
}
if(b1)
cout << "没有连续出现的字符串" << endl;
return 0;
}
运行结果:
练习5.21:修改5.5.1节(第171页)练习题的程序,使其找到的重复单词必须以大写字母开头。
【出题思路】
continue语句是一种跳转语句,负责终止最近的循环中的当前迭代并立即开始下一次迭代。与break语句的区别是,continue虽然终止了当前迭代,但是并不终止循环;而break语句则直接跳出循环。
【解答】
根据题目的要求,我们首先检查读入的单词是否以大写字母开头,如果不是则终止当前迭代并开始下一次循环。满足题意的程序是:
#include <iostream>
#include <string>
using namespace std;
int main()
{
string currString, preString;
bool b1 = true;
cout << "请输入一组字符串:" << endl;
while(cin >> currString)
{
if(currString == preString)
{
b1 = false;
cout << "连续出现的字符串是:" << currString << endl;
break;
}
preString = currString;
}
if(b1)
cout << "没有连续出现的字符串" << endl;
return 0;
}
运行结果:
练习5.22:本节的最后一个例子跳回到begin,其实使用循环能更好地完成该任务。重写这段代码,注意不再使用goto语句。
【出题思路】
goto语句的作用是从goto语句无条件跳转到同一函数的另一条语句。但是一般情况下,不建议读者使用goto语句,因为它使得程序既难理解又难修改。
【解答】
用do-while语句改写后的程序如下所示:
int sz;
do{
sz = get_size();
}while(sz <= 0);