C++ primer 第五章習題

chapter5 語句

練習

5.1節練習

練習5.1

  • 什麼是空語句?什麼時候會用到空語句?

空語句就是不執行任何內容的語句。僅包含一個分號。在語法上需要一條語句但在邏輯上不需要的時候,會用到空語句。

練習5.2

  • 什麼是塊?什麼時候會用到塊?

塊就是複合語句,用花括號括起來的(可能爲空的)語句和聲明的序列。在語法上需要一條語句,但在邏輯上需要多條語句的時候會用到塊。

練習5.3

  • 使用逗號運算符(參見4.10節,第104頁)重寫1.4.1節(第10頁)的 while 循環,使它不再需要塊,觀察改寫之後的代碼的可讀性提高了還是降低了。
while(val <= 10)
    sum += val, ++val;

可讀性降低了。

5.2節練習

練習5.4

  • 說明下列例子的含義,如果存在問題,試着修改它。
(a) while (string::iterator iter != s.end()) {/*...*/}
(b) while (bool status = find(word)) {/*...*/}
    if (!status) {/*...*/}
(a) 遍歷字符串s。語法錯誤,while內的變量必須被初始化,而iter並沒有初始化,應在外部初始化iter。
(b) 函數正確則死循環。status是while的內部變量,無法訪問。應在外部初始化status。

5.3.1節練習

練習5.5

  • 寫一段自己的程序,使用if else 語句實現把數字成績轉換爲字母成績的要求。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
	const vector<string> scores = { "F", "D", "C", "B", "A", "A++" };
	string lettergrade;
	int grade;
	while (cin >> grade)
	{
		if (grade < 60)
			lettergrade = scores[0];
		else
			lettergrade = scores[(grade - 50) / 10];
		cout << lettergrade << '\n';
	}
}

練習5.6

  • 寫一段自己的程序,使用if else 語句實現把數字成績轉換爲字母成績的要求。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
	const vector<string> scores = { "F", "D", "C", "B", "A", "A++" };
	string lettergrade;
	int grade;
	while (cin >> grade)
	{
		grade < 60 ? lettergrade = scores[0] : lettergrade = scores[(grade - 50) / 10];
		cout << lettergrade << '\n';
	}
}

練習5.7

  • 改寫下列代碼段中的錯誤。
(a) if (ival1 != ival2)
        ival1 = ival2
    else ival1 = ival2 = 0;
改爲 if (ival1 != ival2)
        ival1 = ival2;    //原代碼段此處缺少分號

    else else ival1 = ival2 = 0;
(b) if (ival < minval)
        minval = ival;
        occurs = 1;
改爲 if (ival < minval){   //原代碼段缺少花括號將兩條賦值語句改爲複合語句。
        minval = ival;
        occurs = 1;}

(c) if (int ival = get_value())
        cout << "ival = " << ival << endl;
    if (!ival)
        cout << "ival = 0\n";
改爲 int ival = get_value();    //原代碼段中,ival爲第一個if的內部變量
     if (ival)
         cout << "ival = " << ival << endl;
     if (!ival)
         cout << "ival = 0\n";

(d) if (ival = 0)
        ival = get_value();
改爲 if (ival == 0)    //原代碼段其實可以執行,但根據一般語義來說,條件應該爲判斷是否相等而不是賦值
        ival = get_value();

練習5.8

  • 什麼是“懸垂else”?C++語言是如何處理else子句的?

在嵌套if語句中,if分支多於else分支的情況。C++的解決方法是規定else與離它最近的未匹配的if語句匹配。

5.3.2節練習

練習5.9

  • 編寫一段程序,使用一系列if語句統計從cin讀入的文本中有多少元音字母。
#include <iostream>
using namespace std;
int main()
{
	int count = 0;
	char c;
	while (cin >> c) {
		if (c == 'a') count += 1;
		if (c == 'e') count += 1;
		if (c == 'i') count += 1;
		if (c == 'o') count += 1;
		if (c == 'u') count += 1;
	}
	cout << count << endl;
}

