天天看點

C++程式設計:流程控制語句

作者:尚矽谷教育

C++程式執行的流程結構可以有三種:順序、分支和循環。除了最簡單的順序結構是預設的,分支和循環都需要使用專門的“流程控制語句”來定義。

C++程式設計:流程控制語句

1. 語句

C++中表示一步操作的一句代碼,就叫做“語句”(statement),大多數語句都是以分号“;”結尾的。C++程式運作的過程,其實就是找到主函數,然後從上到下順序執行每條語句的過程。

1.1 簡單語句

使用各種運算符,作用到資料對象上,就得到了“表達式”;一個表達式末尾加上分号,就構成了“表達式語句”(expression statement)。

表達式語句表示,要執行表達式的計算過程,并且丢棄最終傳回的結果。

int a = 0; // 變量定義并初始化語句

a + 1; // 算術表達式語句,無意義

++a; // 遞增語句,a的值變為1

cout << " a = " << a << endl; // 輸出語句

其中第二行a + 1; 是沒什麼意義的,因為它隻是執行了加法操作,卻沒有把結果儲存下來(指派給别的變量),a的值也沒有改變,也沒有任何附帶效果(比如最後一句的輸出)。

最簡單的語句,其實是“空語句”,就是隻有一個分号的語句:

; // 空語句

這看起來好像沒什麼用。不過有時候,可能程式在文法上需要有一條語句,而邏輯上什麼都不用做;這時就應該用一條空語句來填充。

初學C++,一定不要忘記語句末尾的分号;當然,對于不需要分号的場景,也盡量避免多寫分号。

1.2 複合語句

簡單語句從上到下按順序依次執行,這非常符合我們對計算機運作的預期。但是很多場景下,簡單的順序結構遠遠不能滿足邏輯需要:比如我們可能需要按照條件判斷,做程式的分支執行;也可能需要将一段代碼循環執行多次。這就需要一些“流程控制語句”(比如if、while、for等)來表達更加複雜的操作了。

而對于流程控制語句,邏輯上來說隻是一條語句;事實上卻可能包含了多條語句、複雜的操作。這就需要用一個花括号“{}”,把這一組語句序列包成一個整體,叫做“複合語句”(compound statement),也叫做“塊”(block)。

int i = 0;

while (i < 5) {

int a = i;

++i;

}

這裡的while表示一個循環,後面隻能跟要循環執行的一條語句;如果我們想寫兩條語句,就要用花括号括起來,構成“塊”。

對于複合語句(塊)需要注意:

l 花括号後面不需要再加分号,塊本身就是一條語句;

l 塊内可以聲明變量,變量的作用域僅限于塊内部;

l 隻有一對花括号、内部沒有任何語句的塊叫做“空塊”,等價于空語句;

2. 條件分支

很多情況下,我們為程式的執行會提供“岔路”的選擇機會。一般都是:滿足某種條件就執行A操作,滿足另一種條件就執行B操作……這樣的程式結構叫做“條件分支”。

C++提供了兩種按條件分支執行的控制語句:if和switch。

2.1 if

if語句主要就是判斷一個條件是否為真(true),如果為真就執行下面的語句,如果為假則跳過。具體形式可以分為兩種:一種是單獨一個if,一般稱為“單分支”;另一種是if … else …,稱為“雙分支”。

C++程式設計:流程控制語句

(1)單分支

單分支是最簡單的if用法,判斷的條件用小括号括起來跟在if後面,然後是如果條件為真要執行的語句。基本形式為:

if (條件判斷)

語句

如果條件為假,那麼這段代碼就會被完全跳過。

我們可以舉一個簡單示例,判斷輸入的年齡數值,然後輸出一句歡迎詞:

#include<iostream>

using namespace std;

int main()

{

cout << "請輸入您的芳齡:" << endl;

int age;

cin >> age;

if ( age >= 18 )

{

cout << "歡迎您,成年人!" << endl;

}

cin.get();

cin.get();

}

通常會用一個花括号将if後面的語句括起來,成為一個“塊”。現在塊裡隻有一條語句,是以花括号是可以省略的:

if ( age >= 18 )

cout << "歡迎您,成年人!" << endl;

如果要執行的是多條語句,花括号就不能省略;否則if後面其實就隻有第一條語句。為了避免漏掉括号出現錯誤,一般if後面都會使用花括号。

(2)雙分支

雙分支就是在if分支的基礎上,加了else分支;條件為真就執行if後面的語句,條件為假就執行else後面的語句。基本形勢如下:

if (條件判斷)

語句1

else

語句2

if分支和else分支,兩者肯定會選擇一個執行。

我們可以在之前程式的基礎上,增加一個else分支:

if ( age >= 18 )

{

cout << "歡迎您,成年人!" << endl;

}

else

{

cout << "本程式不歡迎未成年人!" << endl;

}

