编译软件为 vs2015。
什么是空语句?什么时候会用到空语句?
解答:
只含有一个单独的分号的语句就是空语句。如果在程序的某个地方,语法上需要一条语句但是逻辑上不需要,此时应该使用空语句。
什么是块?什么时候会用到块?
解答:
复合语句也被称作块,是指用花括号括起来的(可能为空的)语句和声明的序列。如果在程序的某个地方,语法上需要一条语句,但是逻辑上需要多条语句,就会用到块。
使用逗号运算符(参见 4.10 节,第 140 页)重写 1.4.1 节(第 10 页)的 while 循环,使它不再需要块,观察改写之后的代码的可读性提高了还是降低了。
解答:
#include "stdafx.h"
#include
using std::cout;
using std::endl;
int main()
{
int sum = 0, val = 1;
//只要 val 的值小于 1, while 循环的值就会持续执行
while (val <= 10)
sum += val, ++val;
cout << "Sum of 1 to 10 inclusive is " << sum << endl;
return 0;
}
用逗号运算符分隔开块内的各条语句,以不再需要块。但这种改写方式降低了代码的可读性,同时逗号运算符总是输出右侧的运算结果,在本程序中虽然没有影响,但不保证这种方式会在其他程序中有丢失数据的风险。
说明下列例子的含义,如果存在问题,试着修改它。
(a)while (string::iterator iter != s.end){ /*......*/ }
(b)while (bool status = find(word)){ /*......*/ }
if ( !status ){ /*......*/ }
解答:
(a)迭代器 iter 没有初始化,修改:while (string::iterator iter = s.begin(), iter != s.end()){ /*......*/ };
(b)定义在控制结构当中的变量旨在相应语句的内部可见,一旦语句结束,变量就超出作用范围。此时 status 在 if 语句中相当于未定义的变量,修改:while (bool status = find(word)){ /*......*/ ; if ( !status ){ /*......*/ } }//将 if 语句放在 while 循环中。
写一段自己的程序,使用 if else 语句实现把数字成绩转换成字母成绩的要求。
解答:
#include "stdafx.h"
#include
#include
#include
using std::string;
using std::vector;
using std::cin;
using std::cout;
using std::endl;
int main()
{
int grade = 0;
const vector vec = { "F","D","C","B","A","A++" };
cout << " please input your grade: " << endl;
while (cin >> grade) {
string final;
if (grade < 60)
final = vec[0];
else {
final = vec[(grade - 50) / 10];
if (grade != 100) { //注意100除以10余数为0但要避免在其后面添加减号
if (grade % 10 >= 3) {
if (grade % 10 > 7)
final += "+";
}
else
final += "-";
}
}
cout << final << endl;
cout << " please input your grade: " << endl;
}
return 0;
}
检验结果:
改写上一题的程序,使用条件运算符(参见第 4.7 节,第 134 页)代替 if else 语句。
解答:
#include "stdafx.h"
#include
#include
#include
using std::cin;
using std::cout;
using std::endl;
using std::string;
using std::vector;
int main()
{
int grade = 0;
const vector vec = { "F","D","C","B","A","A++" };
string final;
cout << " please input your grade: " << endl;
while (cin >> grade) {
final = grade < 60 ? vec[0] ://判断分数段是否小于 60
(grade == 100) ? vec[(grade - 50) / 10] :
(grade % 10 > 7) ? (vec[(grade - 50) / 10] + "+"):
(grade % 10 < 3) ? (vec[(grade - 50) / 10] + "-"):
vec[(grade - 50) / 10];
cout << final << endl;
cout << " please input your grade: " << endl;
}
return 0;
}
验证结果:
改正下列代码段中的错误。
(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)第二行没有加分号。
修改:if ( ival1 != ival2 )
ival1 = ival2;
else ival1 = ival2 = 0;
(b)if 中包含多条语句,需要用花括号括起来,容易产生歧义。
修改: if ( ival < minval ) {
minval = ival;
occurs = 1;}
(c)在第二条 if 语句中,变量 ival 是指未定义的,需要在条件语句外定义 ival,使其作用范围为整个程序。
修改:int ival;
if ( int ival ) = get_value() )
cout << "ival = " << ival << endl;
if ( !ival )
cout << "ival = 0\n";
(d)判断是否相等运算符为 "==",此处使用的是赋值运算符,条件语句的执行结果永远是 false。
修改:if ( ival == 0)
ival = get_value( );
什么是“悬垂 else”?C++ 语言是如何处理 else 子句的?
解答:
当 if 语句内部嵌套多个 if 语句时,很可能 if 分支多于 else 分支,如何确定给定的 else 与某个 if 匹配成为悬垂 else。C++ 中规定 else 与其相邻最近的未匹配的 if 匹配,消除了程序的二义性。
编写一段程序,使用一系列 if 语句统计从 cin 读入的文本中有多少元音字母。
解答:
#include "stdafx.h"
#include
#include
using std::cin;
using std::cout;
using std::endl;
int main()
{
char ch;
unsigned acnt = 0, ecnt = 0, icnt = 0, ocnt = 0, ucnt = 0;
cout << "Please input words: " << endl;
while (cin >> ch) {
if (ch == 'a')
++acnt;
if (ch == 'e')
++ecnt;
if (ch == 'i')
++icnt;
if (ch == 'o')
++ocnt;
if (ch == 'u')
++ucnt;
}
cout << "Number of vowel a: \t" << acnt << endl;
cout << "Number of vowel e: \t" << ecnt << endl;
cout << "Number of vowel i: \t" << icnt << endl;
cout << "Number of vowel o: \t" << ocnt << endl;
cout << "Number of vowel u: \t" << ucnt << endl;
return 0;
}
我们之前实现的统计元音字母的程序存在一个问题:如果元音字母以大写形式出现,不会被统计在内。编写一段程序,统计元音字母的小写形式,也统计大写形式,也就是说,新程序遇到 'a' 和 'A' 都应该递增 acnt 的值,以此类推。
解答:
#include "stdafx.h"
#include
using std::cin;
using std::cout;
using std::endl;
int main()
{
char ch;
unsigned acnt = 0, ecnt = 0, icnt = 0, ocnt = 0, ucnt = 0;
cout << "please input your words: " << 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 << "Number of vowel a or A: \t" << acnt << endl;
cout << "Number of vowel e or E: \t" << ecnt << endl;
cout << "Number of vowel i or I: \t" << icnt << endl;
cout << "Number of vowel o or O: \t" << ocnt << endl;
cout << "Number of vowel u or U: \t" << ucnt << endl;
return 0;
}
修改统计元音字母的程序,使其也能统计空格、制表符和换行符的数量。
解答:
#include "stdafx.h"
#include
using std::cin;
using std::cout;
using std::endl;
int main()
{
unsigned acnt = 0, ecnt = 0, icnt = 0, ocnt = 0, ucnt = 0;
unsigned kcnt = 0, zcnt = 0, hcnt = 0;//分别表示换行符、制表符、空格的数量
char ch;
cout << "Please input your words: " << endl;
while (cin >> std::noskipws >> 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 ' ':
++kcnt;
break;
case '\t':
++zcnt;
break;
case '\n':
++hcnt;
break;
}
}
cout << "Number of vowel a or A: \t" << acnt << endl;
cout << "Number of vowel e or E: \t" << ecnt << endl;
cout << "Number of vowel i or I: \t" << icnt << endl;
cout << "Number of vowel o or O: \t" << ocnt << endl;
cout << "Number of vowel u or U: \t" << ucnt << endl;
cout << "Number of spaces: \t" << kcnt << endl;
cout << "Number of tabs: \t" << zcnt << endl;
cout << "Number of line breaks:\t" << hcnt << endl;
return 0;
}
修改统计元音字母的程序,使其能统计以下含有两个字符的字符序列的数量:ff 、fl 和 fi。
解答:
#include
using std::cin;
using std::cout;
using std::endl;
int main()
{
unsigned acnt = 0, ecnt = 0, icnt = 0, ocnt = 0, ucnt = 0;
unsigned kcnt = 0, zcnt = 0, hcnt = 0;//分别表示换行符、制表符、空格的数量
unsigned ffcnt = 0, flcnt = 0, ficnt = 0;
char ch;
char cc = '\0';
cout << "Please input your words: " << endl;
while (cin >> std::noskipws >> ch) { //表示不忽而略输入中的空格
switch (ch) {
case 'a':
case 'A':
++acnt;
break;
case 'e':
case 'E':
++ecnt;
break;
case 'i':
case 'I':
++icnt;
if (cc == 'f')
++ficnt;
break;
case 'o':
case 'O':
++ocnt;
break;
case 'u':
case 'U':
++ucnt;
break;
case ' ':
++kcnt;
break;
case '\t':
++zcnt;
break;
case '\n':
++hcnt;
break;
case 'f':
if (cc == 'f')
++ffcnt;
break;
case 'l':
if (cc == 'f')
++flcnt;
break;
}
cc = ch;
}
cout << "Number of vowel a or A: \t" << acnt << endl;
cout << "Number of vowel e or E: \t" << ecnt << endl;
cout << "Number of vowel i or I: \t" << icnt << endl;
cout << "Number of vowel o or O: \t" << ocnt << endl;
cout << "Number of vowel u or U: \t" << ucnt << endl;
cout << "Number of spaces: \t" << kcnt << endl;
cout << "Number of tabs: \t" << zcnt << endl;
cout << "Number of line breaks:\t" << hcnt << endl;
cout << "Number of ff:\t" << ffcnt << endl;
cout << "Number of fl:\t" << flcnt << endl;
cout << "Number of fi:\t" << ficnt << endl;
return 0;
}
下面显示的每个程序都含有一个常见的编程错误,指出错误在哪里,然后修改它们。
(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 语句,程序将会依次执行 aCnt++,eCnt++,应分别加上 break 语句。
(b)ix 是在 case 1 中定义的,作用范围仅为 case 1 作用域,下面的 ix 是未定义的,应该在 switch 语句前加上对 ix 的定义 int ix;。
(c)case 关键字应对应一个值,不可以将1,3,5....写在一起,正确写法 case1,case3,case5....以此类推。
(d)case 标签必须是整型常量表达式。ival,jval,kval 均为变量。应在 unsigned 前加上const,或直接写 case+对应数字,如 case 512 等,不用将值赋予变量使用。
编写一段程序,从标准输入中读取若干 string 对象并查找连续重复出现的单词。所谓连续重复出现的意思是:一个单词后面紧跟着这个单词本身要求记录连续重复出现的最大次数以及对应的单词。如果这样的单词存在,输出重复出现的最大次数,如果不存在,输出一条信息说明任何单词都没有连续出现过。例如,如果输入是 how now now now brown cow cow 那么输出应该表明单词 now 连续出现了 3 次。
解答:
#include "stdafx.h"
#include
#include
using std::string;
using std::cin;
using std::cout;
using std::endl;
int main()
{
cout << "Please input your words: " << endl;
string word, str, repeated_w;
int cnt = 0, repeated_t = 0;
while (cin >> word) {
if (word == str)//如果有重复出现的单词,计数器加一
++cnt;
else {
str = word;//如果单词不重复,将下一个单词赋值给 Word 继续判断
cnt = 1; //即使单词不重复,其出现的次数也应该为1,而不是0
}
if (repeated_t < cnt) {
repeated_t = cnt;//找出重复次数最大值
repeated_w = str;//找出赌赢的重复次数最大的单词
}
}
if (repeated_t == 1)//最大重复次数为1时,说明输入中没有单词重复
cout << " There are no repeated words " << endl;
else
cout << "word: " << repeated_w << " repeated " << repeated_t << " times " << endl;
return 0;
}
*(此程序存在一个问题,当输入中出现多个单词具有相同的最大重复次数时,程序只会输出第一个单词,而不能全部输出)
说明下列循环的含义并改正其中的错误。
(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) 含义:在 for 循环中,定义并初始化 ix,ix 不等于 sz 为条件,ix 递增。错误:ix 定义在 for 循环中,其作用范围在 for 循环中,下一条 if 语句中的 ix 是未定义的,修改:将 int ix = 0 写在循环体外。
(b)含义:定义变量 ix ,循环中,ix 不等于 sz,ix 递增。错误:在传统的 for 语句中,即使省略了声明变量的过程,也要保留逗号。修改:for ( ;ix != sz;++ix ){ /*......*/ }
(c)含义:在 for 循环中,定义并初始化 ix,ix 不等于 sz 为条件,ix 递增,sz 递增。错误:条件部分要么一直为 false,要么一直为 true,修改:去掉 ++sz。
while 循环特别适用于那种条件保持不变、反复执行操作的情况,例如,当未达到文件末尾时不断读取下一个值。for 循环则更像是在按步骤迭代,它的索引值在某个范围内依次变化。根据每种循环的习惯用法各自编写一段程序,然后分别用另一种循环改写。如果只能使用一种循环,你倾向于哪种呢?为什么?
解答:
#include "stdafx.h"
#include
using std::cin;
using std::cout;
using std::endl;
int main()
{
//while 循环:
int i = 0;
while (cin >> i) {
cout << "i+1:" << i + 1 << endl;
}
//用 for 循环改写:
for (int i; cin >> i;) {
cout << "i+1:" << i + 1 << endl;
}
//for 循环:
for (int i = 0; i <= 10; ++i) {
cout << i << endl;
}
//用 while 循环改写:
int i = 0;
while (i <= 10) {
cout << i << endl;
++i;
}
return 0;
}
我更喜欢 while 循环,因为其条件部分更为直观简洁,for 循环的语句头定义容易出现错误,其次使用 while 循环时也不用考虑其迭代次数,在处理大量的数据时,程序员编写程序错误的概率小一些。
假设有两个包含整数的 vector 对象,编写一段程序,检验其中一个 vector 对象是否是另一个的前缀。为了实现这一目标,对于两个不等长的 vector 对象,只需挑出长度较短的那个,把它的所有元素和另一个 vector 对象比较即可。例如,如果两个 vector 对象的元素分别是 0、1、1、2 和 0、1、1、2、3、5、8,则程序的返回结果应该为真。
解答:
#include "stdafx.h"
#include
#include
using std::cout;
using std::endl;
using std::vector;
int main()
{
vector v1 = { 0,1,1,2 };
vector v2 = { 0,1,1,2,3,5,8 };
int k = 0, size = 0;
auto beg1 = v1.begin();
auto beg2 = v2.begin();
for (; beg1 != v1.end() && beg2 != v2.end(); ++beg1, ++beg2) {
if (*beg1 == *beg2)//迭代器判断所指对象是否相等
++k;
}
if (v1.size() <= v2.size())
size = v1.size();
else
size = v2.size();
if (k == size) {
if (size == v1.size())//判断谁是谁的前缀
cout << "yes, v1 is a prefix for v2 " << endl;
else
cout << "yes, v2 is a prefix for v1 " << endl;
}
else
cout << "no, no prefix " << endl;
return 0;
}
说明下列循环的含义并改正其中的错误。
(a)do
int v1,v2;
cout << "please enter two numbers to sum:";
if (cin >> v1 >> v2)
cout << "sum is:" << v1 + v2 <
while(cin);
(b)do{
//......}
while (int ival = get_response());
(c)do{
int ival = get_response();}
while (ival);
解答:
(a)do 中有多条语句,需要用花括号括起来。含义:只要输入两个数值就计算他们的和。
(b)变量的定义放在了条件部分是不允许的,应避免出现先使用变量后定义的行为,将 int ival = get_response() 放在 循环体之外。
(c)在 do 中定义的变量作用范围是 do 的语句块,while 中无法访问。若要使用,应将变量定义在循环体外。
编写一段程序,使用 do while 循环重复地执行下述任务:首先提示用户输入两个 string 对象,然后挑出较短的那个并输出它。
解答:
#include "stdafx.h"
#include
#include
using std::cin;
using std::cout;
using std::endl;
using std::string;
int main()
{
string s1, s2, str;
do {
cout << "Please input two words: " << endl;
cin >> s1 >> s2;
if (s1.size() == s2.size())
cout << "The length of two word is equal! " << endl;
else {
str = s1.size() > s2.size() ? s2 : s1;
cout << "the shorter one is: " << str << endl;
}
} while (cin);
return 0;
}
编写一段程序,从标准输入中读取 string 对象的序列直到连续出现两个相同的单词或者所有的单词都读完为止。使用 while 循环一次读取一个单词,当一个单词连续出现两次时使用 break 语句终止循环。输出连续重复的单词,或者输出一个消息说明没有任何单词是连续重复出现的。
解答:
#include "stdafx.h"
#include
#include
using std::cin;
using std::cout;
using std::endl;
using std::string;
int main()
{
string word, str;
cout << "Please input your words: " << endl;
while (cin >> word) {
if (word == str){
cout << "repeated word:\t" << word << endl;
break;//遇到连续的 string 对象终止循环
}
else
str = word;
}
if (cin.eof())//若 string 对象输入结束
cout << "no word was repeated." << endl;
return 0;
}
修改 5.5.1 节(第 171 页)练习题的程序,使其找到的重复单词必须以大写的字母开头。
解答:
#include "stdafx.h"
#include
#include
using std::cin;
using std::cout;
using std::endl;
using std::string;
int main()
{
string word, str;
cout << "Please input your words: " << endl;
while (cin >> word) {
//if (!isupper(word[0]))//判断单词的第一个字母是否为大写字母
//continue;
if (word == str && isupper(word[0])) { //输入的单词重复且开头大写
cout << "repeated word:\t" << word << endl;
break;//遇到连续的 string 对象终止循环
}
else
str = word;
}
if (cin.eof())//若 string 对象输入结束
cout << "no word was repeated." << endl;
return 0;
}
本节的最后一个例子跳回到 begin,其实使用循环能更好地完成该任务。重写这段代码。注意不再使用 goto 语句。
解答:
while(1) {
int sz = get_size();
if (sz <= 0)
continue;
}
编写一段程序,从标准输入中读取两个整数,输出第一个数除以第二个数的结果。
解答:
#include "stdafx.h"
#include
using std::cin;
using std::cout;
using std::endl;
int main()
{
cout << "please input two numbers: " << endl;
int a1 = 0, a2 = 0;
cin >> a1 >> a2;
cout << static_cast(a1) / a2 << endl;//用到前面学过的显示转换
return 0;
}
修改你的程序,使得当第二个数是 0 时抛出异常。先不要设定 catch 子句,运行程序并真的为除数输入 0,看看会发生什么?
解答:
#include "stdafx.h"
#include
#include
using std::runtime_error;
using std::cin;
using std::cout;
using std::endl;
int main()
{
cout << "please input two numbers: " << endl;
int a1 = 0, a2 = 0;
cin >> a1 >> a2;
if (a2 == 0)
throw runtime_error("0 can't be used as a divisor!");//runtime_error 定义在stdexcept头文件中
cout << static_cast(a1) / a2 << endl;//用到前面学过的显示转换
return 0;
}
出现的情况,程序终止并提示 debug error。
修改上一题的程序,使用 try 语句块去捕获异常。catch 子句应该为用户输出一条提示信息,询问其是否输入新数并重新执行 try 语句块的内容。
解答:
#include "stdafx.h"
#include
#include
using std::runtime_error;
using std::cin;
using std::cout;
using std::endl;
int main()
{
cout << "please input two numbers: " << endl;
int a1 = 0, a2 = 0;
while (cin >> a1 >> a2) {
try {
if (a2 == 0)
throw runtime_error("0 can't be used as a divisor!");
//runtime_error 定义在stdexcept头文件中
cout << static_cast(a1) / a2 << endl;//用到前面学过的显示转换
cout << "please input two numbers: " << endl;
}
catch (runtime_error err) {
cout << err.what() << " \nTry again? Enter y or n " << endl;
char c;
cin >> c;
if (!cin || c == 'n')//如果不输入或者输入 n
break;//结束当前循环
}
}
return 0;
}