先前我們的程式很單純,就是順順得執行下去。再來的幾篇文章要介紹的陳述能讓我們的程式多些變化,並解決更多問題。
if-else 條件判斷#
還記得1.1 的範例嗎??我們寫惹個程式,允許使用者輸入兩個整數,而我們輸出兩者相除之商與餘數。然而,如果今天有人很 87 輸入87 0
, 那麼會發生什麼事??
這邊我們稍微補充一下,平常我們 main()
函式都 return 0;
代表正常結束,但這次會回傳 136
, 確認的方法是在終端機輸入 echo $?
. 原因是當我們的程式發生例外而不處理時,會觸發若干 Signal, 像是執行到一半按下 ⌃Ctrl + C 會觸發 SIGINT (2) 使程式中斷、程式被 abort (比如 assert 沒過)會觸發 SIGABRT (6), 錯誤地存取記憶體會觸發 SIGSEGV (11), 而本例致命的算術運算錯誤觸發 SIGFPE (8). 這些都是日後我們常遇到的錯誤。發生例外回傳值就不為 0
, 而會是 128 + (n)
. 其它的 exit code 包括 126
權限不足、127
command not found, …
回過頭來我們的問題。在設計程式時,必須盡可能考慮一切狀況,畢竟使用者是沒有下限地 (? 因此,我們需要檢查除數不可為零。if
statement 派上用場惹。首先看看它的語法:
if (condition)
{
// ...
}
其中 condition
是個表達式,如果表達式非零,就會執行大括弧的內容,否則直接跳過。因此我們可以改進我們的除法計算器:
如果大括弧內只有一個 statement (1 semicolon) 可以偷懶省略。其實在 C/C++ 中,非零就是 true
, 因此也能寫成 if (b) cout << ...
, 就是省略 != 0
的部分。現在再執行一次,故意輸入 87 0
, 程式不再發生錯誤,但直接結束好像有點怪怪的怪怪的欸??所以我們可以應用 else
:
if (condition)
{
// ...
}
else
{
// ...
}
如果 condition
非零,就會執行 if
大括弧的內容,否則執行 else
大括弧的內容,最後繼續執行下去。我們再次改進我們的除法計算器:
這次再有 87 輸入 87 0
, 就會告訴他除數不可為零惹。當然我們的 condition
不見得只是一個關係運算式,還可以結合前一篇介紹的邏輯運算子等等。我們可以一樣在第十行前方點一下設置中斷點,這次不要急著按 F5 繼續執行,改按 F10 Step Over 逐步執行,看看下一行會跳至何處。
類題演練#
多重與巢狀 if-else#
你以為 if-else 就這樣??不不不。我們的 if-else 還可以跟 if-else 自己結合,當然也可以跟下篇介紹的迴圈結合。自己結合的方式有並排的也有巢狀的:
if (condition_0)
{
// ...
}
else if (condition_1)
{
// ...
}
else
{
// ..
}
if (condition_0)
{
if (condition_1)
{
// ...
}
else
{
// ...
}
}
else
{
if (condition_2)
{
// ...
}
else
{
// ...
}
}
這邊應該都還很好理解,就給各位自行體驗惹。做些例題可以確認自己是否真的了解惹。
範例解析#
- GreenJudge c032
- 大家應該多少有聽過學年學分制,本題輸入兩學期成績,要求計算所得學分數。簡單的想法是先計算兩學期平均是否大於六十,再判斷各自是否大於六十,但注意的整數的除法,所以我們可以移項。
- 另解甚至根本不用
if-else
, 歡迎細細品味
- 大家應該多少有聽過學年學分制,本題輸入兩學期成績,要求計算所得學分數。簡單的想法是先計算兩學期平均是否大於六十,再判斷各自是否大於六十,但注意的整數的除法,所以我們可以移項。
- GreenJudge c014
- 這題最單純的想法就是乖乖照題目的條件列式,注意
b
有可能小於a
- 這邊同樣提供不用
if-else
的另解
- 這題最單純的想法就是乖乖照題目的條件列式,注意
類題演練#
- GreenJudge a014
- GreenJudge a015
- GreenJudge a016
- GreenJudge a017
- GreenJudge a018
- GreenJudge a019
- GreenJudge a020
- TCIRC Judge c002
switch-case 分支結構#
switch-case 感覺比較少用,但還是介紹一下。舉例來說高三上開始一週補習四天,每次想晚餐吃什麼這個大哉問實在太痛苦惹,於是我們決定週二吃 SUKIYA、週三吃那個那個飯、週四吃癡麵、週日吃 Burger King. 現在寫個程式,輸入一個整數代表是週幾,其中 0
, 7
皆表示週日,輸出晚餐要吃什麼。
我們現在會 if-else, 當然可以寫出以下程式:
#include <iostream>
using namespace std;
int main()
{
int day;
cin >> day;
if (day == 2)
cout << "SUKIYA\n";
else if (day == 3)
cout << "那個那個飯\n";
else if (day == 4)
cout << "癡麵\n";
else if (day == 0 || day == 7)
cout << "Burger King\n";
else
cout << "No cram school today.\n";
return 0;
}
但這樣有點囉嗦,是吧。所以我們可以用 switch-case 改寫之:
程式碼的可讀性好惹一些,只是注意每個 case 結束後如果沒有 break;
預設會進入下個 case. 另外,C/C++ 的 switch-case 僅支援整數包含字元。乍看之下用 switch-case 程式碼似乎比較冗長,但理論上執行時,if-else 在最糟情況下會遍歷 \(n\) 個判斷,時間複雜度是 \(O(n)\) 線性的,但 switch-case 編譯時可能使用 jump table, lookup table; 達到 \(O(\log n)\) 對數的甚至 \(O(1)\) 常數的時間複雜度。當然大部分情況下差異微乎其微,只是 switch-case 還有許多妙用。
類題演練#
另外 gcc 有提供 case range 可以這樣用:
switch (n)
{
// ...
case 69 ... 87:
cout << "skr skr\n";
break;
// ...
}
跟 __int128_t
一樣,macOS 如果用蘋果的 clang 應該無法使用。
Comments