What & How & Why

Chapter.5

第五章的习题答案


Ex.5.1-5.10

ex.5.1
Exercise 5.1: What is a null statement? When might you use a null statement?

The null statement is a statement that consists of only a semicolon. It can be used when all you need is something to keep the program running properly. Suppose your program has a loop and the loop can be ended by its condition. In order to ensure correctness, you should put a null statement in the loop.

ex.5.2
Exercise 5.2: What is a block? When might you might use a block?

The block is a set of statements and declarations, enclosed by curly braces. It is used when the logic requires more than a single statement to execute.

ex.5.3
Exercise 5.3: Use the comma operator (§ 4.10, p. 157) to rewrite the while loop from § 1.4.1 (p. 11) so that it no longer requires a block. Explain whether this rewrite improves or diminishes the readability of this code.

#include <iostream>
using std::cin;
using std::cout;
using std::endl;

int main(int argc, char const *argv[])
{
	int sum = 0, val = 1;
	while (sum += val++, val <= 10) {;}
	cout << "Sum of 1 to 10 inclusive is: " << sum << endl;	
	return 0;
}
While the rewriting of the program raises the diminishing, the resulting code becomes difficult to read. In my experience, I rarely saw programmers use comma operation in a loop conditions in order to move logic statements out of a block. In addition, the compound logic statement sum += val++ is also not that easy to read.

ex.5.4
Exercise 5.4: Explain each of the following examples, and correct any problems you detect.

(a) while (string::iterator iter != s.end()) { /* . . . */ }

//The loop is trying to traverse the string s by using iterator but forget to initialize the iterator, and  didn't move the iterator forward in each looping. 

Fix:
string::iterator iter = s.begin();
while (string::iterator iter != s.end()) {++iter; /* . . . */}

(b) while (bool status = find(word)) { /* . . . */ } 
if (!status) { /* . . . */ }

//The condition variable "status" is used for ending the loop, however, is not in the looping block. a value outside of its scope is invalid.

Fix:
while (bool status = find(word)) { if (!status) { /* . . . */ }}

ex.5.5
Exercise 5.5: Using an if–else statement, write your own version of the program to generate the letter grade from a numeric grade.

CODE: Q.1

ex.5.6
Exercise 5.7: Correct the errors in each of the following code fragments:

(a) if (ival1 != ival2)
ival1 = ival2
else ival1 = ival2 = 0;

Fix:
if (ival1 != ival2) {
	ival1 = ival2;
} 
else {
	ival1 = 0;
	ival2 = 0;
}

(b) if (ival < minval)
minval = ival;
occurs = 1;

Fix:
if (ival < minval) {
	minval = ival;
	occurs = 1;
}

(c) if (int ival = get_value())
cout << "ival = " << ival << endl;
if (!ival)
cout << "ival = 0\n";

Fix:
if(int ival = get_value()) {
	cout <<"ival = " << ival << endl;
	if (!val) {
		cpit << "ival = 0\n";
	}
}

(d) if (ival = 0)
ival = get_value();

Fix:
if (ival == 0)
ival = get_value();

ex.5.8
Exercise 5.8: What is a “dangling else”? How are else clauses resolved in C++?

“ Colloquial term used to refer to the problem of how to process nested if statements in which there are more ifs than elses. In C++, an else is always paired with the closest preceding unmatched if.

ex.5.9
Exercise 5.9: Write a program using a series of if statements to count the number of vowels in text read from cin.

CODE: Q.1

ex.5.10
Exercise 5.10: There is one problem with our vowel-counting program as we’ve implemented it: It doesn’t count capital letters as vowels. Write a program that counts both lower- and uppercase letters as the appropriate vowel—that is, your program should count both 'a' and 'A' as part of aCnt, and so forth.

CODE: Q.1

Ex.5.11-5.20

ex.5.11
Exercise 5.11: Modify our vowel-counting program so that it also counts the number of blank spaces, tabs, and newlines read.

CODE: Q.1

ex.5.12
Exercise 5.12: Modify our vowel-counting program so that it counts the number of occurrences of the following two-character sequences: ff, fl, and fi.

Notice: Since the question description is not that accurate, there are two possible situations about to occur when counting the frequencies of fffl and fi:

  • If we only count every letter once, for example, the string iffiffi, there are 3 i and 2 ff s. The program would evaluate the string in this way: i - ff - i - ff - i.
  • if we evaluate those strings as a combination of letters, the program would evaluate the string in this way: i-ff-fi-i-ff-fi-i , 3 i,2fi and 2 ff.

Those two different understandings leads to differernt approches. I have attached two solutions for them. The idea for the second soluation is coming from Pezy's solution.

CODE: Q.1 Q.2

ex.5.13
Exercise 5.13: Each of the programs in the highlighted text on page 184 contains a common programming error. Identify and correct each error.