練習5.10

  • 我們之前實現的統計元音字母的程序存在一個問題:如果元音字母以大寫形式出現,不會被統計在內。編寫一段程序,既統計元音字母的小寫形式,也統計元音字母的大寫形式,也就是說,新程序遇到’a’和’A’都應該遞增 aCnt 的值,以此類推。
#include <iostream>
using namespace std;
int main()
{
	unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0;
	char c;
	while (cin >> c) {
		c = tolower(c);
		if (c == 'a') aCnt += 1;
		if (c == 'e') eCnt += 1;
		if (c == 'i') iCnt += 1;
		if (c == 'o') oCnt += 1;
		if (c == 'u') uCnt += 1;
	}
	cout << "Number of vowel a: \t" << aCnt << '\n'
		<< "Number of vowel e: \t" << eCnt << '\n'
		<< "Number of vowel i: \t" << iCnt << '\n'
		<< "Number of vowel o: \t" << oCnt << '\n'
		<< "Number of vowel u: \t" << uCnt << endl;
}

練習5.11

  • 修改統計元音字母的程序,使其也能統計空格、製表符、和換行符的數量。
#include <iostream>
#include <string>
using namespace std;
int main()
{
	unsigned aCnt = 0, eCnt = 0, iCnt = 0, oCnt = 0, uCnt = 0, sCnt = 0, tCnt = 0, nCnt = 0;    //最後三個爲空格,製表符,換行符
	string str;
	char c;
	while (getline(cin, str)) {
		c = tolower(str[0]);
		if (c == 'a') aCnt += 1;
		if (c == 'e') eCnt += 1;
		if (c == 'i') iCnt += 1;
		if (c == 'o') oCnt += 1;
		if (c == 'u') uCnt += 1;
		if (c == ' ') sCnt += 1;    //cin 無法獲取空格和製表符,改用getline
		if (c == '\t') tCnt += 1;
		if (c == '\n') nCnt += 1;    //getline 也無法獲取到換行符,只能改用從文本文件的輸入流中獲取
	}
	cout << "Number of vowel a: \t" << aCnt << '\n'
		<< "Number of vowel e: \t" << eCnt << '\n'
		<< "Number of vowel i: \t" << iCnt << '\n'
		<< "Number of vowel o: \t" << oCnt << '\n'
		<< "Number of vowel u: \t" << uCnt << '\n'
		<< "Number of vowel space: \t" << sCnt << '\n'
		<< "Number of vowel tab: \t" << tCnt << '\n'
		<< "Number of vowel newline: \t" << nCnt << endl;
}

練習5.12

  • 修改統計元音字母的程序,使其能統計含以下兩個字符的字符序列的數量: ff、fl和fi。
#include <iostream>
using namespace std;
int main()
{
	unsigned  ffCnt = 0, flCnt = 0, fiCnt = 0;
	char c;
	char temp = ' ';
	while (cin >> c) {
		if (temp == 'f')
			if (c == 'f') ffCnt += 1;
			else if (c == 'l') flCnt += 1;
			else if (c == 'i') fiCnt += 1;
		temp = c;
	}
	cout << "Number of vowel ff: \t" << ffCnt << '\n'
		<< "Number of vowel fl: \t" << flCnt << '\n'
		<< "Number of vowel fi: \t" << fiCnt << endl;
}

練習5.13

  • 下面顯示的每個程序都含有一個常見的編碼錯誤,指出錯誤在哪裏,然後修改它們。
(a) unsigned aCnt = 0, eCnt = 0, iouCnt = 0;
    char ch = next_text();
    switch (ch) {
        case 'a': aCnt++;
        case 'e': eCnt++;
        default: iouCnt++;}
首先沒有寫break,其次default情況下,任意字符均會使iouCnt++,邏輯錯誤。
修正如下:
unsigned aCnt = 0, eCnt = 0, iouCnt = 0;
char ch = next_text();
switch (ch) {
    case 'a': 
        aCnt++;
        break;
    case 'e':
        eCnt++;
        break;
    case 'i': case 'o': case 'u':
        iouCnt++;
        break;
    default: 
        break;
}
(b) unsigned index = some_value();
    switch (index) {
        case 1:
            int ix = get_value();    //將該語句移至switch結構體之前。
            ivec[ ix ] = index;
            break;
        default:
            ix = ivec.size() - 1;
            ivec [ ix ] = index;}
