《C++ Primer》閱讀筆記(五)語句

第5章 語句

簡單語句(Simple Statements)

如果在程序的某個地方,語法上需要一條語句但是邏輯上不需要,則應該使用空語句(null statement)。空語句中只含有一個單獨的分號;

// read until we hit end-of-file or find an input equal to sought
while (cin >> s && s != sought)
    ;   // null statement

使用空語句時應該加上註釋,從而令讀這段代碼的人知道該語句是有意省略的。

多餘的空語句並非總是無害的。

// disaster: extra semicolon: loop body is this null statement
while (iter != svec.end()) ;    // the while body is the empty statement
    ++iter;     // increment is not part of the loop

複合語句(compound statement)是指用花括號括起來的(可能爲空)語句和聲明的序列。複合語句也叫做塊(block),一個塊就是一個作用域。在塊中引入的名字只能在塊內部以及嵌套在塊中的子塊裏訪問。通常,名字在有限的區域內可見,該區域從名字定義處開始,到名字所在(最內層)塊的結尾處爲止。

語句塊不以分號作爲結束。

空塊的作用等價於空語句。

語句作用域(Statement Scope)

可以在ifswitchwhilefor語句的控制結構內定義變量,這些變量只在相應語句的內部可見,一旦語句結束,變量也就超出了其作用範圍。

while (int i = get_num())   // i is created and initialized on each iteration
    cout << i << endl;
i = 0;  // error: i is not accessible outside the loop

條件語句(Conditional Statements)

if語句(The if Statement)

if語句的形式:

if (condition)
    statement

if-else語句的形式:

if (condition)
    statement
else
    statement2

其中condition是判斷條件,可以是一個表達式或者初始化了的變量聲明。condition必須用圓括號括起來。

  • 如果condition爲真,則執行statement。執行完成後,程序繼續執行if語句後面的其他語句。
  • 如果condition爲假,則跳過statement。對於簡單if語句來說,程序直接執行if語句後面的其他語句;對於if-else語句來說,程序先執行statement2,再執行if語句後面的其他語句。

if語句可以嵌套,其中else與離它最近的尚未匹配的if相匹配。

switch語句(The switch Statement)

switch語句的形式:

switch語句先對括號裏的表達式求值,值轉換成整數類型後再與每個case標籤(case label)的值進行比較。如果表達式的值和某個case標籤匹配,程序從該標籤之後的第一條語句開始執行,直到到達switch的結尾或者遇到break語句爲止。case標籤必須是整型常量表達式。

通常情況下每個case分支後都有break語句。如果確實不應該出現break語句,最好寫一段註釋說明程序的邏輯。

儘管switch語句沒有強制要求在最後一個case標籤後寫上break,但爲了安全起見,最好添加break。這樣即使以後增加了新的case分支,也不用再在前面補充break語句了。

switch語句中可以添加一個default標籤(default label),如果沒有任何一個case標籤能匹配上switch表達式的值,程序將執行default標籤後的語句。

即使不準備在default標籤下做任何操作,程序中也應該定義一個default標籤。其目的在於告訴他人我們已經考慮到了默認情況,只是目前不需要實際操作。

不允許跨過變量的初始化語句直接跳轉到該變量作用域內的另一個位置。如果需要爲switch的某個case分支定義並初始化一個變量,則應該把變量定義在塊內。

case true:
{
    // ok: declaration statement within a statement block
    string file_name = get_file_name();
    // ...
}

迭代語句(Iterative Statements)

迭代語句通常稱爲循環,它重複執行操作直到滿足某個條件才停止。whilefor語句在執行循環體之前檢查條件,do-while語句先執行循環體再檢查條件。

while語句(The while Statement)

while語句的形式:

while (condition)
    statement

只要condition的求值結果爲true,就一直執行statement(通常是一個塊)。condition不能爲空,如果condition第一次求值就是falsestatement一次都不會執行。

定義在while條件部分或者循環體內的變量每次迭代都經歷從創建到銷燬的過程。

在不確定迭代次數,或者想在循環結束後訪問循環控制變量時,使用while比較合適。

傳統的for語句(Traditional for Statement)

for語句的形式:

for (initializer; condition; expression)
    statement

一般情況下,initializer負責初始化一個值,這個值會隨着循環的進行而改變。condition作爲循環控制的條件,只要condition的求值結果爲true,就執行一次statement。執行後再由expression負責修改initializer初始化的變量,這個變量就是condition檢查的對象。如果condition第一次求值就是falsestatement一次都不會執行。initializer中也可以定義多個對象,但是只能有一條聲明語句,因此所有變量的基礎類型必須相同。

