你好,C++(22) 排排坐,吃果果——4.3.3 for循環:某個范圍內…每個都…


4.3.3  for循環:某個范圍內…每個都…

既然while語句和do…while…語句都已經可以滿足我們表達循環現象的需要,那為什么C++還要專門提供for語句來表達循環現象呢?在現實世界中,常常有這樣一類特殊的循環現象,例如:

在公司100000個員工范圍內,每個員工都增加10000元工資;

在從1到100這個范圍內,每個數字都累加到總和中。

說這些是循環現象,是因為它們的動作(增加工資、累加)會循環往復反復多次地執行。而說它們特殊,是因為這些動作總是在某個范圍內(100000個員工范圍內、從1到100范圍內)針對其中的每一個元素執行(每個員工都增加,每個數字都累加)。在自然語言中,我們可以用“某個范圍內…每個都…”這種句式來表達這類在某個范圍內進行的循環現象。又因為其非常普遍,為了更方便地表達這類循環現象,所以C++才專門提供了for循環結構語句。在C++中,for循環結構的語法格式如下:

for( 初始化語句;條件判斷語句;更改語句 )
{
    循環體語句;
}

for循環語句所表達的是在某個范圍內的循環現象,所以,其中往往有一個循環索引,它就像一個游標一樣在循環范圍內移動,從而可以通過它依次訪問到循環范圍內的各個元素。而for關鍵字之后的三條語句,就是對這個循環索引進行操作,使其在循環范圍內按照某種規律移動,從而遍歷整個循環范圍。具體而言:

1. 初始化語句

初始化語句會在進入for循環語句執行時被執行一次,主要用來定義循環索引值並進行初始化,將其定位到循環范圍的起始位置。也就是說,它確定的是循環范圍的起點。比如,“int i = 1”就是一個典型的初始化語句,它定義了循環索引值i並將其賦值為1,也就表示這個循環是從1開始的(在C++中,我們往往用0作為循環起點)。

2. 條件判斷語句

作為每次循環的開始,條件判斷語句都會被執行一次,如果其值為true,會繼續向下執行循環體語句。反之,則直接結束整個for循環的執行。因此,它主要用來判斷循環索引值是否在循環范圍的結束位置之內。如果在范圍之內,條件判斷語句的值就是true,for循環語句會開始下一次循環繼續向下執行循環體語句。反之,如果循環索引值超出了循環范圍的結束位置,條件語句的值就是false,for循環將不再繼續而直接結束整個for循環。從這個意義上講,它確定了循環范圍的終點。例如,“i <= 100”就是一個典型的條件判斷語句,在每次循環開始之前,它都會判斷循環索引i是否在循環范圍的結束位置100之內,以決定是否開始這一次循環體語句的執行,以此來將循環限定在循環范圍之內。

3. 更改語句

更改語句會在每次循環體語句執行結束后被執行,主要用來對循環索引值進行修改,使其按照某種規律,逐漸地依次從循環起點變化到循環終點。在這個過程中,我們就可以根據這個不斷變化的循環索引值訪問這個循環范圍內的每個元素,這一過程通常也被稱為對循環范圍內元素的遍歷。例如,“++i”這個更改語句,就是讓循環索引i在每次循環后增加1,使其向循環范圍的結束位置移動一步。這樣,循環索引i就可以從循環起點1逐漸遞增到循環終點100,這樣我們就有機會訪問到循環范圍內的每一個元素。

最佳實踐:注意循環條件的處理,避免形成死循環

所謂死循環,就是指循環沒有結束的機會,會一次又一次永遠執行下去的循環。任何循環都必須在一定條件下結束循環,或者是因為條件判斷語句的值為false而結束循環,或者是在循環內部在一定條件下用break關鍵字結束循環,總之一定要有結束循環的機會,否則就會成為死循環一直執行下去,導致循環后面的代碼得不到執行,自然也就得不到正確的結果。例如,在前面的例子中,“0 != nInput”這個條件判斷語句就有其值成為fasle的機會,那就是用戶輸入的nInput的值為0的時候。所以,這個循環有機會結束而不會成為死循環。

