C++ Primer 筆記+習題解答(五)

今天是第五篇的總結,最近兩天自我反省,效率着實有提升。

有錯誤 請指正 謝謝

0.引言:

    第五章主體是表達式和語句,重點則是講述了幾種常見的控制流,已經瞭解過的估計看起來很輕鬆,但是這本書中仍然介紹了許多奇技淫巧,直接大家借鑑。

1.簡單語句:

  1.特徵:

大多數語句以分號結束,其中表達式語句由表達式和一個分號構成,作用是執行表達式並丟棄求值結果。

  如:

int var=2;
var+3;
//一個簡單的表達式語句。

  2.空語句:

由單獨的分號構成。一般是語法上需要,但是邏輯上不需要。使用的時候最好加上註釋。不要因爲分號是空語句就隨意使用,可能會造成誤會。C++一般對縮進是無要求的,當你寫下這個語句的時候:

for(auto i:array) ;
   cout<<i<<" ";
一旦手賤在range for 語句後面加上了一個分號,那麼for語句的循環體就變成了空語句,而不是底下的輸出語句。

  3.複合語句(塊語句)

1.相關:

用花括號括起來的語句和聲明序列。一般是語法是需要一條,但是邏輯上需要多條的地方。我們把語句塊當成一條語句來理解,只不過是不以分號結尾。在我們可以看見的語法格式描述中,可能是如此的:

while(condition)
  statement
這個地方一般都是隻寫一個statement,因爲規定就是隻能用一條語句,但是多條語句只能括號出馬了。所以statement也不是複數,因爲規定就是用一條語句。

2.語句作用域:

  在語句內部定義的變量包括 語句頭定義的變量,一般只在作用域中可見,快外不可見,並且會隱藏域外同名變量。

3.條件語句:

  1.if語句:

一般有兩種if語句,帶else 和不帶else 。if語句根據條件選擇執行流程。

語法格式:

if(condition)
  statement
其中的condition 部分可以初始化的聲明和表達式,至於語句部分就隨意了。

關於if語句的嵌套:

我們平時見到如下的:

if 
else if 
else if
else
---
if{
   if
    else
} else 
如上面這些格式的都算嵌套了

嵌套時遇到的問題:

懸垂else問題,看名字比較難理解,其實很簡單,就是一個原則引起的問題,因else 總是會和最近的if語句匹配,這個就會導致一些錯誤的匹配。解決辦法也很簡單,善用花括號。有的人推薦多個if語句一定要寫上花括號,不然寫多了自己就亂了,而且便於修改,如果不加花括號,那麼改的時候還要加上。

  2.switch 語句:

我看微軟的vs2013稱之爲開關語句。它是根據括號內的整形表達式計算結果選擇執行的語句。看好了是整形表達式,如果你用浮點數,那麼一定錯了。

一般搭配case關鍵字和對應的值構成了case label .標籤必須是整形常量表達式。不要認爲char 不是整形。

任何兩個case 標籤不能相同,不然肯定有二義性問題產生,另外,default也是一個標籤。

執行流程:可以多個標籤公用一個執行語句,比如:

switch(ch){
 case 'a':
 case 'b‘:
 case 'c':
   ++cnt;
}
或者別的寫法:
switch(ch){
 case 'a': case 'b‘: case 'c':
   ++cnt;
}
一般來說case 標籤後跟break一起用,用於流程跳轉。

從上面我們可以看出來,標籤後一般後跟語句,注意我們沒說語句塊,或者標籤。如果只有默認標籤,記得寫上空語句。

switch 內部變量定義:一個很常見的問題,你在一個標籤後定義了一個變量,一旦執行跳過這個標籤,但是後面的標籤卻使用了前面中定義的變量,很容易出現問題,所以一般來說,case標籤內定義的變量就給它一個單獨的作用域,也就是說讓它只在自己的case內可見可用。

控制流會繞過一個直接初始化的變量,不管是顯式還是隱式的。