(a) unsigned aCnt = 0, eCnt = 0, iouCnt = 0;
char ch = next_text();
switch (ch) {
//missing break for each case
case 'a': aCnt++;
case 'e': eCnt++;
default: iouCnt++;
}
Fix:
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) unsigned index = some_value();
switch (index) {
case 1:
int ix = get_value();
ivec[ ix ] = index;
break;
default: //control flow transfer jumps into the variable socpe
ix = ivec.size()-1;
ivec[ ix ] = index;
Fix:
unsigned index = some_value();
switch (index) {
case 1:{
	int ix = get_value();
	ivec[ ix ] = index;
	break;
	}
default:{ 
	int 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: //syntax error for multiple cases
oddcnt++;
break;
case 2, 4, 6, 8, 10:
evencnt++;
break;
Fix
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) unsigned ival=512, jval=1024, kval=4096;
unsigned bufsize;
unsigned swt = get_bufCnt();
switch(swt) {
case ival:
bufsize = ival * sizeof(int); //case label must be a intergal constexpr expression
break;
case jval:
bufsize = jval * sizeof(int);
break;
case kval:
bufsize = kval * sizeof(int);
break;
}
Fix:
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;
}

ex.5.14
Exercise 5.14: Write a program to read strings from standard input looking for duplicated words. The program should find places in the input where one word is followed immediately by itself. Keep track of the largest number of times a single repetition occurs and which word is repeated. Print the maximum number of duplicates, or else print a message saying that no word was repeated. For example, if the input is “how now now now brown cow cow”, the output should indicate that the word “now” occurred three times.

CODE: Q.1

ex.5.15
Exercise 5.15: Explain each of the following loops. Correct any problems you detect.

(a) for (int ix = 0; ix != sz; ++ix) { /* . . . */ }  // the loop runs until ix reachs sz
if (ix != sz) //there is no need to test the condition again in loop body
// . . .
Fix:for (int ix = 0; ix != sz; ++ix) { //....}

(b) int ix;
for (ix != sz; ++ix) { /* . . . */ } //the same loop as (a). ix need to be initialized, and a null statement is needed in the header to be an init-statement.
Fix: int ix = 0; for(; ix! =sz; ++ix)

(c) for (int ix = 0; ix != sz; ++ix, ++ sz) { /* . . . */ } the expression of sz will cause the loop to run forever.
Fix:for (int ix = 0; ix != sz; ++ix) {//....}

ex.5.16

Exercise 5.16: The while loop is particularly good at executing while some condition holds; for example, when we need to read values until end-of-file. The for loop is generally thought of as a step loop: An index steps through a range of values in a collection. Write an idiomatic use of each loop and then rewrite each using the other loop construct. If you could use only one loop, which would you choose? Why?

/* while idomatic */
int i = 0;
while (cin >> i) {}
/* for version */
for (int i = 0; cin >> i;) {}
/* for idomatic */
for (int i = 0; i < 10; ++i) {}
/*while version*/
int i = 0;
while (i < 10) { 
    ++i;
}
I prefer for to while. The biggest advantage that for-loop over while-loop is for-loop can keep all loop control variables as local variables by putting them all into the header, whereas while-loop has to define the control variable outside of the loop, since any variable is defined in a while-loop condition will be reset at the beginning of every new step. Using for-loop would prevent the potential variable name confliction.

ex.5.17
Exercise 5.17: Given two vectors of ints, write a program to determine whether one vector is a prefix of the other. For vectors of unequal length, compare the number of elements of the smaller vector. For example, given the vectors containing 0, 1, 1, and 2 and 0, 1, 1, 2, 3, 5, 8, respectively your program should return true.

CODE: Q.1

ex.5.18
Exercise 5.18: Explain each of the following loops. Correct any problems you detect.

(a) do
		int v1, v2;
		cout << "Please enter two numbers to sum:" ;
		if (cin >> v1 >> v2)
		cout << "Sum is: " << v1 + v2 << endl;
	while (cin);
/* Program (a) is trying to keep adding two numbers until the loop is over. The problem here is the loop body doesn't come with a curly brace. */
Fix:
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());
/* define a control variable insde the while condtiion is not allowed. */
Fix:
int ival = get_response();
do {
    // . . .
} while (/*...*/);
/* ival is not defined in the do while condition scope. */
(c) do {
	int ival = get_response();
} while (ival)

Fix:
int ival = get_response();
do {
    ...
} while (ival)

ex.5.19
Exercise 5.19: Write a program that uses a do while loop to repetitively request two strings from the user and report which string is less than the other.

CODE: Q.1

ex.5.20
Exercise 5.20: Write a program to read a sequence of strings from the standard input until either the same word occurs twice in succession or all the words have been read. Use a while loop to read the text one word at a time. Use the break statement to terminate the loop if a word occurs twice in succession. Print the word if it occurs twice in succession, or else print a message saying that no word was repeated.

CODE: Q.1

Ex.5.21-5.25

ex.5.21
Exercise 5.21: Revise the program from the exercise in § 5.5.1 (p. 191) so that it looks only for duplicated words that start with an uppercase letter.

CODE: Q.1

ex.5.22
Exercise 5.22: The last example in this section that jumped back to begin could be better written using a loop. Rewrite the code to eliminate the goto.

for (int sz = get_size(); sz <= 0; sz = get_size()) {;}

ex.5.23
Exercise 5.23: Write a program that reads two integers from the standard input and prints the result of dividing the first number by the second.

#include <iostream>
using std::cin;
using std::cout;
using std::endl;
int main(int argc, char const *argv[])
{
	int a{0}, b{0};
	cin >> a >> b;
	cout << a * 1.0 / b << endl;
	return 0;
}

ex.5.24
Exercise 5.24: Revise your program to throw an exception if the secondnumber is zero. Test your program with a zero input to see what happens onyour system if you don’t catch an exception.

#include <iostream>
#include <stdexcept>
using std::logic_error;
using std::cin;
using std::cout;
using std::endl;

int main(int argc, char const *argv[])
{
	int a{0}, b{0};
	
		cin >> a >> b;
		if (b == 0) {
			throw logic_error("The divsor can't be zero.");
		}
		else
			cout << a * 1.0 / b << endl;
	
	return 0;
}

ex5.25
Exercise 5.25: Revise your program from the previous exercise to use a try block to catch the exception. The catch clause should print a message to the user and ask them to supply a new number and repeat the code inside the try.

CODE: Q.1