我們可以回憶起來,之前介紹過的唯一一個三元運算符——條件運算符,其實就可以實作類似的功能。是以條件運算符可以認為是if … else 的一個文法糖。

以下兩條語句跟上面的if…else是等價的:

// 條件運算符的等價寫法

age >= 18 ? cout << "歡迎您,成年人!" << endl : cout << "本程式不歡迎未成年人!" << endl;

cout << (age >= 18 ? "歡迎您,成年人!" : "本程式不歡迎未成年人!") << endl;

(3)嵌套分支(多分支)

程式中的分支有可能不隻兩個,這時就需要對if分支或者else分支再做條件判斷和拆分了,這就是“嵌套分支”。

C++程式設計:流程控制語句

簡單來說,就是if或者else分支的語句塊裡,繼續使用if或者if…else按條件進行分支。這是一種“分層”的條件判斷。

if ( age >= 18 )

{

cout << "歡迎您,成年人!" << endl;

if (age < 35)

{

cout << "加油,年輕人!" << endl;

}

}

else

{

cout << "本程式不歡迎未成年人!" << endl;

if (age >= 12)

{

cout << "少年,好好學習!" << endl;

}

else

{

cout << "小朋友,别玩電腦!" << endl;

}

}

嵌套分支如果比較多,代碼的可讀性會大幅降低。是以還有一種更加簡單的嵌套分支寫法,那就是if … else if …,具體形式如下:

if (條件判斷1)

語句1

else if (條件判斷2)

語句2

else if (條件判斷3)

語句3

else

語句n

這種分支的嵌套,本質上隻能對else分支進行,而且隻能在最底層的分支中才能執行語句。

C++程式設計:流程控制語句

測試代碼如下:

if (age < 12) {

cout << "小朋友,别玩電腦!" << endl;

}

else if (age < 18)

{

cout << "少年,好好學習!" << endl;

}

else if (age < 35)

{

cout << "加油,年輕人!" << endl;

}

else if (age < 60)

{

cout << "加油,中年人!" << endl;

}

else

{

cout << "好好休息,老年人!" << endl;

}

2.2 switch

在一些應用場景中,要判斷的條件可能不是範圍,而是固定的幾個值。比如考試成績隻分“A”“B”“C”“D”四個檔位,分别代表“優秀”“良好”“及格”“不及格”。

C++程式設計:流程控制語句

這個時候如果用if … else會顯得非常繁瑣,而swith語句就是專門為了這種分支場景設計的。

switch文法基本形式如下:

swith (表達式){

case 值1:

語句1

break;

case 值2:

語句2

break;

default:

語句n

break;

}

這裡switch後面的括号裡是一個表達式,對它求值,然後轉換成整數類型跟下面每個case後面的值做比較;如果相等,就進入這個case指定的分支,執行後面的語句,直到swith語句結束或者遇到break退出。需要注意的是:

  • case關鍵字和後面對應的值,合起來叫做一個“case标簽”;case标簽必須是一個整型的常量表達式;
  • 任何兩個case标簽不能相同;
  • break語句的作用是“中斷”,會直接跳轉到switch語句結構的外面;
  • 如果沒有break語句,那麼比對某個case标簽之後,程式會從上到下一直執行下去;這會執行多個标簽下面的語句,可能發生錯誤;
  • 如果沒有比對上任何case标簽的值,程式會執行default标簽後面的語句;default是可選的,表示“預設要執行的操作”。

我們可以利用swith寫一個判斷考試成績檔位,輸入一句相應的話:

#include<iostream>

using namespace std;

int main()

{

cout << "請輸入您的成績:" << endl;

char score;

cin >> score;

switch (score)

{

case 'A':

cout << "成績優秀!" << endl;

break;

case 'B':

cout << "成績良好!" << endl;

break;

case 'C':

cout << "恭喜!及格了!" << endl;

break;

case 'D':

cout << "歡迎下次再來!" << endl;

break;

default:

cout << "錯誤的成績輸入!" << endl;

break;

}

cin.get();

cin.get();

}

3 循環

可以重複執行一組操作的語句叫做“循環”,有時也叫作“疊代”。循環一般不能無限進行下去,是以會設定一個終止的判斷條件。

C++中的循環語句,有while、do while和for三種。

3.1 while

while隻需要給定一個判斷條件,隻要條件為真,就重複地執行語句。形式如下:

while (條件)

語句

要執行的語句往往會有多條,這就需要用花括号将它們括起來。這個塊一般被稱為“循環體”。

一般來說,用來控制while循環的條件中一定會包含變量,通常叫做“循環變量”;而它或者在條件中變化,或者在循環體中變化,這樣才能保證循環能夠終止退出。

比如我們可以用一個循環輸出10次“Hello World”,并且列印出目前循環次數:

#include<iostream>

using namespace std;