現代C++規定,不允許肉啊過變量的初始化語句直接跳轉到該變量作用域內的另一個位置。

一開始我理解是有一個誤區的,後來仔細斟酌才發現,與大家分享下:

switch(ch){
 case 'a':
   char temp=’ ’;
 case 'b‘:
   ++cnt;
}
一開始我以爲temp變量的作用域僅僅侷限於case 'a'標籤內,但是事實上此變量作用域是整個switch語句內,也就說一般來說只有花括號是能形參作用域,這個地方理解要注意。

4.迭代語句:

 0.迭代語句:

也稱循環語句,循環語句常見的就三種,for循環,while 循環,do while 循環,如果算上C++11的範圍for,一共四種。

 1.while 語句:

語法格式:

while(condition)
  statement
其中條件部分可以是表達式或者是初始化的聲明,其實無論是什麼東西,最後還是要轉換成布爾值才能判斷。

一般由條件部分或者循環體內改變迭代變量,不然成了死循環。

使用條件: 1.不知道要多少次迭代的時候使用。2.想在循環結束後訪問迭代變量。

  2.傳統的for語句:

語法格式:

for(init-statement;condition;expression)
  statement
語句頭中的初始化部分,可以定義多個對象,但是只能有一條聲明語句,也就是說基礎類型要一致。如:

for(int i=0,var=1; ;)
for語句的省略:

1.省略初始化部分:無須初始化的時候就可以省略,當然一般是在循環體外定義過了相關迭代變量。但是後面分號不可以省略。

2.省略condition 部分:等價於把條件設置爲1,也就是永真,這個時候最後在expression 部分或者循環體內有相應的退出循環措施。

3.省略expression部分:只需要在循環體內或者條件部分修改迭代變量就可以了。比如:

for(int i;cin>>i;)
/**/
我們直在條件裏面檢測循環變量並且可以修改循環變量,當然這個做法着實是我第一次見到,有點震驚,但是對比下while 又覺得可以接受。

4.range for 語句:

範圍for語句其實挺好用的,一般處理的是序列中的全部元素。

語法格式:

for( declaration:expressin)
 statement
expression 一般是一個序列。也就是說可以寫個花括號在那裏。

declaration 部分一般是聲明一個變量用於迭代序列裏的元素。一般用auto,省去推斷類型。

5.do while 語句:

同while 無大區別,一般就是do while 語句一定會執行一次循環體。

語法格式:

do 
statement
while(conditon);
不建議在condition裏面定義變量,應該順序執行,最後才執行到conditon裏。所以可能會發生未定義行爲。

5.跳轉語句:

   0.四種:

break語句。continue 語句。returned 語句。goto 語句。

  1.break 語句:

適用範圍:循環和switch 語句中。結束範圍是好最近的循環或者標籤內。

功能:結束當前循環或者標籤內的執行,控制權移交到循環體或者開關語句外的第一條語句。

  2.continue 語句:

適用範圍:循環語句內。結束範圍是循環體內。

功能:加速下一次迭代。

區別:在for語句中執行continue 語句,相當於直接跳轉到expression 部分執行。但是在while 語句中,卻是直接跳轉到condition部分,如果condition部分沒用修改條件的能力,那麼會發生什麼呢?當然當你的condition中有修改迭代變量的能力的時候,那就相當於執行for語句的expression部分。

  3.returne 語句:

暫時不表。

   4.goto語句:

暫時不表。

6.異常處理和標準異常:

不詳細總結,按照書上的要求,用到的時候在詳細介紹。這個地方只要知道有這個特性就可以了。

 異常處理機制:

   1.異常檢測,throw出去。

   2.異常處理:try catch住。

  異常類:

用於throw表達式和catch 中傳遞相關的錯誤信息。總而言之就是個類。

7.習題解答:

5.1

由單獨的分號構成的語句。
用處:一般是邏輯上不需要,但是語法上需要。
5.2

