# 前言 本文章宗旨為帶領新手入門C++,我會從0開始帶你了解C++,並且學習一些基礎應用,在接下來的程式教學中,為了節省版面,部分程式只會書寫主程式內的代碼,如果有需要運行的話,可以把等等要介紹的基本架構複製後,改掉main函數中的內容,就可以運行了。 # 基本架構 這是在各類程式中最一開始你會見到的基礎型,我們來簡單的了解一下架構。 ```cpp=1 #include <bits/stdc++.h> // 引入了C++中幾乎所有的宣告,我們才有辦法在接下來的程式中使用一些指令。 using namespace std; // 使用標準函數庫 int main() { // main() 是 CPP 程式的起始函數 // 主程式碼書寫區域 return 0; // 回傳0表示程式執行完畢 } ``` # C++守則 在C++當中,有幾件你必須知道的事情: 1. 每寫完一行程式,就必須在那之後加上半形分號,才能繼續寫下一行,就跟我們寫作文需要逗號一樣,一個句子寫完就要有一個標點符號。 2. 基本上所有的大括號、小括號都是成雙成對存在。 3. 格式很重要!格式很重要!格式很重要! 4. 基本上在初學階段,你的所有程式都會寫在main裡面。 # Code::Blocks介紹 本次使用的軟體為Code::Blocks,不使用Visual Studio Code的原因是,在APCS的考試中不能使用。下載教學網路上都有,這邊不多做說明,如果啟動有看到下方這個,就選第三個就好了。 ![1_lY3aD1ofoyKd2Ryv6pzulQ](https://hackmd.io/_uploads/S1N4T6S3R.png) ## 如何開始一個新的專案 步驟一:點擊新增檔案(下圖中紅色圈圈) ![步驟1](https://hackmd.io/_uploads/Sywry0Bn0.png) 步驟二:新增一個新的空白檔案(下圖中紅色框框) ![步驟2](https://hackmd.io/_uploads/rJ3Bk0Hn0.png) 步驟三:點擊儲存檔案(下圖中紅色圈圈) ![步驟3](https://hackmd.io/_uploads/rJx8y0B2A.png) 步驟四:取好檔名後在後方加上.cpp(下圖中紅色框框) ![步驟4](https://hackmd.io/_uploads/H1zL1RHnC.png) 這樣就完成啦!可以開始寫程式了! ## 快捷鍵介紹 下方是幾個常用的快捷鍵空能,建議背起來,能大幅提升效率喔。 | 按鍵 | 功能 | | -------- | -------- | | Tab | 空4格 | | F9 | 執行 | | Ctrl+C | 複製 | | Ctrl+V | 貼上 | | Ctrl+Z | 上一步 | # 格式 格式是為了讓版面看起來更舒服,下方幾點為常見格式要求: 1. 每進入一個大括號就要空4格(按一下Tab)。 2. 通常在每個符號前後會空1格。 ```cpp=1 #include <bits/stdc++.h> using namespace std; int main() { int a; cin >> a; if (條件) { if (條件) { if (條件) { cout << "字串"; } else { cout << "字串"; } } else { cout << "字串"; } } else { cout << "字串"; } return 0; } ``` 下方為錯誤示範,程式一樣可以運行沒錯,但出現BUG的時候會很難找錯誤,易讀性大大降低。 ```cpp=1 #include <bits/stdc++.h> using namespace std; int main() { int a; cin>>a; if(條件){ if(條件){ if(條件){ cout<<"字串"; } else{ cout<<"字串"; } } else{ cout<<"字串"; } } else{ cout<<"字串"; } return 0; } ``` # 變數宣告 變數宣告的功能就是讓電腦幫你記憶一個變數,但在電腦程式中,我們需要詳細的定義這個變數的性質。 | 名稱 | 類型 | 範圍 | | -------- | -------- | -------- | | int | 整數 |-2^31 ~ 2^31-1 | | long long | 長整數 |-2^63 ~ 2^63-1 | | float | 浮點數 | 小數點後第七位 | | double | 雙精度浮點數 | 小數點後第十五位 | | char | 字元 | 一個字元 | | string | 字串 | 多個字元 | | bool | 布林值 | 0(代表false)1(代表true) | 以下是變數宣告的示範: ```cpp=1 #include <bits/stdc++.h> using namespace std; int main() { // 整數 int myInt = 42; // 長整數 long long myLongLong = 123456789012345; // 浮點數 float myFloat = 3.14; // 雙精度浮點數 double myDouble = 2.718281828459045; // 字元 char myChar = 'Z'; // 字串 string myString = "Learning C++"; // 布林值 bool myBool = false; // 顯示變數的值 cout << "int: " << myInt << endl; cout << "long long: " << myLongLong << endl; cout << "float: " << myFloat << endl; cout << "double: " << myDouble << endl; cout << "char: " << myChar << endl; cout << "string: " << myString << endl; cout << "bool: " << (myBool ? "true" : "false") << endl; //看不懂沒關係 return 0; } ``` ### 輸出結果 ``` int: 42 long long: 123456789012345 float: 3.14 double: 2.71828 char: Z string: Learning C++ bool: false ``` ## 想一想 1. 變數超出該類型的範圍會發生什麼事呢?(例如 int a = 9999999999999999999,這樣子再輸出 a 會得到什麼呢?) ## 想一想-解答 當變數超出其範圍時,會發生溢出(overflow)。這種情況下,變數會回繞至該型別的最小值或最大值附近,導致結果不正確。具體的行為取決於平台和編譯器,但通常遵循以下模式: * 正溢出:以 int 舉例,當一個數值超過 int 的最大值時,它會回繞到最小值。假設你的 int 最大值是 2,147,483,647,若將其增加 1,如下方: ```cpp=1 #include <bits/stdc++.h> using namespace std; int main() { int maxInt = 2147483647; // int 的最大值2^31-1 cout << "Before overflow: " << maxInt << endl; maxInt++; cout << "After overflow: " << maxInt << endl; return 0; } ``` ### 輸出結果 ``` Before overflow: 2147483647 After overflow: -2147483648 ``` * 負溢出:以 int 舉例,當一個數值低於 int 的最小值時,它會回繞到最大值。假設你的 int 最小值是 -2,147,483,648,若將其減少 1,如下方: ```cpp=1 #include <bits/stdc++.h> using namespace std; int main() { int minInt = -2147483648; // int 的最小值-2^31 cout << "Before overflow: " << minInt << endl; minInt--; cout << "After overflow: " << minInt << endl; return 0; } ``` ### 輸出結果 ``` Before overflow: -2147483648 After overflow: 2147483647 ``` # 變數範圍 變數根據宣告的位置,可以決定有多少程式碼「認識它」,舉個例子,就像是你在班上自我介紹,但是隔壁班同學不會認識你一樣,如果你在全校面前自我介紹,那隔壁班同學就會認識你。而在程式中,我們稱之為「全域變數」和「區域變數」。 ```cpp=1 #include <bits/stdc++.h> using namespace std; int m=20; //全域變數 void add(){ int p=30; //區域變數 } int main(){ int n=10; //區域變數 for(int i=0;i<10;i++){ //迴圈變數 i=i+n; } return 0; } ``` ## 想一想 1. 上方那些變數可以在main函數中輸出呢? ## 想一想-解答 答案是 m 和 n 喔! # 輸出指令-cout cout 可以將一些資訊輸出到螢幕上,如果是字串,就要用" "框起來,如果是變數就不用。 ```cpp=1 int a = 10; string s = "電腦研習社 讚!" cout << "資訊" << endl; cout << s << endl; cout << a; ``` ### 輸出結果 ``` 資訊 電腦研習社 讚! 10 ``` 若要輸出更多資訊,又不想打很多 cout,則可以使用連續輸出。 ```cpp=1 cout << "第一個資訊" << "第二個資訊" << "第三個資訊"; ``` 若想將輸出的內容分行,可以使用指令 endl。 ```cpp=1 cout << "第一個資訊" << endl << "第二個資訊" << endl << "第三個資訊"; ``` 這邊需要注意的就是 << 的方向,不要跟接下來的 cin搞錯了。 ## 高手過招 如果希望輸出指定位數的小數,可以使用 setprecision(),具體可參考下方寫法: ```cpp=1 #include <bits/stdc++.h> using namespace std; int main() { double num = 123.456789; // 顯示 3 個有效數位 cout << setprecision(3) << num << endl; // 顯示小數點後 3 位 cout << fixed << setprecision(3) << num; return 0; } ``` ### 輸出結果 ``` 123 123.457 ``` # 輸入指令-cin cin 可以將你輸入的內容儲存到變數中,換句話說,你必須先宣告一個變數,才能使用 cin。 ```cpp=1 int a; cin >> a; ``` 如同 cout,cin 也可以做連續輸入。 ```cpp=1 int a, b, c; cin >> 變數a >> 變數b >> 變數c; ``` 這邊會出現的問題,大概就是 >> 和 << 弄混了吧! ## 題目練習 [A0001-教師示範程式](https://code.dali.tc.edu.tw/problem/A0001) --- # 運算子 運算子幫助我們進行簡單的運算,或者是邏輯的判別。 | 符號 | 意思 | | -------- | -------- | | = | 設為 | | == | 相等 | | ++ | 遞增 | | ╴╴ | 遞減 | | > | 大於 | | < | 小於 | | >= | 大於等於 | | <= | 小於等於 | | != | 不等於 | | && | 而且 | | || | 或者 | | ! | 非 | 值得注意的是,輸出運算結果時,並不需要加上" ",否則會變成字串輸出,例如下方: ```cpp=1 #include <bits/stdc++.h> using namespace std; int main(){ int a,b; a=5,b=3; cout << a+b << endl; cout << "a+b"; return 0; } ``` ### 輸出結果 ``` 8 a+b ``` ## 高手過招 * 若需使用較難的數學計算,可以在開頭先加入 #include <math.h>。 * 常用的計算函數像是 abs(x)、sqrt(x)、pow(x,n)等等,有興趣可以去學起來。 ## 題目練習 [A0002-第一個線上程式](https://code.dali.tc.edu.tw/problem/A0002) --- # 選擇結構 在寫判定式時,須注意格式,小括號內放的是條件,大括號內放的是執行內容。 ## if if 就是我們口頭上說的「如果...」,當我們給予的「條件」成立時,程式就會執行你指定的「內容」,反之,程式將會跳過這個判定式。 ```c++=1 if(條件){ 執行內容 } ``` ## if-else if-else 就是我們口頭上說的「如果...否則...」,當我們給予的「條件」成立時,程式就會執行你指定的「內容」,反之,條件不成立時,程式將會執行 else 的部分。 ```c++=1 if(條件){ 執行內容 } else{ 執行內容 } ``` ## else if else if 通常用在需假設的條件數量 >=3 時,其意思和 if相同。 ```c++=1 if(條件){ 執行內容 } else if(條件){ 執行內容 } else{ 執行內容 } ``` ## 想一想 1. 如果有不止三種情況的話,該怎麼辦呢? 2. 一定要有 else 嗎? 3. 如果同時符合兩個條件的時候,會執行哪一個? ## 高手過招 三元運算符(ternary operator)是一種簡化的條件表達式,這個表達式在APCS觀念題很愛考。 ``` condition ? expression1 : expression2 ``` * condition:一個布林表達式,評估為 true 或 false。 * expression1:如果 condition 為 true,則運算結果為這個表達式的值。 * expression2:如果 condition 為 false,則運算結果為這個表達式的值。 ## 題目練習 [A0006-分數的等第](https://code.dali.tc.edu.tw/problem/A0006) --- # 重複迴圈 重複迴圈主要用來執行相同或有連續性的程式,它化簡了我們程式的長度,重複迴圈主要有以下幾個架構: 1. 執行條件 2. 重複次數 3. 執行內容 這三個東西在等一下的三種迴圈中會使用到,也是重複迴圈的核心概念所在。 ## for for 迴圈通常用在已知道重複次數的情況下,它的格式如下。 ```c++=1 for(起始值;執行條件;一輪結束後起始值的變量){ 執行內容 } //舉例 for(int i=0;i<5;i++){ cout << i << endl; } /* i的起始值為0,每經過一次循環+1,當i小於5時執行 第一round i=0 輸出0 第二round i=1 輸出1 第三round i=2 輸出2 第四round i=3 輸出3 第五round i=4 輸出4 第六round i=5 因為執行條件為i小於5時執行 故迴圈終止 */ ``` 特別注意執行條件的部分,若條件沒給好,有可能導致迴圈無法正常執行或導致無窮迴圈。 ```c++=1 for(int i=0;i>=0;i++){ cout << i << endl; } //因為i>=0恆成立,所以此迴圈為無窮迴圈,不會終止 for(int i=0;i<0;i++){ cout << i << endl; } //因為i<0恆不成立,所以此迴圈不會執行 ``` ## 想一想 1. 下方程式碼的輸出結果會是什麼呢?為什麼會這樣子? ```c++=1 int i; for(i=0;i<10;i++){ cout << i << endl; } cout << endl; for(int j=0;j<5;j++){ cout << j << endl; } cout << endl; cout << i; cout << j; ``` ## 題目練習 [A0012-質數判斷](https://code.dali.tc.edu.tw/problem/A0012) --- ## while while 迴圈通常用在不知道重複次數,只知道執行條件的情況下。 ```c++=1 while(執行條件){ 執行內容 } ``` 當執行條件成立的情況下,while 迴圈便會一直執行。 ```c++=1 int n=10; while(n>0){ cout << n << endl; n--; } ``` ### 執行結果 ``` 10 9 8 7 6 5 4 3 2 1 ``` ## do-while do-while 和 while 迴圈最大的不同是,它不論如何都會先執行一次,才進行條件判斷。 ```c++=1 do{ 執行內容 }while(執行條件); ``` 所以就算不符合執行條件,也會執行一次後才終止。 ```c++=1 int n=10; do{ cout << n << endl; n--; }while(n<0); ``` ### 執行結果 ``` 10 ``` ## 題目練習 [A0008-兩數互質嗎?](https://code.dali.tc.edu.tw/problem/A0008) --- # break and continue 這兩者主要用在重複迴圈內,特定條件下需要終止或者跳過這次迴圈所使用,以下用一個例子來說明。 ```c++=1 for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ cout << i << " " << j << endl; } } ``` ### 執行結果 ``` 0 0 0 1 0 2 1 0 1 1 1 2 2 0 2 1 2 2 ``` ## break break 是用來終止迴圈的,可以終止「最近的一層迴圈」,通常搭配 if 做使用。 ```c++=1 for(int i=0;i<5;i++){ if(i==3){ break; } cout << i << endl; } ``` ### 執行結果 ``` 0 1 2 ``` ## 想一想 1. 下方這段程式的輸出結果是什麼呢? ```c++=1 for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ cout << i << " " << j << endl; break; } } ``` ## 題目練習 [A0014-算術基本定理](https://code.dali.tc.edu.tw/problem/A0014) --- ## continue continue 是用來「跳過」這一次的迴圈的,通常搭配 if 做使用。 ```c++=1 for(int i=0;i<3;i++){ for(int j=0;j<3;j++){ if(j==2){ continue; } cout << i << " " << j << endl; } } ``` ### 執行結果 ``` 0 0 0 1 1 0 1 1 2 0 2 1 ``` # 一維陣列 白話:有一棟名字叫 a 的大樓,裡面有 n 個房間,每間房間裡面有放東西。 程式:如下 ```c++=1 int a[n]={資料,資料,資料,資料,資料}; ``` 圖解:如下 ![image](https://hackmd.io/_uploads/ByocuyI5p.png) ## 陣列的編碼 陣列的編號在程式中是從 0 開始,所以第一間房間叫做 a[0],第二間叫做 a[1],以此類推。所以一個陣列 a[n]總共可以存放 n 筆資料,第一筆資料叫做 a[0],最後一筆資料叫做 a[n-1]。 ## 陣列的輸入 大多時候我們並不是一開始就知道陣列中的數字,也不知道有幾項,而是需要使用者輸入,遇到這種情況,我們可以這麼做: ```c++=1 int n; cin >> n; //n代表有幾筆資料 int a[n]={}; //建立一個長度為n的空陣列 for(int i=0;i<n;i++){ cin >> a[i]; //輸入每一間房間的數字 } ``` 上方這個範本之後會大量的出現在題目之中,一定要記起來! ## 陣列的輸出 陣列的輸出相對簡單,以下這段程式建立了一個名字叫做 a,用來儲存整數的一維陣列,並且將陣列中的每一項輸出。 ```c++=1 int a[5]={10,20,30,40,50}; for(int i=0;i<5;i++){ cout << a[i] << endl; } ``` ### 執行結果 ``` 10 20 30 40 50 ``` ## 想一想 1. 如果我只宣告了 int a[5],但 cout << a[13],會得到什麼結果呢?結果一定是 0 嗎? ## 陣列的運算 陣列中存放的資料可以透過運算子進行運算(忘了運算子是什麼可以回上面找)。 ```c++=1 int a[5]={10,20,30,40,50}; cout << a[1]+a[2] << endl; //20+30=50 cout << a[3]-a[2] << endl; //40-30=10 cout << a[1]*a[4] << endl; //20*50=1000 cout << a[4]/a[0] << endl; //50/10=5 ``` ### 執行結果 ``` 50 10 1000 5 ``` ## 題目練習 [APCS-o076. 1. 特技表演](https://zerojudge.tw/ShowProblem?problemid=o076) --- # 二維陣列 二維陣列你可以將他理解成多個一維陣列所拼湊起來的陣列,他有類似於數學的X,Y軸,只不過需要特別注意,在二維陣列中,左上角為原點 (0,0) ,往右跟往下都是正的。 ![image](https://hackmd.io/_uploads/HJINdkL9a.png) ## 陣列的輸入與輸出 如同一維陣列,我們並不一定會事前知道陣列中的資料,所以我們通常用下方的這個格式來處理大多數二維陣列的問題: ```c++=1 int n,m; cin >> n >> m; //n,m代表陣列長寬 int a[n][m]; //建立一個n*m大小的空陣列 for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cin >> a[i][j]; //輸入每一個陣列的資料 } } for(int i=0;i<n;i++){ for(int j=0;j<m;j++){ cout << a[i][j]; //輸出每一個陣列的資料 } } ``` 我們使用了雙重 for 迴圈來拜訪到二維陣列中的每一格,這個寫法會很常出現在二維陣列中。 ## 題目練習 [APCS-o077. 2. 電子畫布](https://zerojudge.tw/ShowProblem?problemid=o077) --- # 小結 到這邊C++的新手教學差不多告一段落了,如果都看得懂的話,你可以嘗試去zerojudge上解題,以APCS的程度來分級的話,現在的你應該有接近3級分的程度了!已經超越了一半以上的高中生了喔!希望你對程式設計的熱誠不要消失,網路上有許多資源可以學習,我也會繼續學習,期待下一篇筆記能教導更多更進階的程式內容。 --- # 連結 * [SHCH Online Judge參考解答(教學版)](https://hackmd.io/@37aitHUHRnKghKiwEbbHmg/r1cT1qEhA) * [SHCH Online Judge](https://code.dali.tc.edu.tw/) * [ZeroJudge](https://zerojudge.tw/) * [AP325](https://jmj.cmgsh.tp.edu.tw/files/AP325_v1.3.pdf) * [Yui Huang 演算法學習筆記](https://yuihuang.com/)