National Yunlin University of Science and Technology
Uedu Main Site
Explore Uedu
Student Console
Register as Member/Login
Research Informed Consent Center
Survey Center
Educational Big Data Challenge
Claim or create a course
Try a Scenario Task
Support & Messages
Uptime Data

UeduGPTs

--

Jupyters

1

Local AI

--

Uedu Code

--

雲林科技大學 AQI 56 27°C PM2.5 10
AI Reply Desktop Notifications

Show a desktop notification when the AI TA finishes replying

Chat Message Notifications

Notify me when classmates post messages in the forum

Sound notification

Play an alert sound whenever there is a new notification

Unit 05

流程控制

if、switch、for、while 與 do-while
Interaction實作 20 minute(s)

Learning Objectives

  • 用 if、else if、else 依條件選擇要執行的程式,並看懂巢狀 if 與條件運算子 ?:
  • 用 switch 比對整數或字元,說明 break 的作用與 fall-through
  • 依情況選用 for、while、do-while 迴圈
  • 用 break、continue 控制迴圈,追蹤巢狀迴圈的執行順序
  • 辨認常見錯誤:= 與 == 混用、if 後面多一個分號、無窮迴圈

程式不只從上往下跑

到目前為止的程式都是一行接一行、從上往下執行。真正的程式需要做選擇(分數夠高才印「及格」)和重複(把 1 到 100 加起來), 這兩件事合稱流程控制(control flow):

需求 用什麼
條件成立才做 if、if … else、else if
依某個值分成好幾種情況 switch
知道要重複幾次 for
不知道次數,條件成立就繼續 while
至少要做一次 do … while

本課每個範例都可以逐步播放。注意左邊的箭頭:條件不成立時,箭頭會跳過那一段;迴圈每跑完一輪,箭頭會跳回迴圈開頭。

if、else if、else

if (條件) {
    // 條件為 true 時執行
} else if (另一個條件) {
    // 前面的條件都不成立、這個條件成立時執行
} else {
    // 以上都不成立時執行
}
  • 條件放在小括號裡,結果是 true 或 false。整數也可以當條件:0 是 false,其他值都是 true
  • 一串 if … else if … else 由上往下檢查,只會執行第一個成立的那一段,後面的就不再檢查
  • 大括號裡只有一行時可以省略大括號,但建議一律寫上,之後加程式碼時比較不會出錯
  • if 裡面還可以再放 if,稱為巢狀 if;else 屬於離它最近、還沒有配對的 if

條件運算子 條件 ? 值1 : 值2:條件成立時得到值1,否則得到值2。適合「二選一指定給變數」這種短的情況:

string label = (score >= 60) ? "及格" : "不及格";

成績分級:if、巢狀 if 與 ?:

score 是 72。看箭頭停在哪些 if 與 else if:前兩個條件不成立,第三個成立之後,else 那一段就直接跳過。想一想:把 score 改成 85,箭頭會怎麼走?

switch:依一個值分成好幾種情況

switch (運算式) {
    case 常數1:
        // ...
        break;
    case 常數2:
        // ...
        break;
    default:
        // 都不符合時
}
  • switch 的運算式要是整數類的值(int、char、enum 等),不能是 double 或 string
  • 每個 case 後面是一個常數,不能寫範圍或變數;要比對範圍(例如 80~89 分)請用 if
  • 程式跳到符合的 case 之後,會一直往下執行,直到遇到 break 或 switch 結束。忘了寫 break,就會連下一個 case 的程式也一起執行, 這叫做 fall-through
  • 刻意讓幾個 case 共用一段程式時,把它們連著寫(case 'B': case 'C':),這是 fall-through 的正當用法
  • default 是「以上都不符合」,可以省略

C++17 加入了 [[fallthrough]]; 標記,寫在 case 的最後,表示「這裡是刻意不寫 break」。 g++ 加上 -Wextra 編譯時會對沒有標記的 fall-through 提出警告,有標記就不會。本站的逐步執行器目前不支援這個標記,所以範例裡沒有使用。

switch、break 與 fall-through

箭頭從 switch 那一行直接跳到符合的 case 底下。第一段 grade 是 'B',和 'C' 共用同一段程式;最後一段 level 是 2,因為沒有 break,從「第二關」一路印到「第三關」。

想一想:if 與 switch

1.

下面的程式會印出什麼?

int x = 15;
if (x > 10) {
    cout << "A";
} else if (x > 5) {
    cout << "B";
} else {
    cout << "C";
}
2.

下面的程式會印出什麼?

int n = 1;
switch (n) {
    case 1: cout << "1";
    case 2: cout << "2"; break;
    case 3: cout << "3";
}
3.