用花括號括起來的語句和聲明序列。
可以寫一條語句的地方都可以用快。一般來說是語法上需要一條,但是邏輯上需要多天的地方。
5.3

#include <string>
#include <iostream>
using namespace std;
int main(){
	int sum = 0;
	int var = 0;
	while ((++var,var <= 10))//這個地方的順序還不能顛倒,因爲while順序有求值順序的。
		sum += var;
	cout << "The sum is " << sum << endl;
	system("pause");
	return 0;
}
其實寫成
sum+=var++是最好讀的方式。
用法逗號表達式重新可讀性下降了。
5.4

a)因爲聲明的變量沒用初始化,所以比較行爲不合乎我們的要想
修改:while(string::iterator iter =s.begin()!=s.end())
b)應該是誤用==和=號。
修改:while(bool status==find(word))
5.5

#include <string>
#include <iostream>
using namespace std;
int main(){
	string level;
	unsigned grade = 0;
	cout << "Enter grade ";
	cin >> grade;
	if (grade < 60)
		level = "F";
	else if (grade >= 60 && grade <= 69)
		level = "D";
	else if (grade >= 70 && grade <= 79)
		level = "C";
	else if (grade >= 80 && grade <= 89)
		level = "B";
	else if (grade >= 90 && grade <= 99)
		level = "A";
	else if (grade == 100)
		level = "A++";
	else
		cout << "The grade is more than 100,check the grade " << endl;
	cout << "The level is " << level << endl;
	system("pause");
	return 0;
}
這個寫法比較常見了,推薦下書上的寫法。
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(){
    vector<string> svec = { "F", "D", "C", "B", "A", "A++" };
    unsigned grade = 0;
    string level;
    cout << "Enter grade : ";
    cin >> grade;
    if (grade < 60)
        level = svec[0];
    else{
        if (grade == 100)
            level = svec[5];
        else{
            if (grade % 10>7)
                level = svec[(grade - 50) / 10] + "+";
            else if (grade % 10 < 3)
                level = svec[(grade - 50) / 10] + "-";
            else
                level = svec[(grade - 50) / 10];
        }
    }
    cout << "The level is " << level << endl;
    system("pause");
    return 0;
}
//書上這個還實現了A+, A-;而且簡潔。
5.6

#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(){
	vector<string> svec = { "F", "D", "C", "B", "A", "A++" };
	unsigned grade = 0;
	string level;
	cout << "Enter grade : ";
	cin >> grade;
	level = ((grade == 100) ? "A++"
		: ((grade < 100 && grade >= 90) ? "A"
		: ((grade < 90 && grade >= 80) ? "B"
		: (((grade < 80 && grade >= 70) ? "C"
		: ((grade < 70 && grade >= 60) ? "D" : "F"))))));  //你看這個括號寫的。。。
	cout << "The level is " << level << endl;
	system("pause");
	return 0;
}
5.7

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;
else
  cout<<"ival=0\n";
d)
if(ival==0)
  ival=get_value;    
5.8

懸垂else就是 else總是會和最近的if匹配,從而可能導致問題產生。
處理措施一般就是用花括號。
5.9

#include <iostream>
using namespace std;
int main(){
	char ch;
	int cnt = 0;
	cout << "Enter chars or Enter Ctrl +z to stop ";
	while (cin>>ch){
		if (ch == 'a' || ch == 'e' || ch == 'i' || ch == 'o' || ch == 'u')
			cnt++;
		else
			continue;
	}
	cout << "The occurance of vowel is " << cnt << endl;
	system("pause");
	return 0;
}
5.10