int main()

{

cout << "循環開始...\n" << endl;

int i = 1;

while (i <= 10)

{

cout << "Hello World!" << endl;

cout << "現在是第" << i << "次循環\n" << endl;

++i;

}

cout << "循環結束!" << endl;

cin.get();

}

這裡需要注意,循環體最後的 ++i一定不能漏掉。如果沒有這條語句,i的值就不會更改,循環就永遠不會退出。

3.2 do while

do while和while非常類似,差別在于do while是先執行循環體中的語句,然後再檢查條件是否滿足。是以do while至少會執行一次循環體。

do while文法形式如下:

do

語句

while (條件)

我們可以接着之前while循環的代碼繼續測試:

do

{

cout << "現在是倒數第" << --i << "次循環" << endl;

cout << "GoodBye World!\n" << endl;

} while (i > 1);

由于之前的變量i已經做了10次遞增,是以do wihle開始時i的值為11。進入循環體直接輸出内容,每次i遞減1,直到i = 1時退出循環。

3.3 for

通過while和do while可以總結出來,一個循環主要有這樣幾個要素:

l 一個條件,用來控制循環退出;

l 一個循環體,用來定義循環要執行的操作;

而一般情況下,我們都是通過一個循環變量來控制條件的,這個變量需要随着循環疊代次數的增加而變化。while和do while的循環變量,都是在循環體外單獨定義的。

for是用法更加明确的循環語句。它可以把循環變量的定義、循環條件以及循環變量的改變都放在一起,統一聲明出來。

(1)經典for循環

for循環的經典文法形式是:

for (初始化語句; 條件; 表達式)

語句

關鍵字for和它後面括号裡的部分,叫做“for語句頭”。

for語句頭中有三部分,用分号分隔,主要作用是:

  • 初始化語句負責初始化一個變量,這個變量值會随着循環疊代而改變,一般就是“循環變量”;
  • 中間的條件是控制循環執行的關鍵,為真則執行下面的循環體語句,為假則退出。條件一般會以循環變量作為判斷标準;
  • 最後的表達式會在本次循環完成之後再執行,一般會對循環變量進行更改;

這三個部分并不是必要的,根據需要都可以進行省略。如果省略某個部分,需要保留分号表示這是一個空語句。

我們可以用for循環語句,實作之前輸出10次“Hello World”的需求:

#include<iostream>

using namespace std;

int main()

{

for (int i = 1; i <= 10; i++)

{

cout << "Hello World!" << endl;

cout << "現在是第" << i << "次循環!\n" << endl;

}

cin.get();

}

(2)範圍for循環

C++ 11新标準引入了一種更加簡單的for循環,這種語句可以直接周遊一個序列的所有元素。這種for循環叫做“範圍for循環”。文法形式如下:

for (聲明: 序清單達式)

語句

這裡for語句頭中的内容就很簡單了,隻需要聲明一個變量,後面跟上一個冒号(注意不是分号),再跟上一個序列的表達式就可以了。所謂“序列”,其實就是一組相同類型的資料對象排成了一列來統一處理;是以這個聲明的意思,其實就是從序列中依次取出所有元素,每次都指派給這個變量。

是以範圍for循環的特點就是,不需要循環變量,直接就可以通路序列中的所有元素。

// 範圍for循環

for (int num : {3, 6, 8, 10})

{

cout << "序列中現在的資料是:" << num << endl;

}

這裡用花括号把一組數括起來,就構成了最簡單的序列:{3, 6, 8, 10}。後面将要介紹的數組,以及vector、string等類型的對象,也都是序列。

3.4 循環嵌套

循環語句和分支語句一樣,也是可以進行嵌套的。具體可以while循環中嵌套while,可以for循環中嵌套for,也可以while、do while和for混合嵌套。因為for的循環變量定義更明确,是以一般用for的循環嵌套會多一些。

for (int i = 0; i < 3; i++)

{

for (int j = 0; j < 5; j++)

{

cout << "Hello World! i = " << i << ", j = " << j << endl;

}

}

循環嵌套之後,内層語句執行的次數,将是外層循環次數和内層循環次數的乘積。這會帶來大量的時間消耗,使程式運作變慢,是以使用嵌套循環要非常謹慎。

下面是一個使用雙重for循環,列印輸出“九九乘法表”的例子。

#include<iostream>

using namespace std;

int main()

{

// i表示行數,j表示列數

for (int i = 1; i < 10; i++)

{

for (int j = 1; j <= i; j++) {

cout << j << " × " << i << " = " << i * j << "\t";

}

cout << endl;

}

cin.get();

}

這裡使用内外兩層for循環,實作了一個二維“表”的輸出。後面我們會看到,循環嵌套對于處理多元資料非常有用。

4 跳轉

在流程控制語句中還有一類“跳轉語句”,主要用來中斷目前的執行過程。C++中有四種跳轉語句:break,continue,goto以及return。