執行switch語句時,可能跳過ix的定義。改爲在switch外部定義即可。
(c) unsigned evenCnt = 0, oddCnt = 0;
    int digit = get_num() % 10;
    switch (digit) {
        case 1,3,5,7,9:    //改爲case 1: case 3: case 5: case 7: case 9:
            oddcnt++;
            break;
        case 2,4,6,8,10:    //改爲case 0: case 2: case 4: case +: case 8:
            evencnt++;
            break;
    }
case寫法錯誤,同時在switch內部的變量名稱大小寫也錯誤了。以及不應該存在10的情況,應改爲0。
(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;
}
case 標籤必須是整型常量表達式。而不能是變量。
將首部初始化語句修改爲constexpr unsigned ival = 512, jval = 1024, kval = 4096;

5.4.1節練習

練習5.14

  • 編寫一段程序,從標準輸入中讀取若干string對象並查找連續重複出現的單詞。所謂連續重複出現的意思是:一個單詞後面緊跟着這個單詞本身。要求記錄連續重複出現的最大次數以及對應的單詞。如果這樣的單詞存在,輸出重複出現的最大次數;如果不存在,輸出一條信息說明任何單詞都沒有連續出現過。例如:如果輸入是:

    how now now now brown cow cow
    那麼輸出應該表明單詞now連續出現了3次。

#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
	vector<string> vstr;
	string str;
	int count = 0;
	while (cin >> str)
		vstr.push_back(str);
	auto beg = vstr.begin();
	while (beg + 1 != vstr.end()) {
		if (*beg == *(beg + 1)) count++;
		beg++;
	}
	cout << count;
}

5.4.2節練習

練習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; ++iz, ++ sz) { /*...*/ }

(a) 遍歷結構體。if的含義不明。錯誤爲for語句頭中定義的對象只在for循環體內可見。故在if語句中ix是未定義的。
(b) 遍歷結構體。for語句的頭一句應該是初始化,缺少分號。改爲 for (;ix != sz; ++ix) 
(c) 遍歷結構體。將會導致死循環。刪除sz自增的表達式。

練習5.16

  • while 循環特別適用於那種條件不變、反覆執行操作的情況,例如,當未達到文件末尾時不斷讀取下一個值。for 循環更像是在按步驟迭代,它的索引值在某個範圍內依次變化。根據每種循環的習慣用法各自編寫一段程序,然後分別用另一種循環改寫。如果只能使用一種循環,你傾向於哪種?爲什麼?
#include <iostream>
using namespace std;
int main()
{
	int i = 0, sum = 0;
	while (i <= 100){
		sum += i;
		++i;
	}
	for (int i = 0; i != 100; ++i)
		sum += i;
}
while循環。括號內更簡潔,循環使用的變量結束循環後仍可使用。

練習5.17

  • 假設有兩個包含整數的vector對象,編寫一段程序,檢驗其中一個vector對象是否是另一個的前綴。爲了實現這一目標,對於兩個不等長的vector對象,只需挑出長度較短的那個,把它的所有元素和另一個vector對象比較即可。例如,如果兩個vector對象的元素分別是0、1、1、2 和 0、1、1、2、3、5、8,則程序的返回結果爲真。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main()
{
	vector<int> v1 = { 0,1,1,2 }, v2 = { 0,1,1,2,3,5,8 };
	auto beg1 = v1.begin(), beg2 = v2.begin();
	string tag = "True";
	while (beg1 != v1.end() && beg2 != v2.end()) {
		if (*beg1 != *beg2) {
			tag = "False";
			break;
		}
		++beg1; ++beg2;
	}
	cout << tag;
}

5.4.4節練習

練習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 (ival = get_response());
(c) do {
        ival = get_response();
    } while (ival);

(a) 循環內有多條語句時,應使用花括號括起來,形成複合語句。
(b) 不允許在條件語句內定義變量,它將在被定義先被使用,這是不合理的。
(c) 條件語句使用的變量必須定義在循環體之外。而ival在循環體內被定義。不合法。