#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(){
	char ch;
	int acnt = 0;
	int ecnt = 0;
	int icnt = 0;
	int ocnt = 0;
	int ucnt = 0;
	while (cin>>ch){
		ch = tolower(ch);
		switch (ch){
			case 'a':
				++acnt;
				break;
			case 'e':
				++ecnt;
				break;
			case 'i':
				++icnt;
				break;
			case 'o':
				++ocnt;
				break;
			case 'u':
				++ucnt;
				break;
			default:
				break;
		}
	}
	cout << "The result is :\n"
		<< "a or A occur " << acnt << " times\n"
		<< "e or E occur " << ecnt << " times\n"
		<< "i or I occur " << icnt << " times\n"
		<< "o or O occur " << ocnt << " times\n"
		<< "u or U occur " << ocnt << " times\n";
	system("pause");
	return 0;
}


5.11

#include <cctype>
#include <iostream>
#include <string>
using namespace std;
int main(){
	unsigned acnt = 0;  //這個地方可以考慮用向量.
	unsigned ecnt = 0;
	unsigned icnt = 0;
	unsigned ocnt = 0;
	unsigned ucnt = 0;
	unsigned space_cnt = 0;  //統計空格。
	unsigned t_cnt = 0;  //統計製表符
	unsigned n_cnt = 0; //統計
	string line = "asASDFA  AEdqwf\t\n       asqeas "; //因爲你用cin或者getline輸入字符的時候會忽略空格或者換行。
        for (auto &x : line){
		x = tolower(x);
		if(x=='a') ++acnt;
		else if(x=='e') ++ecnt;
		else if(x=='i') ++icnt;
		else if(x=='o') ++ocnt;
		else if(x=='u') ++ucnt;
		else if(!isspace(x)) ++space_cnt;
		else if(x=='\n') ++n_cnt;
		else if (x == '\t') ++t_cnt;
		else continue;
	}
	cout << "The result is :\n"
		<< "a or A occur " << acnt << " times\n"
		<< "e or E occur " << ecnt << " times\n"
		<< "i or I occur " << icnt << " times\n"
		<< "o or O occur " << ocnt << " times\n"
		<< "u or U occur " << ocnt << " times\n"
		<< "space occurs " << space_cnt << "times\n"
		<< "\\t occurs " << t_cnt << " times\n"
		<< "\\n occurs " << n_cnt << " times\n";
	system("pause");
	return 0;
}
5.12

#include <cctype>
#include <iostream>
#include <vector>
#include <string>
using namespace std;
int main(){
	unsigned ff_cnt = 0;
	unsigned fl_cnt = 0;
	unsigned fi_cnt = 0;
	string line = "fffqwfiasfl";
	for (decltype(line.size()) i = 0; i != line.size()-1; i++){
		if (line[i] == 'f'){
			if (line[i + 1] == 'f')
				++ff_cnt;
			else if (line[i + 1] == 'l')
				++fl_cnt;
			else if (line[i + 1] == 'i')
				++fi_cnt;
			else
				continue;
		}
		else
			continue;
	}
	cout << "ff occurs " << ff_cnt << " times\n"
		<< "fl occurs " << fl_cnt << "times\n"
		<< "fi occurs " << fi_cnt << "times\n";
	system("pause");
	return 0;
}
這個地方 就不用switch 實現了但是目標還是先判斷字符f,然後在此標籤內部繼續用開關語句或者用if語句分別統計ff等。

5.13

a)
缺少break語句。修改略。
b)
在標籤內定義變量,沒有加上花括號。
c)
書寫格式有錯誤。
d)
標籤後的值必須是整形常量表達式。

5.14

#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main(){
	string word;
	vector<string> svec;
	cout << "Enter word " << endl;
	while (cin >> word){
		svec.push_back(word);
	}
	int max_cnt = 0;
	int cnt = 0;
	for (decltype(svec.size()) i = 0; i<svec.size()-1;i++){
		if (svec[i] ==svec[i+1])
			++cnt;
		else
			cnt = 0;
		if (cnt>max_cnt)
			max_cnt = cnt;
		
	}
	if (max_cnt == 0)
		cout << "No exist " << endl;
	else
		cout << max_cnt +1<< endl;
	system("pause");
	return 0;
}
5.15

a)if語句永遠都不會執行。
b)缺少初始化部分,空語句都沒寫。
c)一個循環,只不過表達式部分是一個逗號表達式,同時地址迭代變量和sz.
5.16

#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main(){
	int sum = 0;
	int var = 1;
	while (var<11){
		sum += var++;
	}
	cout << "The sum is " << sum << endl;
	system("pause");
	return 0;
}
#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main(){
    int sum = 0;
    int var = 1;
    for (var = 1; var < 11; ++var)
        sum += var;
    cout << "The sum is " << sum << endl;
    system("pause");
    return 0;
}
一般不知道明確的循環次數的時候我傾向於使用while循環,明確知道要循環多少次的時候我傾向使用for循環。
5.17

#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main(){
	vector<int> short_ivec = { 0, 1, 1, 2 };
	vector<int> long_ivev = { 0, 1, 1, 2, 3, 5, 8 };
	bool status;
	for (decltype(short_ivec.size())i = 0; i < short_ivec.size(); ++i){
		if (short_ivec[i] != long_ivev[i]){
			status = false;
			break;
		}
		else
			status = true;
	}
	if (status)
		cout << "It is prefix " << endl;
	else
		cout << "Not prefix " << endl;
	system("pause");
	return 0;
}
5.18

a)缺少花括號。
循環輸出輸入的兩個數的和直到cin流無效。
b)
在條件中定義變量。可能無法使用。
c)
可能會出現死循環。含義大致是給ival賦值,然後檢測其值是否是0,0就跳出循環,不是0,重複。
5.19

#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main(){
	string str1, str2;
	cout << "Enter two strings " << endl;
	cin >> str1 >> str2;
	do {
		cout << ((str1.size()》
str2.size()) ? str2 : str1)<<endl;
		cout << "Enter two strings  or Enter Ctrl+z to stop " << endl;
	} while (cin>>str1>>str2);
	system("pause");
	return 0;
}
5.20

#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main(){
	string word, preword;
	cout << "Enter string or Enter x to exit ";
	while (cin >> word){
		if (word == preword){
			cout << word << endl;
			break;
		}
		preword = word;
		if (word == "x"){
			cout << "讀取完畢" << endl;
			break;
		}
	}
	system("pause");
	return 0;
}
5.21

#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main(){
	string word, preword;
	cout << "Enter string or Enter x to exit ";
	while (cin >> word){
		if (word == preword){
			if (isupper(word[0])){
				cout << word << endl;
				break;
			}
			else
				continue;
		}
		preword = word;
		if (word == "x"){
			cout << "讀取完畢" << endl;
			break;
		}
	}
	system("pause");
	return 0;
}
5.22

do{
  int sz=get_size();
}while(sz<=0);
5.23

#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main(){
	int var1, var2;
	cin >> var1>>var2;
	if (var2 != 0)
		cout << var1 / var2;
	else
		cout << "被除數爲0" << endl;
	system("pause");
	return 0;
}
5.24

#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main(){
	int var1, var2;
	cin >> var1>>var2;
        cout << var1 / var2;
	system("pause");
	return 0;
}
//程序異常終止。
5.25

#include <string>
#include <iostream>
#include <vector>
using namespace std;
int main(){
	int var1, var2;
	try{
		cout << "Enter two numbers ";
		cin >> var1 >> var2;
		if (var2 == 0)
			throw 0;
		cout <<"The result is "<< var1 / var2 << endl;
	}
	catch (int){
		cout << "被除數爲0,是否重新輸入 yes or no";
		char ch;
		cin>>ch;
		if (ch != 'y'&& ch != 'Y')
			exit(0);
		cout << "重新輸入被除數 ";
		cin >> var2;
		cout << "The result is " << var1 / var2 << endl;
	}
	system("pause");
	return 0;
}


後記:

   越發覺得自己水平不夠,有些習題做的都有點吃力。加油自勉。

End

發佈了53 篇原創文章 · 獲贊 3 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章