# CPP Lecture2 ![upload_0673f86c099c4a1a5741d9a110bedecf](https://hackmd.io/_uploads/rJaDXxjo1x.png) - __學習++型別轉換++、++條件判斷++ 、++迴圈和跳躍語句++__ - __`if`、`else if`、`else` 的先後順序?__ - __如何使用 `for`、`while`、`do-while`?__ - __什麼是跳脫字元? (Escape Characters)__ --- #### 📌 型別轉換(Type Casting) > C++ 允許將一種資料型態轉換為另一種,這種轉換稱為++型別轉換++。 <br/> 1. `括號型態轉換`(C-style Casting) 2. `標準型別轉換`(`static_cast<type>()`) 3. `隱式型別轉換`(Implicit Type Conversion) ⚡ 要釐清三種方式的區別、誤區以及應用。 --- #### 🔹 1. 括號型態轉換(C-style Casting) 因繼承了 C 語言的型別轉換語法, 稱為 ++C-style Casting++,寫法如下: - `目標型別 變數 = (目標型別) 被轉換的變數;` - 範例: ```cpp[] double pi = 3.14159; int int_pi = (int)pi; // pi 轉換為 int,變成 3 int int_pi = int(pi); // 一樣結果,C++ 風格 ``` --- ### `括號型態轉換` Pros and Cons 1. **++精簡++**: 句構簡潔、簡短:`(type)variable` 。 2. **++不安全++**:沒有類型檢查,可能造成未定義行為錯誤(Undefined Behavior Error)。 3. **++可讀性差++**:難以判斷是什麼類型的轉換,例如`指標類型`轉換可能會導致錯誤。 4. **++可能隱藏錯誤++**:如果程式碼變得複雜,這種轉換方式可能會導致難以排查的錯誤,因為`括號`用途廣泛:函式的傳入變數、運算的先後、邏輯劃分 等都需要用到括號。 --- #### 🔹 2. 標準型別轉換(`static_cast<type>()`) <br/> 以 `static_cast<>` 來進行「++編譯時類型檢查++」 的轉換。語法如下: - `目標型別 變數 = static_cast<目標型別>(被轉換的變數);` - 範例: ```cpp[] double pi = 3.14159; int int_pi = static_cast<int>(pi); // 結果與括號型態轉換相同,變成 3 ``` 這與 `(int)pi` 看似相同,但 `static_cast<>` 比++括號型態轉換++更安全且更具可讀性。 --- ### `標準型別轉換` Pros and Cons 1. **++編譯時檢查++**: - 只能用於「++明確允許的轉換++」,如數值型別之間的轉換、指標類型的轉換等。 - 不能轉換不同類型的指標(如 `int*` 轉 `double*`),避免潛在的錯誤。 2. **++程式可讀性高++**:明確表示轉換的型別。 3. **++避免謬誤++**:如果轉換不合法,編譯器會報錯,而括號型態轉換可能直接編譯通過但執行時出錯。 --- #### 🔹 3. 隱式型別轉換(Implicit Type Conversion) <br/> 當 C++ 自動進行型別轉換時, 稱為「++隱式型別轉換++」。通常發生在: - **較低精度型別** → 較高精度型別 - **數值運算** → 類型不匹配校正 - 範例: ```cpp[] int a = 10; double b = a; // 10.0, 整數轉浮點數 ``` ++_**`精度提升不會造成資料遺失,C++ 會自動進行轉換`**_++ --- ### ⚠️ 常見的問題 <br/> - ❌ 精度損失: ```cpp[] double x = 3.14; int y = x; // 小數部分 0.14 被捨去 ``` - ❌ 數學運算出錯: ```cpp[] int a = 5; int b = 2; double result = a / b; // 結果為 2,因為 a/b 仍是整數 ``` ✅ ++修正方式++ ```cpp[] double result = static_cast<double>(a) / b; // 結果為 2.5 ``` --- ### 📊 型態轉換比較 | 轉換方式 | 是否安全 | 是否有類型檢查 | 可讀性 | 適用場景 | |-|-|-|-|-| | `括號型態轉換` | ✖ | ✖ | 低 | 低級語法,不建議使用 | | `標準型別轉換` | ✓ | ✓ | 高 | 主要用於數值型別轉換 | | `隱式型別轉換` | ✓ | ✓ (自動)| - | 變數宣告時自動發生 | --- ### ➣ 例題1:推斷輸出 Q. 下面代碼的輸出是? ```cpp[] int a = 7, b = 2, c = 0; cout << a / b << " "; // ? cout << (double)(a / b) << " "; // ?? cout << a / static_cast<double>(b) << " "; // ??? cout << static_cast<double>(c) << " "; // !?? cout << (double)a / c << endl; // !!?? ``` :::spoiler ▼ 解答 ++3++ ++3++ ++3.5++ ++0++ ++inf++ 原因❓❓ ::: --- ### ➣ 例題2:錯誤的型別轉換 Q. 以下哪一行會造成未定義行為? ```cpp[] int* p = nullptr; double* q = (double*)p; // A double* r = static_cast<double*>(p); // B ``` :::spoiler ▼ 解答 (答案:`B`) - 會直接編譯錯誤 - `static_cast<>` 不能轉換++不相關的指標類型++。 ::: (沒學到指標可以先跳過) --- #### 📌 流程控制/條件判斷(`if` / `else if` / `else`) <br/> 流程控制陳述式可以控制條件式分支以 執行不同區塊的程式。只有在 `condition` 判斷 為非零值 (或 **true**) 時,才會執行 ++if-branch++ 中 其中一個條件下的陳述式。共有以下三種型式: 1. `if` 條件語句 (Pure Judgment) 2. `if-else`條件判斷(Conditional Judgment) 3. `else if`多重條件(Multi-Cond. Judgement) --- #### 🔹 1. `if` 條件語句 > __僅使用 if 語句 做單一的判斷__ - 語法: ```cpp[] if (條件) {     /* 只有條件為 true 時才會執行 */ } ``` - 範例: ```cpp[] int x = 10; if (x < 11) { cout << "x < 11 is true!\n"; // executed } ``` ```cpp[] int x = 0, y = 1; if (x) { cout << "Is this going to execute?\n"; // NO } if (y) { cout << "Or is this going to execute??\n"; // YES } ``` --- ### 小練習 <br/> 請判斷以下分別輸出什麼❓ ```cpp[] #include <iostream> #include <cstdlib> using namespace std; int main() { // (1) if (false) cout << true << endl; // ? // (2) if (true) cout << false << endl; // ?? // (3) if (!false) cout << true << endl; // ??? // (4) if (!true) cout << false << endl; // ???? // (5) if (true || false) cout << "What's going on !?" << endl; // ????? // (6) if (!(false && true) && !false) cout << "Come on, Last one!" << endl; // ?????? return 0; } ``` :::spoiler ▼ 解答 1: `N`, 2: `Y`, 3: `Y`, 4: `N`, 5: `Y`, 6: `Y` ::: --- #### 🔹 2. `if-else` 條件語句 > __if 搭配 else 語句 陳述式分別為++條件符合而執行++ & ++條件不符合而執行++__ - 語法: ```cpp[] if (條件) {     /* 條件為 true,就只執行此區段的程式碼 */ } else {     /* 條件為 false,才執行此區段的程式碼 */ } ``` - 範例: ```cpp[] int x = 12; if (x < 11) { cout << "x < 11 is true!\n"; // not executed! } else { cout << "x < 11 is false!\n"; // executed } if (x >= 11) cout << "Is this going to execute?\n"; // Yes else cout << "Or is this going to execute??\n"; // No ``` --- ### 小練習 <br/> 請判斷以下分別輸出哪一行❓ ```cpp[] #include <iostream> #include <cstdlib> using namespace std; int main() { int a = 1, b = 10; // (1) if (a == b) { cout << "a is equal to b\n"; } else { cout << "a is NOT equal to b\n"; } // (2) if (a != b) { if (b < 10) { cout << "(A)" << endl; } else { cout << "(B)" << endl; } } else { cout << "(C)" << endl; } // (3) if (a <= 10) { if (b <= 1) { cout << "(A)" << endl; } else { if (a % 2 == 1) cout << "(B)" << endl; } } else { if (b == 10) cout << "(C)" << endl; else cout << "(D)" << endl; } return 0; } ``` :::spoiler ▼ 解答 1: `a is NOT equal to b`, 2: `(B)`, 3: `(B)` ::: --- #### 🔹 3. `else if` 分支條件語句 > __else if 語句 作為 if 的條件沒通過時的替代方案 跟 if 一樣需要自己的條件語句__ - 語法: ```cpp[] if (條件1) {     /* 條件1 為 true,則僅執行此區塊 */ } else if (條件2) {     /* 條件1 為 false,且條件2 為 true 時,僅執行此區塊 */ } else {     /* 以上條件都不符合,一律只執行此區塊 */ } ``` - 範例: ```cpp[] if (11 < 10) { cout << "11 is smaller than 10" << endl; } else if (11 > 10) { cout << "11 is bigger than 10" << endl; } else cout << "11 is equal to 10" << endl; ``` --- ### 小練習 <br/> 請判斷以下分別輸出哪一行❓ ```cpp[] #include <iostream> #include <cstdlib> using namespace std; int main() { int x = 1, y = 2, z =3; if (x > y) { cout << "(A)" << endl; } else if (x < z) { if (x * y >= z) { cout << "(B)" << endl; } else if (z / x <= y) { cout << "(C)" << endl; } else if (z / y >= x) { cout << "(D)" << endl; } } else if (y > z) { if (x * y / z > y) cout << "(E)" << endl; } else { if (false) { cout << "(F)" << endl; } else if (true) { cout << "(G)" << endl; } } return 0; } ``` :::spoiler ▼ 解答 `(D)` ::: --- ### ✎ `流程控制` - 實作題1 <br/> Q. 請寫一個程式判斷**輸入整數**是++奇數還是偶數++ :::spoiler ▼ 詳解v1 ```cpp[] #include <iostream> using namespace std; int main() { int x; cin >> x; if (x % 2 == 0) cout << "輸入為偶數" << endl; if (x % 2 != 0) cout << "輸入為奇數" << endl; return 0; } ``` ::: :::spoiler ▼ 詳解v2 ```cpp[] #include <iostream> using namespace std; int main() { int x; cin >> x; if (x % 2 == 0) cout << "輸入為偶數" << endl; else cout << "輸入為奇數" << endl; return 0; } ``` ::: --- ### ✎ `流程控制` - 實作題2 <br/> Q. 請寫一個程式判斷**輸入整數**是 ++個位數++/++十位數++/++百位數++/++百位數以上++ :::spoiler ▼ 詳解v1 ```cpp[] #include <iostream> using namespace std; int main() { int x; cin >> x; if (x < 10) cout << "輸入為個位數" << endl; else if (x < 100) cout << "輸入為十位數" << endl; else if (x < 1000) cout << "輸入為百位數" << endl; else if (x >= 1000) cout << "輸入為百位數以上" << endl; return 0; } ``` ::: :::spoiler ▼ 詳解v2 ```cpp[] #include <iostream> using namespace std; int main() { int x; cin >> x; if (x < 10) cout << "輸入為個位數" << endl; else if (x < 100) cout << "輸入為十位數" << endl; else if (x < 1000) cout << "輸入為百位數" << endl; else cout << "輸入為百位數以上" << endl; return 0; } ``` ::: --- ### ✎ `流程控制` - 實作題3 <br/> Q. 請寫一個程式判斷**輸入整數**是 ++百位數以下++/++百位數以上++ 的 ++奇數++/++偶數++ :::spoiler ▼ 詳解 (_可以有很多種寫法達成要求_) ```cpp[] #include <iostream> using namespace std; int main() { int x; cin >> x; if (x < 100) { cout << "輸入整數為百位數以下的"; cout << (x % 2 ? "基數" : "偶數") << endl; } else { cout << "輸入整數為百位數以上的"; cout << (x % 2 ? "基數" : "偶數") << endl; } return 0; } ``` ::: --- #### 📌 迴圈(Loop) <br/> ++__迴圈__++ 是最基礎的自動化,在給定的條件下 自動執行範圍下的陳述式,一旦條件為 `false` 就跳出自動執行的程序,以下三種常見迴圈: 1. `for` Loop: 已知執行次數時使用 2. `while` Loop: 當條件為 true 時執行 3. `do-while` Loop: ++至少執行一次++,再根據條件判斷是否繼續 --- #### 🔹 1. `for` 迴圈 > 包含三個要素: ++初始化++(可有可無)、++持續條件++(不建議無)、++更新++(可有可無) - 語法: ```cpp[] for (初始化 ; 持續條件 ; 更新) {     /* 迴圈內的程式碼 (陳述式) */ } ``` - 範例: ```cpp[] for (int i = 0 ; i <= 100 ; i += 2) {     cout << i << " "; } cout << endl; ``` --- ### 小練習 > `無窮迴圈`: 是我們最不希望在正常程式中出現的,它會導致電腦不斷重複迴圈中的陳述式,並且沒有遠遠不會達到終止條件(需要外部來關閉程式) <br/> 請判斷以下是否會出現無窮迴圈❓ ```cpp[] #include <iostream> using namespace std; int main() { int i = 100; for (int j = 10; i > -1; j = j - 2) { i -= j; cout << i << " " << j << endl; } return 0; } ``` :::spoiler ▼ 解答 _++會出現無窮迴圈++_ ::: --- #### 🔹 2. `while` 迴圈 > 一個很簡單的迴圈 只有一個維持條件,但要注意不要造成`無窮迴圈` - 語法: ```cpp[] while (條件) { // (維持條件)     /* 迴圈內的程式碼 (陳述式) */ } ``` - 範例: ```cpp[] int i = 0; while (i < 5) {     cout << "i = " << i << endl;     i++; } // 無窮迴圈 while (true) { cout << "Infinite Loop !!!" << endl; } ``` --- ### 小練習 <br/> ⚠️ 請判斷如何避免==錯誤==的出現❓ ```cpp[] #include <iostream> using namespace std; int main() { int a, b, temp; a = 64; b = 28; while(a != 0){ // Euclidean Algo temp = b; b = a % b; a = temp; } cout << a << '\n'; return 0; } ``` :::spoiler ▼ 解答 _`while(b != 0)`_ ::: --- #### 🔹 3. `do-while` 迴圈 > 基本上跟 while loop 相同,差在必定++最少執行一次++ - 語法: ```cppp[] do {     /* 迴圈內的程式碼 (陳述式) */ } while (條件); // (維持條件) ``` - 範例: ```cpp[] int i = 0; do {     cout << "i = " << i << endl;     i += 1; } while (i < 5); ``` --- ### 小練習 <br/> Q. 說明 `for`/`while`/`do-while` 主要區別在哪裡? :::spoiler ▼ 詳解 - `for`:適合已知次數的迴圈如固定重複 10 次 - `while`:適合不確定次數但滿足條件才繼續執行 - `do-while`:與 while 類似,但至少執行一次 ::: --- ### 小試身手 🖊️ - 請利用任一種迴圈方法來輸出以下結果: ``` * *** ***** ******* (菱形寬度為 7) ***** *** * ``` - 並且使用者可以輸入奇數++菱形寬度++ $n$: - 模板: ```cpp[] #include <iostream> using namespace std; int main() { int n; cin >> n; // 你的程式碼 return 0; } ``` --- ### ⚿ 關於`迴圈`... ![image](https://hackmd.io/_uploads/HJlB7xohJx.png) =>> 有沒有想過?? 程式有沒有辦法來判斷或是處理: 1. 已經進入了++無窮迴圈++ _或是_ 2. 迴圈中的某些情況++需要跳過++ ==以下介紹 ...== --- ### 🕺 跳躍語句 (`break`/`continue`) 當在需要迴圈中: - 強制中止 loop 時: 使用 ++`break`++ 保留字,直接跳出迴圈的執行。 - 跳過當前 loop 中,此次 iteration(迭代)時: 使用 ++`continue`++ 保留字,直接略過此次迭代。 <br/> 不懂?? 看範例 >> --- ### 🔹`break` <br/> - 用法:`break;` (就是一個很簡單的 callout) - 範例: ```cpp[] int iterationCount = 0; while (true) { // 這執行條件會造成無窮迴圈 iterationCount++; if (iterationCount >= 100) { break; // 這邊計算迴圈總數量,當到達 100 時 `break` } } cout << "while 迴圈外..." << endl; ``` > `for`、`do-while` 同樣可以使用 `break` 語句 --- ### 🔹`continue` <br/> - 用法:`continue;` (一樣是一個 callout) - 範例: ```cpp[] for (int i = 0; i < 1000; ++i) { if (i % 3 == 0) { // 只要整除三的 i 皆會直接跳過 continue; } cout << "這裡的 i = " << i << " 不會是三的倍數" << endl; } ``` > `while`、`do-while` 同樣可以使用 `continue` 語句 --- ### ✎ 綜合練習1 - 質數判斷器 <br/> 請實作一個程式用來讀取++整數輸入++, 輸入數量未知,一旦讀取到輸入小於等於1時停止, 針對每個輸入需要判斷是否是`質數` > __可能會用到 `cin`、`while`、`for` 等 前面出現過的語法__ --- ### ✎ 綜合練習1 - 詳解 :::spoiler ▼ 程式碼 ```cpp[] #include <iostream> using namespace std; int main() { int x; while (1) { // 未知輸入數量 所以跳脫語句寫在陳述式裡 cin >> x; if (x <= 1) break; // 輸入小於 2 時退出迴圈 int factorCount = 0; // 計算有幾個非 1 及非自己本身 個因數 for (int i = 2; i < x; ++i) if (x % i == 0) factorCount++; // 判斷因數數量 if (!factorCount) cout << x << " is prime number!!" << endl; else cout << x << " is not prime number." << endl; } return 0; } ``` ::: --- ### ✎ 綜合練習2 - 挑剔加總 <br/> 請實作一個程式用來處理以下任務, 第一行會輸入++一個正整數++來指定接下來一行 會有多少個整數輸入 (以空格隔開): 例如: ``` 5 2 3 -11 4 3 ``` 一旦讀取到++負數++時就直接跳過 剩餘的繼續做加總,最後請輸出最終加總的答案。 > 考慮用上 `continue` --- ### ✎ 綜合練習2 - 詳解 :::spoiler ▼ 程式碼 ```cpp[] #include <iostream> using namespace std; int main() { int count, number, sum = 0; cin >> count; for (; count > 0; --count) { cin >> number; if (number < 0) continue; sum += number; } cout << "挑剔總和為: " << sum << endl; return 0; } ``` ::: --- ### 流程控制補充 (`switch-case`) > 現在我們學到 `break` 的用法 這在 `case` 的中止跳躍會需要 這是++速度最快++、++效率最高++的流程控制,但功能有限 - 語法: ```cpp[] switch (變數) { case 值1: // 當變數 == 值1 時只執行此 case 底下陳述式 break; case 值2: // 當變數 == 值2 時執行此 case 底下陳述式 break; ... // 可以有無限多個 case default: // 其他完全沒列出(符合)的情況下才執行 } ``` 一個 `case` 的區塊是 `冒號:` 到 `break;` 之間的程式碼 --- ### `switch-case` 範例 ```cpp[] #include <iostream> using namespace std; int main() { int day; cout << "請輸入星期幾 (1-7): "; cin >> day; switch (day) { case 1: cout << "星期一\n"; break; case 2: cout << "星期二\n"; break; case 3: cout << "星期三\n"; break; case 4: cout << "星期四\n"; break; case 5: cout << "星期五\n"; break; case 6: cout << "星期六\n"; break; case 7: cout << "星期日\n"; break; default: cout << "輸入錯誤,請輸入 1-7!\n"; } return 0; } ``` 直接定義了一周七天分別的對應 `case` 輸入如果不在範圍內,就會跑到 `default` --- ### `switch-case` 的謬誤 ```cpp[] #include <iostream> using namespace std; int main() { char fruit = 'b'; switch (fruit) { case 'a': cout << "apple 蘋果\n"; case 'b': cout << "banana 香蕉\n"; case 'c': cout << "cherry 櫻桃\n"; case 'd': cout << "durian 榴槤\n"; break; case 'e': cout << "eggplant 茄子\n"; break; default: cout << "沒有找到水果\n"; } return 0; } ``` - Output: ``` banana 香蕉 cherry 櫻桃 durian 榴槤 ``` > 使用時要非常注意 ==break== 有沒有寫進去 --- #### 📌 跳脫字元 (Escape Character) ##### (這個跟跳躍語句`沒有關係`) 最常見的例子就是 `'\n'` 我們都知道這個字元代表換行 但為何是這樣?? ANS: 在 C++ 中需要表示某些無法直接輸入的特殊字元(如`換行 \n`、`tab` `\t`),或有特定意義的符號 (如 `雙引號 \"`、`單引號 \'`),就要用跳脫字元。 <br/> 這些字元由 反斜線 `\` 開頭,告訴編譯器它們有特殊意義,不是普通的文字輸出。 --- ### 🔹 為什麼需要跳脫字元? <br/> 舉例來說: 當我們要輸出 He said: "Hello!",如果直接寫: ```cpp[] cout << "He said: "Hello!""; // ❌ 錯誤! ``` 這段程式會產生語法錯誤,因為 C++ 會把 "Hello!" 認為是另一個字串,導致括號錯誤。 正確寫法: ```cpp[] cout << "He said: \"Hello!\""; // ✔️ 正確 ``` --- ### 🔹 使用跳脫字元的注意事項 (`\`) <br/> `\\` 反斜線:為什麼 `\` 不能直接使用? 如果我們寫: ```cpp[] cout << "C:\Program Files\System32"; // ❌ 錯誤! ``` 會產生錯誤,因為 `"\P"`、`"\S"` 會被當作未知的跳脫字元! <br/> 解決方法:使用 `\\` ```cpp[] cout << "C:\\Program Files\\System32"; // ✔️ 正確 ``` --- ### 🔹 常見++跳脫字元++列表 ➤➤➤ ![3-graph-colors-change-my-mind](https://hackmd.io/_uploads/r1vVMzsn1x.jpg) --- | 跳脫字元 | 說明 | 範例 | |-|-|-| | `\n` | 換行 | `"a\nb"` → a換行b | | `\t` | Tab 鍵 | `"A\tB"` → A B | | `\"` | 雙引號 | `"\"Hi!\""` → "Hi!" | | `\'` | 單引號 | `"It\'s"` → It's | | `\\` | 反斜線 \ | `"C:\\D\\"` → C:\D\ | | `\0` | Null 結尾字元 | 字串結尾 | | `\r` | ==回車==(Carriage Return) | Win 換行 (`\r\n`) | | `\b` | Backspace ==(退格)== | "ABC\bD" → ABD (刪除 C) | --- ### 小練習 - 請寫出程式,讓輸出結果為: ``` C:\Users\Alice\Documents "It's a wonderful day!" A B C ``` :::spoiler ▼ 解答 ```cpp[] cout << "C:\\Users\\Alice\\Documents\n"; cout << "\"It's a wonderful day!\"\n"; cout << "A\tB\tC\n"; ``` ::: --- ### 📝 習題練習 --- 提示 `#include <cmath>` > `sqrt(x) -> float` x 開根號 <br/> 1. [a059. 完全平方和](https://zerojudge.tw/ShowProblem?problemid=a059) 2. [a121. 質數又來囉](https://zerojudge.tw/ShowProblem?problemid=a121) --- #### 1. [a059. 完全平方和](https://zerojudge.tw/ShowProblem?problemid=a059) :::spoiler ▼ 解答 ```cpp[] #include <iostream> #include <cmath> // sqrt using namespace std; int main() { int pairNum; cin >> pairNum; for (int i = 0; i < pairNum; ++i) { int a, b, sum = 0; cin >> a >> b; for (int j = a; j <= b ; ++j) { int root = sqrt(j); // 取平方根的整數部分 if (root * root == j) sum += j; } cout << "Case " << (i + 1) << ": " << sum << endl; } return 0; } ``` ::: --- #### 2. [a121. 質數又來囉](https://zerojudge.tw/ShowProblem?problemid=a121) :::spoiler ▼ 解答 ```cpp[] #include <iostream> #include <cmath> // sqrt using namespace std; int main() { int a, b; while (cin >> a >> b) { int count = 0; for (int i = a; i <= b; ++i) { if (i == 1) continue; else if (i == 2) { count++; continue; } int hasFactor = 0; for (int j = 2; j < sqrt(i) + 1; ++j) if (i % j == 0) { hasFactor = 1; break; } if (!hasFactor) count++; } cout << count << endl; } return 0; } ``` :::
{"title":"CPP Lecture2","description":"CPP Lecture2.","image":"https://hackmd.io/_uploads/BJ6Q7ub3kg.png","contributors":"[{\"id\":\"08ecf684-cada-47c1-ad99-984ab62fb65e\",\"add\":18892,\"del\":1475}]"}
    153 views