switch語句
不允許跨過變量的初始化語句直接跳轉到該變量作用域內的另一個位置。如果需要爲 switch
的某個 case
分支定義並初始化一個變量,則應該把變量定義在塊內。
case true:
{
// 正確:聲明語句位於語句塊內部
string file_name = get_file_name();
// ...
}
break;
case false:
if (file_name.empty()) // 錯誤:file_name不在作用域之內
迭代語句
迭代語句通常稱爲循環,它重複執行操作直到滿足某個條件才停止。while
和 for
語句在執行循環體之前檢查條件,do-while
語句先執行循環體再檢查條件。
for循環執行順序
for
循環的表達式一般如下:
for(表達式1;表達式2;表達式3){
表達式4;
}
執行的順序爲:
1)第一次循環,即初始化循環。
首先執行表達式1(一般爲初始化語句),再執行表達式2(一般爲條件判斷語句),判斷表達式1是否符合表達式2的條件,如果符合,則執行表達式4,否則,停止執行,最後執行表達式3.
2)下次的循環:
首先執行表達式2,判斷表達式3是否符合表達式2的條件;如果符合,繼續執行表達式4,否則停止執行,最後執行表達式3.如果往復,直到表達式3不再滿足表達式2的條件。
總結:總的來說,執行順序是一致的,先進行條件判斷(表達式2),再執行函數體(表達式4),最後執行表達式3。如此往復,區別在於,條件判斷的對象,在第一次判斷時,是執行表達式1,初始化對象,後續的判斷對象是執行後的結果(表達式3)
try語句塊和異常處理
異常(exception) 是指程序運行時的反常行爲,這些行爲超出了函數正常功能的範圍。當程序的某一部分檢測到一個它無法處理的問題時,需要使用異常處理(exception handling)。
異常處理機制包括 throw
表達式(throw expression)、try
語句塊(try block)和異常類(exception class)。
- 異常檢測部分使用
throw
表達式表示它遇到了無法處理的問題(throw 引發了異常)。 - 異常處理部分使用
try
語句塊處理異常。try
語句塊以關鍵字try
開 始,並以一個或多個catch
子句(catch clause)結束。try 語句塊中代碼拋出的異常通常會被某個catch
子句處理,catch
子句也被稱作異常處理代碼(exception handler)。 - 異常類用於在
throw
表達式和相關的catch
子句之間傳遞異常的具體信息。
throw表達式
程序的異常檢測部分使用throw
表達式引發一個異常。throw
表達式包含關鍵字throw
和緊隨其後的一個表達式,其中表達式的類型就是拋出的異常類型。
// 首先item1和item2是否表示同一種書籍
if (item1.isbn() != item2.isbn())
throw runtime_error("Data must refer to same ISBN");
// 如果程序執行到了這裏,表示兩個ISBN相同
cout << item1 + item2 << endl;
在上述代碼中,如果ISBN編號不同則拋出一個類型爲runtime_error
的異常。類型runtime_error
是標準庫異常類型的一種,定義在stdexcept
頭文件中。需要對runtime_error
對象進行初始化,方式是提供一個string
對象或者C風格字符串作爲參數。
try語句塊
try
語句塊的通用語法形式:
try {
program-statements
}
catch (exception-declaration) {
handler-statements
}
catch (exception-declaration) {
handler-statements
} // . . .
try
語句塊中的 program-statements
組成程序的正常邏輯,其內部聲明的變量在塊外無法訪問,即使在catch
子句中也不行。try
語句塊之後是catch
子句,當選中了某個 catch
子句處理異常後,執行與之對應的塊。catch
一旦完成,程序會跳過剩餘的所有 catch
子句,繼續執行後面的語句。
while (cin >> item1 >> item2) {
try {
// 執行添加兩個Sales_item對象的代碼
// 如果添加失敗,代碼拋出一個runtime_error異常
} catch (runtime_error err) {
// 提醒用戶兩個ISBN必須一致,詢問是否重新輸入
cout << err.what()
<< "\nTry Again? Enter y or n" << endl;
char c;
cin >> c;
if (!cin || c == 'n')
break; // 跳出while循環
}
}
在複雜系統中,程序在拋出異常前,其執行路徑可能已經經過了多個try
語句塊。一個try
語句塊可能調用了包含另一個try
語句塊的函數。尋找處理代碼的過程與函數調用鏈剛好相反。當異常被拋出時, 首先搜索拋出該異常的函數。如果沒找到匹配的 catch
子句, 終止該函數, 並在調用該函數的函數中繼續尋找。如果還是沒有找到匹配的 catch
子句,這個新的函數也被終止, 繼續搜索調用它的函數。以此類推,沿着程序的執行路徑逐層回退,直至找到適當類型的 catch
子句爲止。如果最終沒能找到與異常相匹配的 catch
子句,程序會執行名爲 terminate
的標準庫函數。該函數的行爲與系統有關,一般情況下,執行該函數將導致程序非正常退出。類似地,如果一段程序沒有 try
語句塊且發生了異常,系統也會調用 terminate
函數並終止當前程序的執行。
標準異常
-
exception
頭文件 定義了最通用的異常類exception
。它只報告異常的發生,不提供任何額外信息。 -
stdexcept
頭文件定義了幾種常用的異常類。 -
new
頭文件定義了bad_alloc
異常類。 -
type_info
頭文件 定義了bad_cast
異常類。
標準庫異常類的繼承體系如下:
只能以默認初始化的方式初始化exception
、bad_alloc
和bad_cast
對象,不允許爲這些對象提供初始值。
其他異常類型的行爲則恰好相反:應該使用string
對象或者C風格字符串初始化這些類型的對象,但是不允許使用默認初始化的方式,當創建此類對象時,必須提供初始值,該初始值含有錯誤相關的信息。
異常類型只定義了一個名爲what
的成員函數,該函數返回一個指向C風格字符串的const char*
,用於提供關於異常的一些文本信息。
練習
- 統計字符串中含以下兩個字符的字符序列的數量:ff、fl 和 fi。
#include <iostream>
using namespace std;
int main()
{
unsigned int ffCnt = 0, flCnt = 0, fiCnt = 0;
char ch, prech = '\0';
cout << "Please input a string:" << endl;
while (cin >> ch)
{
bool bl = true;
if (prech == 'f')
{
switch (ch)
{
case 'f':
++ffCnt;
bl = false;
break;
case 'l':
++flCnt;
break;
case 'i':
++fiCnt;
break;
}
}
if (!bl)
prech = '\0';
else
prech = ch;
}
cout << "Number of ff: \t" << ffCnt << '\n'
<< "Number of fl: \t" << flCnt << '\n'
<< "Number of fi: \t" << fiCnt << endl;
system("pause");
return 0;
}
2. 編寫一段程序,從標準輸入中讀取若干 string
對象並查找連續重複出現的單詞,所謂連續重複出現的意思是:一個單詞後面緊跟着這個單詞本身。要求記錄連續重複出現的最大次數以及對應的單詞。如果這樣的單詞存在,輸出重複出現的最大次數;如果不存在,輸出一條信息說明任何單詞都沒有連續出現過。
#include <iostream>
#include <string>
using namespace std;
int main()
{
string cur_str = "", pre_str = "", max_str = "";
unsigned int count = 1, max = 0;
while(cin >> cur_str){
if(cur_str == pre_str){
++count;
if(count > max){
max = count;
max_str = cur_str;
}
}else{
count = 1;
}
pre_str = cur_str;
}
if(max > 1){
cout << "The string that appear most frequently is: " << max_str << endl;
}
system("pause");
return 0;
}
3. 編寫一段程序,從標準輸入讀取兩個整數,輸出第一個數除以第二個數的結果。使用 try
語句塊去捕獲異常。catch
子句應該爲用戶輸出一條提示信息,詢問其是否輸入新數並重新執行try
語句塊的內容。
#include <iostream>
using namespace std;
int main()
{
int ival1, ival2;
while(cin >> ival1 >> ival2){
try{
if (ival2 == 0)
{
throw runtime_error("The divisor cannot be 0");
}
cout << "The div result is:" << ival1 / ival2 << endl;
}catch(runtime_error error){
cout <<error.what() <<endl;
cout << "do you want to continue?(y/n)" << endl;
char ch;
cin >> ch;
if(ch != 'y' && ch!='Y')
break;
}
}
system("pause");
return 0;
}