循環的結束往往是由條件判斷語句決定的,所以我們在處理條件判斷語句時要格外小心。如果處理不當,就可能導致無論怎么執行,其值始終是true,這樣循環就永遠沒有機會結束而形成一個死循環。例如:

// 條件判斷語句處理不當形成的死循環
// 忘掉了變更語句,但是仍能編譯通過
for(int i = 0; i < 10000;) 
{
    cout<<"I LOVE YOU!"<<endl;
}

這段程序的本意是想說一萬遍“I LOVE YOU!”裝情聖,結果卻忘了在更改語句中對循環索引i進行更改,這樣,循環索引i的值始終是最初的0,而條件判斷語句“i<10000”的值也就始終為true,循環始終無法結束而成為一個死循環,結果就成了喋喋不休地說“I LOVE YOU!”,自然只會被人當成傻瓜了。如果不想從情聖變傻瓜,那就好好處理我們的條件判斷語句,盡量避免死循環的出現。

for關鍵字之后的三個語句是對循環條件進行處理,那循環體語句就表達的是循環動作。在執行的時候,for循環會首先執行一次初始化語句,然后再執行條件判斷語句,如果其值為true,則意味着當前循環條件滿足,就會開始向下執行循環體語句,完成后,接着會執行更改語句對循環索引值進行修改,隨后會再次執行條判斷語句,以判斷循環條件是否仍然滿足,如果滿足,則開始下一次循環。這個過程會不斷循環下去,直到條件判斷的值為false,循環條件不再滿足為止。for循環的執行過程如圖4-5所示。

在整個循環過程中,循環索引的值會按照某種規律依次從循環開始位置變化到循環的結束位置,這也就意味着,在每次循環中,循環索引的值是不斷變化的,而利用這些不斷變化的索引值,我們就可以訪問到循環范圍內的各個數據。例如,”nTotal += i;” 就是一個典型的循環體語句,每次循環的時候,它將循環索引值i加和到nTotal中,而循環索引值i的值又是從1(int i = 1)到100(i <= 100)逐漸遞增(++i)的,這也就相當於nTotal依次加上了1、2、3…99、100,自然最后得到的就是從1到100所有整數的累加和了。

按照上面我們對for循環各個部分的分析,我們可以得出這個計算從1到100所有整數和的for循環:

// 計算從1到100之間所有整數的和
// 記錄和值
int nTotal = 0;
// 使用for循環,將1到100之間的整數逐個跟nTotal相加
for( int i = 1 ;  // 循環起點
i <= 100 ;    // 循環終點
++i )          // 循環索引值變化規律
{
    // 將整數累加
    nTotal += i;
}

cout<<"1到100之間所有整數的和是"<<nTotal<<endl;

4.3.4  循環控制:break和continue

雖然循環現象會周而復始不斷地執行,但也有遇到意外情況循環被打破的時候。例如:

一直不斷地為祖國辛勤工作,只要我還活着。但如果生病了,只好提前退休;

公司100000位員工,除了年齡超過50歲的人之外,其余每個人的工資都增加10000元;

這里,循環現象中出現的“生病”和“年齡超過50歲”,就打破了原來的循環,屬於循環現象中的例外情況,需要特殊處理,有的需要提前終止循環(生病退休),有的需要跳過循環體的執行(不增加工資)而直接開始下一次循環。為了描述循環中的例外情況,C++提供了兩個關鍵字:break和continue。

1. break

在介紹switch並列條件選擇語句時已經介紹過break關鍵字,它的作用就是結束整個switch語句的執行。與之類似的,當它用在循環結構中時,其作用也同樣是結束當前循環控制語句,繼續執行循環語句之后的下一條語句。這樣,我們就可以利用它來表達那些因例外情況而需要提前結束的循環現象。例如,用它來表達因“生病”這一例外情況而“提前退休”的循環現象:

// 是否活着
bool bAlive = true;
// 是否生病
bool bSick = false;