for語句頭中定義的對象只在for循環體內可見。

範圍for語句(Range for Statement)

範圍for語句的形式:

for (declaration : expression)
    statement

其中expression表示一個序列,擁有能返回迭代器的beginend成員。declaration定義一個變量,序列中的每個元素都應該能轉換成該變量的類型(可以使用auto)。如果需要對序列中的元素執行寫操作,循環變量必須聲明成引用類型。每次迭代都會重新定義循環控制變量,並將其初始化爲序列中的下一個值,之後纔會執行statement

do-while語句(The do-while Statement)

do-while語句的形式:

do
    statement
while (condition);

計算condition的值之前會先執行一次statementcondition不能爲空。如果condition的值爲false,循環終止,否則重複執行statement

因爲do-while語句先執行語句或塊,再判斷條件,所以不允許在條件部分定義變量。

跳轉語句(Jump Statements)

跳轉語句中斷當前的執行過程。

break語句(The break Statement)

break語句只能出現在迭代語句或者switch語句的內部,負責終止離它最近的whiledo-whilefor或者switch語句,並從這些語句之後的第一條語句開始執行。

string buf;
while (cin >> buf && !buf.empty()) 
{
    switch(buf[0])
    {
        case '-':
            // process up to the first blank
            for (auto it = buf.begin()+1; it != buf.end(); ++it)
            {
                if (*it == ' ')
                break;  // #1, leaves the for loop
                // . . .
            }
            // break #1 transfers control here
            // remaining '-' processing:
            break;  // #2, leaves the switch statement
        case '+':
    // . . .
    } // end switch
// end of switch: break #2 transfers control here
} // end while

continue語句(The continue Statement)

continue語句只能出現在迭代語句的內部,負責終止離它最近的循環的當前一次迭代並立即開始下一次迭代。和break語句不同的是,只有當switch語句嵌套在迭代語句內部時,才能在switch中使用continue

continue語句中斷當前迭代後,具體操作視迭代語句類型而定:

  • 對於whiledo-while語句來說,繼續判斷條件的值。
  • 對於傳統的for語句來說,繼續執行for語句頭中的第三部分,之後判斷條件的值。
  • 對於範圍for語句來說,是用序列中的下一個元素初始化循環變量。

goto語句(The goto Statement)

goto語句(labeled statement)是一種特殊的語句,在它之前有一個標識符和一個冒號。

end: return; // labeled statement; may be the target of a goto

標籤標識符獨立於變量和其他標識符的名字,它們之間不會相互干擾。

goto語句的形式:

goto label;    

goto語句使程序無條件跳轉到標籤爲label的語句處執行,但兩者必須位於同一個函數內,同時goto語句也不能將程序的控制權從變量的作用域之外轉移到作用域之內。

建議不要在程序中使用goto語句,它使得程序既難理解又難修改。

try語句塊和異常處理(try Blocks and Exception Handling)

異常(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表達式(A throw Expression)

throw表達式包含關鍵字throw和緊隨其後的一個表達式,其中表達式的類型就是拋出的異常類型。

try語句塊(The try Block)

try語句塊的通用形式:

try 
{
    program-statements
} 
catch (exception-declaration) 
{
    handler-statements
} 
catch (exception-declaration) 
{
    handler-statements
} // . . .

try語句塊中的program-statements組成程序的正常邏輯,其內部聲明的變量在塊外無法訪問,即使在catch子句中也不行。catch子句包含關鍵字catch、括號內一個對象的聲明(異常聲明,exception declaration)和一個塊。當選中了某個catch子句處理異常後,執行與之對應的塊。catch一旦完成,程序會跳過剩餘的所有catch子句,繼續執行後面的語句。

如果最終沒能找到與異常相匹配的catch子句,程序會執行名爲terminate的標準庫函數。該函數的行爲與系統有關,一般情況下,執行該函數將導致程序非正常退出。類似的,如果一段程序沒有try語句塊且發生了異常,系統也會調用terminate函數並終止當前程序的執行。

標準異常(Standard Exceptions)

異常類分別定義在4個頭文件中:

  • 頭文件exception定義了最通用的異常類exception。它只報告異常的發生,不提供任何額外信息。

  • 頭文件stdexcept定義了幾種常用的異常類。

  • 頭文件new定義了bad_alloc異常類。

  • 頭文件type_info定義了bad_cast異常類。

標準庫異常類的繼承體系:

只能以默認初始化的方式初始化exceptionbad_allocbad_cast對象,不允許爲這些對象提供初始值。其他異常類的對象在初始化時必須提供一個string或一個C風格字符串,通常表示異常信息。what成員函數可以返回該字符串的string副本。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章