4.1 break

break語句表示要“跳出”目前的流程控制語句,它隻能出現在switch或者循環語句(while、do while、for)中。當代碼中遇到break時,會直接中斷距離最近的switch或者循環,跳轉到外部繼續執行。

int i = 0;

while (true)

{

cout << " Hello World! " << endl;

cout << " 這是第" << ++i << "次輸出\n" << endl;

if (i >= 5)

{

break;

}

}

如果循環條件永遠為真,那麼循環體中一定要有break,保證在某種情況下程式可以退出循環。

4.2 continue

continue語句表示“繼續”執行循環,也就是中斷循環中的本次疊代、并開始執行下一次疊代。很明顯,continue隻能用在循環語句中,同樣針對最近的一層循環有效。

continue非常适合處理需要“跳過”某些情況的場合。

// 逢7過

for (int num = 1; num < 100; num++)

{

cout << "\t";

// 如果是7的倍數,或者數字中有7,則跳過

if (num % 7 == 0 || num % 10 == 7 || num / 10 == 7)

continue;

cout << num;

// 如果是10的倍數,則換行

if (num % 10 == 0)

cout << endl << endl;

}

上面模拟了一個經典的小遊戲“逢7過”,如果遇到7的倍數比如7、14、21,或者數字中有7比如17、27、71,都要跳過。

4.3 goto

goto語句表示無條件地跳轉到程式中的另一條語句。goto的文法形式為:

goto 标簽;

這裡的“标簽”可以認為是一條語句的“名字”,跟變量類似,隻不過它是指代一條語句的辨別符。定義标簽也非常簡單,隻要在一條語句前寫出辨別符,然後跟上冒号就可以了,比如:

begin: int a = 0;

下面是一個具體的例子:

int x = 0;

cout << "程式開始..." << endl;

begin:

do

{

cout << " x = " << ++x << endl;

} while (x < 10);

if (x < 15) {

cout << "回到原點!" << endl;

goto begin;

}

cout << "程式結束!" << endl;

由于goto可以任意跳轉,是以它非常靈活,也非常危險。一般在代碼中不要使用goto。

4.4 return

return是用來終止函數運作并傳回結果的。之前的Hello World程式中就曾經介紹,主函數最後的那句 return 0; 就是結束主函數并傳回結果,一般這句可以省略。

而在自定義的函數中,同樣可以用return來傳回。

5. 應用案例

綜合利用分支和循環語句,就可以實作很多有趣的功能。

5.1 判斷質數

質數也叫素數,是指一個大于1的自然數,因數隻有1和它自身。質數是數論中一個經典的概念,很多著名定理和猜想都跟它有關;質數也是現代密碼學的基礎。

判斷一個數是否為質數沒有什麼規律可言,我們可以通過驗證小于它的每個數能否整除,來做暴力求解。下面是一段判斷質數、并輸出0~100内所有質數的程式:

#include<iostream>

using namespace std;

// 定義一個判斷質數的函數,用return傳回判斷結果

bool isPrime(int num)

{

int i = 2;

while (i < num)

{

if (num % i == 0) return false;

++i;

}

return true;

}

int main()

{

cout << "請輸入一個自然數(不超過20億):" << endl;

int num;

cin >> num;

if (isPrime(num))

{

cout << num << "是質數!" << endl;

}

else

{

cout << num << "不是質數!" << endl;

}

cout << "\n=========================\n" << endl;

cout << "0 ~ 100 内的質數有:" << endl;

for (int i = 2; i <= 100; i++)

{

if (isPrime(i))

cout << i << "\t";

}

cout << endl;

cin.get();

cin.get();

}

5.2 猜數字

猜數字是一個經典的小遊戲,程式随機生成一個0~100的數字,然後由使用者輸入來猜測。如果猜對,輸出結果并退出;如果不對,則提示偏大還是偏小。我們可以對猜的次數做限制,比如一共5次機會。

#include<iostream>

using namespace std;

int main()

{

cout << "=========猜數字========" << endl;

cout << "規則:輸入0~100的整數,有5次機會\n" << endl;

// 以目前時間為随機數種子,生成一個0~100的僞随機數

srand(time(0));

int target = rand() % 100;

int n = 0; // 猜的次數

while (n < 5)

{

cout << "請輸入0~100的整數:" << endl;

int num;

cin >> num;

if (num == target)

{

cout << "恭喜你,猜對了! 幸運數字是:" << target << endl;

break;

}

else if (num > target)

cout << "數字太大了!再猜一遍!" << endl;

else

cout << "數字太小了!再猜一遍!" << endl;

++n;

}

if (n == 5)

cout << "已經猜過5遍,沒有猜中!歡迎下次再來!" << endl;

cin.get();

cin.get();

}

繼續閱讀