練習5.19

  • 編寫一段程序,使用do while 循環重複地執行下述任務:首先提示用戶輸入兩個string對象,然後挑出較短的那個並輸出它。
#include <iostream>
#include <string>
using namespace std;
int main()
{
	string rsp;
	do {
		string str1 = "", str2 = "";
		cout << "Please enter two string:" << endl;
		cin >> str1 >> str2;
		if (str1.size() > str2.size()) cout << str2 << " is shorter." << "\n\n";
		else cout << str1 << " is shorter." << "\n\n";
		cout << "More? Enter yes or no: ";
		cin >> rsp;
	} while (!rsp.empty() && rsp[0] != 'n');
}

5.5.1節練習

練習5.20

  • 編寫一段程序,從標準輸入中讀取string對象的序列直到連續出現兩個相同的單詞或者所有單詞都讀完爲止。使用while循環一次讀取一個單詞,當一個單詞連續出現兩次時使用break語句終止循環。輸出連續重複出現的單詞,或者輸出一個消息說明沒有任何單詞是連續重複出現的。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
	vector<string> vstr;
	string str;
	string exist_str;
	while (cin >> str) {
		vstr.push_back(str);
		if (exist_str == str)
			break;
		exist_str = str;
	}
	str = vstr[0];
	auto beg = vstr.begin() + 1;
	bool tag = false;
	while (beg != vstr.end()){
		if (str == *beg) {
			tag = true;
			break;
		}
		str = *beg;
		++beg;
	}
	if (tag) cout << str;
	else cout << "no repeat word.";
}

5.5.2節練習

練習5.21

  • 修改5.5.1節練習題的程序,使其找到的重複單詞必須以大寫字母開頭。
#include <iostream>
#include <string>
#include <vector>
using namespace std;
int main()
{
	vector<string> vstr;
	string str;
	string exist_str;
	while (cin >> str) {
		vstr.push_back(str);
		if (exist_str == str)
			break;
		exist_str = str;
	}
	str = vstr[0];
	auto beg = vstr.begin() + 1;
	bool tag = false;
	while (beg != vstr.end()){
		if (!isupper(str[0])) {   //不管首字母是否大寫,迭代器必須繼續指向下一個元素。
			str = *beg;
			++beg;
			continue;
		}
		if (str == *beg) {
			tag = true;
			break;
		}
		str = *beg;
		++beg;
	}
	if (tag) cout << str;
	else cout << "no repeat word.";
}

5.5.3節練習

練習5.22

  • 本節的最後一個例子跳回到 begin,其實使用循環能更好的完成該任務,重寫這段代碼,注意不再使用goto語句。
#include <iostream>
using namespace std;
int main()
{
	int sz = get_size();
	while (sz <= 0) sz = get_size();
}

5.6.3節練習

練習5.23

  • 編寫一段程序,從標準輸入讀取兩個整數,輸出第一個數除以第二個數的結果。
#include <iostream>
using namespace std;
int main()
{
	int num1, num2;
	cin >> num1 >> num2;
	cout << num1 / num2;
}

練習5.24

  • 修改你的程序,使得當第二個數是0時拋出異常。先不要設定catch子句,運行程序並真的爲除數輸入0,看看會發生什麼?
#include <iostream>
using namespace std;
int main()
{
	int num1, num2;
	cin >> num1 >> num2;
	if (num2 == 0) 
		throw runtime_error("ERROR! Division by zero!");
	cout << num1 / num2;
}

編譯器提示該異常沒有被處理,程序暫停。

練習5.25

  • 修改上一題的程序,使用try語句塊去捕獲異常。catch子句應該爲用戶輸出一條提示信息,詢問其是否輸入新數並重新執行try語句塊的內容。
#include <iostream>
using namespace std;
int main()
{
	int num1, num2;
	while(cin >> num1 >> num2)
	    try {
		    if (num2 == 0) throw runtime_error("ERROR!Division by zero!");
		    cout << num1 / num2;
	    }catch (runtime_error err) {
			cout << err.what() << "\nTry Again? Enter y or n" << endl;
			char c;
			cin >> c;
			if (!cin || c == 'n') break;
	    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章