下面的程式會印出什麼?

int a = 7;
cout << (a % 2 == 0 ? "even" : "odd");
第 1 次作答

三種迴圈

for (初始化; 條件; 更新) { ... }     // 先初始化一次,每輪先檢查條件,做完再更新
while (條件) { ... }                // 每輪先檢查條件
do { ... } while (條件);            // 先做一次,再檢查條件(結尾要分號)
迴圈 什麼時候用 最少執行幾次
for 次數已知,例如「從 1 數到 n」 0 次
while 次數不知道,例如「一直除以 10 直到變成 0」 0 次
do-while 至少要先做一次,例如「先顯示選單,再問要不要繼續」 1 次

for (int i = 1; i <= 5; i++) 裡宣告的 i 只在這個迴圈裡有效,迴圈結束後就消失了。在動畫的變數區可以看到 i 在迴圈結束後不見。

for、while、do-while

注意三件事:for 每一輪箭頭都會回到第 7 行(更新 i、再檢查條件);while 回到第 14 行;do-while 的條件 k < 3 一開始就不成立,但因為先做再檢查,還是執行了一次。

break、continue 與巢狀迴圈

  • break:立刻離開最內層的迴圈(或 switch),接著執行迴圈後面的程式
  • continue:跳過這一輪剩下的程式,直接進入下一輪;在 for 迴圈裡會先執行更新(i++)再檢查條件

迴圈裡面可以再放迴圈,稱為巢狀迴圈。外層每跑一輪,內層就從頭跑完一整輪。印表格、走訪二維資料都會用到。 注意 break 與 continue 只影響它所在的那一層迴圈。

break、continue 與巢狀迴圈

第一段:偶數時箭頭停在第 8 行的 continue,接著直接回到第 6 行;i 是 9 時遇到 break,迴圈提早結束,10 沒有被檢查。第二段:看 row 與 col 的變化,內層迴圈跑的次數等於 row。

常見錯誤

下面三種錯誤都能通過編譯,程式也能執行,只是結果不對,所以特別難發現:

錯誤 寫成 實際發生的事
= 與 == 混用 if (stock = 0) 把 0 指定給 stock,條件的值是 0,永遠不成立
if 後面多一個分號 if (temp > 30); 分號本身是一個「空敘述」,if 只管它;下面的大括號每次都會執行
迴圈變數沒有更新 while (count < 3) { ... } 裡忘了 count++ 條件永遠成立,變成無窮迴圈,程式不會結束

g++ 加上 -Wall 編譯時,會對「在條件裡使用指定運算」提出警告,建議你加括號表明是刻意的。養成用 -Wall 編譯的習慣,可以抓到很多這類錯誤。 程式陷入無窮迴圈時,在終端機按 Ctrl + C 可以強制結束。

看起來對、其實錯的程式

注意第 7 行執行之後,stock 從 5 變成 0,而且「缺貨」沒有印出來。第 13 行的條件不成立,第 15 行卻還是執行了。

想一想:迴圈與常見錯誤

1.

下面的程式會印出什麼?

int i = 10;
do {
    cout << i;
    i++;
} while (i < 5);
2.

下面的程式會印出什麼?

for (int i = 0; i < 10; i++) {
    if (i == 3) continue;
    if (i == 6) break;
    cout << i;
}
3.

下面的程式會印出什麼?

int x = 0;
if (x = 5) {
    cout << "yes" << x;
} else {
    cout << "no" << x;
}
第 1 次作答

動手寫:FizzBuzz

讀入一個正整數 n,從 1 數到 n,每個數字印一行:3 的倍數印 Fizz、5 的倍數印 Buzz、同時是 3 和 5 的倍數印 FizzBuzz,其他印數字本身。輸入是 15。(執行時輸入的 15 會先顯示在輸出裡,就像在終端機上打字一樣。)

你的輸出
預期輸出

重點回顧

  • if … else if … else 由上往下檢查,只執行第一個成立的那一段;條件 ? 值1 : 值2 適合短的二選一
  • switch 比對整數類的值與常數;每個 case 結尾記得 break,否則會 fall-through 到下一個 case
  • for 用在次數已知,while 先檢查再執行,do-while 至少執行一次
  • break 離開最內層迴圈,continue 跳過這一輪剩下的程式
  • 巢狀迴圈:外層每跑一輪,內層跑完一整輪
  • 小心 = 與 ==、if 後面的分號、忘了更新迴圈變數;用 g++ -Wall 編譯可以幫你抓到一部分錯誤
這一課完成了!
Next lesson:函式
你目前沒有登入,學習進度只存在這個瀏覽器。 Login 後,進度會跟著帳號,換電腦也看得到。