while(bAlive) // 判斷是否活着
{
    if(bSick) // 判斷是否生病
    {
         cout<<"生病了提前退休"<<endl;
          break; // 因為生病這一例外情況而提前結束循環
    }

    cout<<"為祖國辛勤工作"<<endl;
    // 改變循環控制條件bAlive…
}

//

在執行循環體語句的時候,會首先用if條件語句判斷是否生病,也就是判斷例外情況是否發生。如果例外情況發生,bSick的值會變為true,程序會進入if條件語句內部執行,當遇到break關鍵字之后,就會跳出循環,結束整個循環的執行。這樣,if條件語句負責對是否發生例外情況進行判斷,而break關鍵字則負責在例外情況發生的時候提前結束循環。兩者結合起來,就很好地表達了那些因發生例外情況而需要提前結束的循環現象。

我們可以再來看一個實際的例子,還是那個收支統計程序,我們可以用break關鍵字將其改寫為:

int nTotal = 0;
int nInput = 0;

do
{
    cout << "請輸入你的收入或支出:";
    cin>>nInput;   
    // 對輸入的數據進行判斷,
    // 如果是0這種例外情況,表示輸入結束,用break關鍵字結束整個循環
    if( 0 == nInput )
        break;

    // 正常情況,將輸入的收支數目加和到收支總數
     nTotal += nInput;

} while ( true ); // 用true作循環條件,表示循環會在內部因例外情況而結束

在這里,我們用true作為do…while…循環語句的條件判斷語句,但這並不是一個“死循環”,因為它有結束循環的機會,那就是當用戶輸入的nInput為0時,程序會進入“if( 0 == nInput )”條件語句執行,遇到其中的break關鍵字就會結束整個循環,從而避免了成為死循環。同時,它也表達了對“輸入的收支數目為0”這一例外情況的處理:結束整個循環。經過這樣的改寫后,循環語句可以無限地接受用戶的輸入,但是當用戶想結束輸入的時候,只需要輸入0滿足“0 == nInput”這個意外情況條件,執行break關鍵字就可以結束整個循環的執行。

2.  continue

break關鍵字是在某種條件下結束整個循環,而continue關鍵字則是在某種條件下結束本次循環體(也就是跳過continue關鍵字之后的所有循環體語句)的執行,然后直接繼續向下嘗試下一次循環。如果是while或do…while…循環,會直接判斷循環條件是否滿足以開始下一次循環;如果是for循環,則會接着執行更改語句然后再判斷循環條件是否滿足以開始下一次循環。還是使用上面的收支統計例子,如果一個大款對小於10000元的小錢根本不在乎,只想統計大於等於10000的收入和支出,則可以用continue關鍵字將程序改寫如下:

// 大款的收支統計程序
int nTotal = 0;
int nInput = 0;

do
{
    cout << "請輸入你的收入或支出:";
    cin>>nInput;
 
    // 如果是小於10000的小錢,不用統計在內
    if( (nInput > -10000) && (nInput < 10000) )
        continue; // 跳過后面的循環體語句,不進行統計

    nTotal += nInput;
} while ( 0 != nInput );

在這個大款的收支統計程序中,當nInput接收用戶輸入數據后,我們用if條件語句判斷其數值是否小於10000。如果小於,表示這是不用統計的小錢,則執行if條件語句中的continue關鍵字,跳過后面的加和統計語句“nTotal += nInput;”的執行不將其統計在內,而直接跳轉到對條件表達式“0 != nInput”的計算,以判斷是否可以開始下一次循環。這樣,就很好地表達了對“收支數目小於10000”這種例外情況的特殊處理:結束本次循環,不將其統計在內。

總結起來,break和continue常常和條件語句混合使用,條件語句負責判斷是否出現例外情況,而它們則表達對例外情況的處理:break是跳出整個循環,立刻結束循環控制語句的執行;而continue只跳出本次循環,結束本次循環的執行而繼續執行下一次循環。圖4-6展示了break和continue之間的區別。

 

圖4-6  break和continue之間的區別


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM