C++[0] = ## Intro ### 程式語言是什麼 > 程式語言(英語:programming language)是用來表達電腦程式的電腦語言。它是一套標準化的交流技巧,一種能夠讓程式設計師準確地定義電腦所需資料的語言,以向電腦發出指令並精確地定義不同情況下應當採取的行動。 --[維基百科](https://zh.wikipedia.org/zh-tw/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80) - 程式語言就是人類用來命令電腦做事情所用的語言 - 機器語言: - 以二進位直接對電腦下指令 - 組合語言: - 二進位好難寫->以文字代替二進位來表達指令 - 對應到機器語言 - 無法在不同處理器共通 - 高階語言: - 讓同一個程式在不同處理器運行 - 易讀性up - 翻譯成機器語言時可以 - 編譯(Compille):**執行前**透過編譯器一次翻譯所有程式碼,ex. C、C++、Java... - 直譯(Interpret):**執行時**一邊翻譯一邊執行,ex. Python、JavaScript、PHP... ![CompilerVSInterpreter_HowTheyWork](https://hackmd.io/_uploads/SkYeSWpFWg.png) ![CompilerVSInterpreter_Compare](https://hackmd.io/_uploads/BJbWSW6KWx.png) ### C++ 是什麼? #### C v.s. C++ - C - 1970 年左右 D. Ritchie 和 K. Thompson 在貝爾實驗室開發出來的程式語言 - 由 B 語言演變而來,屬於編譯語言 - [ABC](https://www.zhihu.com/question/22826568/answer/65915408) - 具有高階語言的特性,也有接近組合語言的速度 - C++ - 也是在貝爾實驗室開發出來的 - 目的:打造一種具有物件導向的C語言 - C語言寫的程式大部份都可以在C++執行 - 物件導向程式設計(**O**bject-**O**riented **P**rogramming) > 物件導向程式設計(英語:Object-oriented programming,縮寫:OOP)是種具有物件概念的程式設計典範,同時也是一種程式開發的抽象方針。它可能包含資料、特性、程式碼與方法。物件則指的是類別(class)的實例。它將物件作為程式的基本單元,將程式和資料封裝其中,以提高軟體的重用性、靈活性和擴充性,物件裡的程式可以訪問及經常修改物件相關連的資料。在物件導向程式程式設計裡,電腦程式會被設計成彼此相關的物件。 --[維基百科](https://zh.wikipedia.org/zh-tw/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1) - 具有「物件(Objects)」概念的程式語言設計模式 - C++ 的用途 - 相對複雜的語言 - 能夠寫出具有底層硬體控制功能的程式 - 加入了物件導向等許多現今語言的特性 - 處理更加貼近使用者的程式 - ex. Windows、iOS、Chrome、Firefox、英雄聯盟 ### What is an Algorithm? " 由有限步驟所構成的集合,可以用於解決某一個特定的問題。 " - 把西瓜做成一杯西瓜汁? 1. 把西瓜剖半 2. 挖出剛剛剖半的西瓜中的果肉並去籽 3. 將經過 2. 處理的西瓜果肉放入果汁機 4. 按下果汁機的啟動按鈕 5. 將果汁機裡榨好的西瓜汁倒入一個杯子 - 電腦科學中,演算法就是為了解決特定問題而設計的一組明確、有限的運算規則或步驟。 ### What are Online Judges? #### 線上解題系統 - 題目測試:提供各種演算法相關的題目,讓使用者撰寫程式解答 - 自動評測:使用測試數據來檢查程式的正確性與效能,並給予回饋 - 即時反饋:提交程式後,OJ 會迅速回報結果,如「通過」、「錯誤」、「超時」等 #### Online Judges - ZeroJudge:台灣的 OJ,電腦老師很喜歡 - TIOJ:建中資訊社維護 - ISCOJ:建北電資 OJ - CSES:有很多演算法題目可以練習 - Codeforces:全球最大的 OJ,常常有比賽 - Atcoder:第二大 OJ,在日本 - NEOJ:台大資芽的 OJ - LeetCode:收集軟體工程師面試考古題的 OJ #### OJ Results | Result | Meaning | | --- | --- | | AC (Accepted) | 答案正確,通過所有測資 | | WA (Wrong Answer) | 輸出結果與標準答案不符 | | TLE (Time Limit Exceeded) | 程式執行時間超過限制 | | MLE (Memory Limit Exceeded) | 程式使用的記憶體超過限制。 | | RE (Runtime Error) | 程式執行時發生錯誤 | | CE (Compilation Error) | 程式語法錯誤,無法編譯 | ## Setup | EDITOR 文字編輯器 | IDE 整合式開發環境 | | --- | --- | | 高度自定義 | 功能完整 | | 啟動速度快 | 吃效能,速度慢 | | 需自行安裝編譯器 | 內附編譯器 | | ==VSCode== | ==Code::Blocks== | ### 編譯器 - 編譯器(Compiler)會將某種程式語言寫成的原始碼轉換成電腦能解讀的語言 - IDE 不需安裝編譯器 - 文字編輯器安裝的方法:[VSCode 的 C++ 安裝教學](https://hackmd.io/@liaojason2/vscodecppwindows) ### 程式開發軟體們 - [Dev-C++](https://alwaysfreesir.blogspot.com/2017/05/devcpp-install.html):免費且非常好使用,不過它是一個比較古老的IDE,連編譯器也是好幾年前的(不過前陣子好像有別的公司接手) - [Code::Blocks](https://ithelp.ithome.com.tw/articles/10273955):真的很醜,但學校們很喜歡 - [onlinegdb](https://www.onlinegdb.com/):除了他是線上這點很方便外完全沒道理用 - [等等](https://www.hostinger.com/tutorials/best-code-editors) ## Hello World! ```cpp #include <iostream> using namespace std; int main() { cout << "Hello World!\n"; return 0; } ``` ### 第 1 行:導入 \<iostream\> 這個標準函式庫 > #include \<iostream\> - \#include 可將函式庫導入程式 - \<iostream\> 是函式庫名稱:專門處理程式的輸入輸出 ### 第 2 行:使用標準函式庫 > using namespace std; - std:C++ 標準函式庫的代號 (**st**an**d**ard library) - 告訴電腦,我們想在程式中使用 C++ 標準函式庫 - 不加的話就要在用到的時候在前面加`std::` ex. `std::cout`、`std::endl` ### 第 3 行:空行 - 會被電腦自動跳過 - 目的是為了讓程式碼可讀性更高 - 不用不會怎麼樣只是可能會被覺得很醜 ### 第 4 & 7 行:主函式 - main 函式是 C++ 定義一個程式的起點 - 大括號 {} 內就是 main 函式的內容 - 電腦執行的程式就要寫在這個大括號內 ### 第 5 行:Hello World! - `cout`:輸出 - `<<`:把右邊的資料傳給 cout - ``\n``:跳脫字元,換行 - `<< endl`:也可以換行 - ==一行程式結束後記得要加 `;`== ### 第 6 行:回傳 - 告訴電腦這個函式成功執行了 - 可有可無,因為編譯器會自動在結尾補上 `return 0;` - `return 0`:正常退出 - `return 1`:異常退出 ### 函式庫 - 函式庫中會有預先定義好的函式、類別和工具,可直接使用 - `iostream`:輸入輸出 - `algorithm`:常用演算法 - `cmath`:數學函式庫 - 萬用標頭檔:`bits/stdc++.h` - 包含絕大部分會用到的函式庫 - 引入一大包東西雖然你可能只有用到一點點 - macOS 要用有點蠻煩 顯然我怕麻煩 - 等等我還是會講他們分別屬於什麼函式庫 ### 命名空間 - 命名空間(namespace)是 C++ 提供的一種機制,用來避免名稱衝突 ```cpp #include <iostream> #include <string> using namespace std; string name = "C++"; string name = "Python"; int main() { cout << name; } ``` - 兩個 name 沒有區分開來,導致編譯錯誤 ``` cpp #include <iostream> #include <string> using namespace std; namespace A { string name = "C++"; } namespace B { string name = "Python"; } int main() { cout << A::name << '\n'; //C++ cout << B::name; //Python } ``` - 使用命名空間即可避免錯誤 - 但其實在寫程式時應該避免重複命名 #### namespace std - C++ 標準函式庫的所有函式、類別(如 cout, cin, vector, string 等)都定義在 std 命名空間內 ```cpp #include <iostream> int main() { std::cout << "Hello World!" << std::endl; } ``` - 未使用 using namespace std;需要在 cout, endl 前加上 std:: - ==using namespace std; 會導致 std 內的所有函式和類別變成全域可用,可能會與其他函式名稱衝突,因此在大型專案中建議避免使用== ### 換行 | `\n` 跳脫字元 | `endl` 輸出流 | | --- | --- | | 換行 | 換行並刷新緩衝區 | | 速度快 | 速度慢 | | 競程用 | 專案用 | | 推薦 | 不推薦 | ## Variables and Data Types ### 變數 - 數值會改動的數 - 程式用來存放資料的空間 - 占有電腦的記憶體 - 執行的過程中可以對變數進行處理和運算 #### 宣告 - 宣告格式:`資料型態 變數名稱;` ```cpp #include <iostream> using namespace std; int main() { int a; } ``` - 宣告一個命名為 a 的整數(int)變數,其資料型態為 int #### 資料型態 | 名稱 | 型態(type)| 範圍(range)| 記憶體大小 | | --- | --- | --- | --- | | `int` | 整數 | -2^31^ ~ 2^31^-1 | 4 bytes | | `unsigned int` | 正整數 | 0 ~ 2^32^-1 | 4 bytes | | `long long` | 整數 | -2^63^ ~ 2^63^-1 | 8 bytes | | `unsigned long long` | 正整數 | 0 ~ 2^64^-1 | 8 bytes | | `bool` | 布林值 | 真假值(True/False)| 1 byte | | `char` | 字元 | 一個字元 | 1 byte | | `string` | 字串 | 多個字元 | 可變 | | `float` | 浮點數 | 十進位精度約 6~7 位 | 4 bytes | | `double` | 浮點數 | 十進位精度約 15~16 位 | 8 bytes | #### 賦值 - 賦予變數一個值 - 賦值格式:`資料型態 變數名稱 = 值;` ```cpp #include <iostream> #include <string> using namespace std; int main() { //宣告一個整數變數 a //將 a 的值設為 1 int a = 1; //宣告一個字元變數 c //將 c 的值設為 'a'(單引號) char c = 'a'; //宣告一個字串變數 s //將 s 的值設為 "str"(雙引號) string s = "str"; } ``` #### 變數命名 - 需與變數內容相關 - 只能用大小寫字母、數字、_、$ - 數字**不可**作為變數名開頭 - 大小寫意義不同(為不同變數) - 不可使用==保留字== #### 保留字 - 給編譯器做特殊判斷用 ![reserved_word](https://hackmd.io/_uploads/B1C8rDCt-l.png) ## Input & Output - C++的輸入和輸出是使用`cin`和`cout`來進行 - 使用它們的時候需要引入`<iostream>`函式庫 ### 輸入 - `cin >> 變數(已宣告過的);` - 讀到空白或換行會結束讀取 - 輸入多個值:`cin >> 變數 >> 變數;` ### 輸出 - `cout << 要輸出的物件;` - 可輸出變數或是輸出一個值 - 輸出多個值:`cout << 變數 << 變數;` ```cpp #include <iostream> using namespace std; int main() { string s; cin >> s; // Hello World cout << s; // Hello string a, b; cin >> a >> b; // Hello World cout << a << '\n'; // Hello cout << b << '\n'; // World } ``` ### getline - 讀取整行 - `getline(cin, 變數)` ```cpp #include <iostream> using namespace std; int main() { string s; getline(cin, s); cout << s; } ``` ## Operators - 運算子 - 對變數或數值做運算 ### 指定運算子`=` - 先對`=`右邊進行運算 - 將運算結果存入左邊 - 左邊要可以存值 ex. 變數 ```cpp #include <iostream> using namespace std; int main() { int x; x = 2 + 1; cout << x << '\n'; // 3 x = x + 1; cout << x << '\n'; // 4,先計算右邊再存入左邊 } ``` ### 算術運算子 - 數學的運算符號 - 先乘除後加減 - 括號優先 ```cpp #include <iostream> using namespace std; int main() { int a = 5, b = 3, c = 2; // 逗號左右可以分別賦值 cout << a + b << '\n'; // 8,加 cout << a - b << '\n'; // 2,減 cout << a * b << '\n'; // 15,乘 cout << a / b << '\n'; // 1,除 cout << a % b << '\n'; // 2,模除(取餘數) cout << c + a * b << '\n'; // 17,先乘除後加減 cout << (c + a) * b << '\n'; // 21,括號內優先 } ``` - line 9:a 和 b 都是整數,對兩個整數做除法`/`時自動向下取整 ```cpp #include <iostream> using namespace std; int main() { int a = 1; a += 1; // a = a + 1 cout << a << '\n'; // 2 a -= 2; // a = a - 2 cout << a << '\n'; // 0 } ``` ### 遞增遞減 - 前置遞增遞減`++x`/`--x`:加減之後的值 - 後置遞增遞減`x++`/`x--`:加減之前的值 ```cpp #include <iostream> using namespace std; int main() { int a = 0; cout << ++a << '\n'; // 1,先加再用 cout << a++ << '\n'; // 1,先用 cout << a << '\n'; // 2,再加 cout << --a << '\n'; // 1,先減再用 cout << a-- << '\n'; // 1,先用 cout << a << '\n'; // 0,再減 } ``` ### 比較運算子 - 回傳 true(1) 或 false(0) 兩種結果 ```cpp #include <iostream> using namespace std; int main() { int a = 4, b = 7, c = 4; cout << (a == b) << '\n'; // 0 cout << (a == c) << '\n'; // 1 cout << (a != b) << '\n'; // 1 cout << (a > b) << '\n'; // 0 cout << (a > c) << '\n'; // 0 cout << (a >= b) << '\n'; // 0 cout << (a >= c) << '\n'; // 1 cout << (a < b) << '\n'; // 1 cout << (a <= b) << '\n'; // 1 } ``` ### 邏輯運算子 - 邏輯運算也只有 true(1) 或 false(0) 兩種結果 - 邏輯 AND `&&` - `A`、`B`皆為true時, `A && B` 為`true` - 否則 `A && B` 為 `false` | A && B | B = true | B = false | | ------------ | -------- | --------- | | **A = true** | true | false | | **A = false**| false | false | - 邏輯 OR `||` - `A`、`B`皆為`false`時, `A || B` 為`false` - 否則 `A || B` 為 `true` | A \|\| B | B = true | B = false| | ------------ | -------- | -------- | | **A = true** | true | true | | **A = false**| true | false | - 邏輯 NOT `!` - 當 `A` 為 `true` 時,`!A` 為 `false` - 否則 `A` 為 `false` 時,`!A` 為 `true` ### 型別轉換 - 把某個型別轉換成另一個型別 - 隱含型別轉換 - C++ 會自動做的轉換 - 選擇運算式中所有型別中儲存空間較大的型別 ```cpp #include <iostream> using namespace std; int main() { cout << 3 / 2 << endl; // 1 cout << 3 / 2.0 << endl; // 1.5 } ``` - 使用指定運算子`=`就會以指定運算子左邊的資料型別為準 ```cpp #include <iostream> using namespace std; int main() { int x; x = 3 / 2.0; cout << x << endl; // 1 } ``` - 強制型別轉換 - 程式運算過程中對型別做強制的轉換 - 轉換格式: ``` (轉換型別) 變數; (轉換型別) 數值; ``` ```cpp #include <iostream> using namespace std; int main() { int x = 3; cout << (double)x / 2 << endl; //輸出 1.5 cout << (char)97 << endl; //輸出「a」, 97是字元'a'在ASCII碼中的編號 } ``` ## Array & Vector ### 陣列 - 多個相同資料型別的變數所組成 - 每個元素都是一個變數 - ==陣列索引值(index)是從 0 開始(0-based)== | index | 0 | 1 | 2 | 3 | 4 | 5 | | --- | --- | --- | --- | --- | --- | --- | | value | 123 | 53 | 42 | 4 | 1920 | 4 | - 陣列宣告格式: - `資料型態 陣列名稱[陣列大小];` - `資料型態 陣列名稱[] = {初始值1, 初始值2...};` - 用中括號`[]`加上索引值`陣列名稱[索引值]`表示陣列的某個變數 ```cpp #include <iostream> using namespace std; int main() { int a[5]; // 可儲存 5 個整數變數 int b[] = {1, 3, 4}; // 陣列中有 1, 3, 4 三個整數,長度為 3 cout << b[0] << ' ' << b[2] << '\n'; // 1 4 cout << b[3] << '\n'; // 噴錯,陣列 b 長度只有 3 a[] = {1, 2, 3, 4, 5}; cout << a[0] << '\n'; // 1 a[0] = 9; cout << a[0] << '\n'; // 9 char c[10], d[2]; // 也可儲存其他資料型態 } ``` ### 二維陣列 - n x m 的陣列 - 陣列宣告格式: - `資料型態 陣列名稱[n][m];` - `資料型態 陣列名稱[][] = {{初始值1-1, 初始值1-2...},{初始值2-1, 初始值2-2...},...};` - a[n][m]: | index | 0 | 1 | 2 | ... | m-1 | | --- | --- | --- | --- | --- | --- | | 0 | a[0][0] | a[0][1] | a[0][2] | ... | a[0][m-1] | | 1 | a[1][0] | a[1][1] | a[1][2] | ... | a[1][m-1] | | 2 | a[2][0] | a[2][1] | a[2][2] | ... | a[2][m-1] | | ... | ... | ... | ... | ... | ... | | n-1 | a[n-1][0] | a[n-1][1] | a[n-1][2] | ... | a[n-1][m-1] | ### Vectors - #include <vector> - 動態陣列 - 跟陣列很像,但長度可改變 - 動態陣列宣告:`vector<資料型態> 動態陣列名稱` `vector<資料型態> 動態陣列名稱(陣列長度)` `vector<資料型態> 動態陣列名稱(陣列長度, 所有元素預設值)` - 二維動態陣列宣告:`vector<vector<資料型態>> 動態陣列名稱` `vector<vector<資料型態>> 動態陣列名稱(陣列高度m)` `vector<vector<資料型態>> 動態陣列名稱(陣列高度m, vector<資料型態>(陣列長度n))` `vector<vector<資料型態>> 動態陣列名稱(陣列高度m, vector<資料型態>(陣列長度n, 所有元素預設值))` ```cpp #include <iostream> #include <vector> using namespace std; int main() { vector<int> v, t, k; v.push_back(1); v.push_back(3); cout << v[0] << ' ' << v[1] << '\n'; // 1 3 cin >> v[0]; // 2 cin >> v[1]; // 4 cout << v[0] << ' ' << v[1] << '\n'; // 2 4 vector<int> a(5, 0); cout << a[0] << ' ' << a[3] << '\n'; // 0 0 a.pop_back(); cout << a.size() << '\n'; // 4 a.clear(); // 移除所有元素 a.empty(); // 1,回傳是否為空 t.resize(5); cin >> t[4] >> t[3]; // 1 3 cout << t[3] << ' ' << t[4] << '\n'; // 3 1 k.assign(5, 0); cout << k[0] << ' ' << k[2] << '\n'; // 0 0 } ``` ## Conditionals ## Loops ## Practices ## References - https://hackmd.io/@Scott-Chou/rkbl5dzCO - https://zh.wikipedia.org/zh-tw/%E7%BC%96%E7%A8%8B%E8%AF%AD%E8%A8%80 - https://vocus.cc/article/66232973fd89780001355768 - https://hackmd.io/@Co-E5uCjTiSXhCaEXduquA/ryepv8F7U9 - https://zh.wikipedia.org/zh-tw/%E9%9D%A2%E5%90%91%E5%AF%B9%E8%B1%A1%E7%A8%8B%E5%BA%8F%E8%AE%BE%E8%AE%A1 - https://medium.com/@p81122g/%E6%B7%BA%E8%AB%87%E7%89%A9%E4%BB%B6%E5%B0%8E%E5%90%91%E7%A8%8B%E5%BC%8F%E8%A8%AD%E8%A8%88-object-oriented-programming-81355c85484b - https://jason-chen-1992.weebly.com/home/-whats-algorithm - https://ithelp.ithome.com.tw/m/articles/10233392 - https://www.reddit.com/r/learnprogramming/comments/sga9ey/is_there_really_such_a_big_difference_between/?tl=zh-hant - https://alwaysfreesir.blogspot.com/2017/05/devcpp-install.html - https://ithelp.ithome.com.tw/articles/10273955 - https://hackmd.io/@liaojason2/vscodecppwindows - https://blog.csdn.net/m0_37187717/article/details/104631305 - https://hackmd.io/@LukeTseng/H1P1nSt7yl - https://medium.com/@leonardian14/c-vector-%E7%B0%A1%E5%96%AE%E8%AA%AA%E6%98%8E%E8%88%87%E7%94%A8%E6%B3%95-946c975bd526