C++ Primer 习题(第五章附答案)

练习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=0while (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;
}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值