# C++程式教學
#### By Ching-Kai Tseng (CKK)
---
為了方便大家閱讀,可以請大家先取得這份簡報,裡面有各種程式碼提供參考
* https://reurl.cc/9vk48a
* 
**P.S 希望大家別先看進度後面的內容,這樣會暴雷 : (**
---
## 大家都加入slido一起討論吧!
* https://reurl.cc/4r95ER
* 
* 想做什麼都可以,只要不涉及**人身攻擊**等行為
---
## 簡報服用方式:
* 方向鍵很重要!

----
* 向右:切換到下一章節
* 向左:切換到上一章節
* 向下:下一頁投影片
* 向上:上一頁投影片
* P.S 如果沒辦法往下了,代表這個章節已經結束,可以向右到下一章節
* **手機板**也可以用滑動的方式換頁哦 ~
---
## 首先,我們先來認識一下C++吧

----
## C++歷史
* 1980年代由*比雅尼·斯特勞斯特魯普*發明
* 1998年,國際標準組織頒布了C++程式設計語言的第一個國際標準ISO/IEC 14882:1998
* 目前最新標準為ISO/IEC 14882:2020(包含包含了核心語言和標準庫的規則)
更多資訊請右轉[維基百科](https://zh.wikipedia.org/zh-tw/C%2B%2B)
----
<font size=3>https://hellogithub.com/report/tiobe/</font>

----
## C++有什麼特性?
1. 編譯語言(全部轉換為binary執行檔)
2. 標準模板庫**STL**(各種神奇容器vector, list, map, set以及算法sort, find等)
3. 異常處理(try, throw, catch)
4. inline function(以空間換取時間!)
5. <font color="red">物件導向(Object Oriented Programming)</font>
----
一個簡單的物件...
```cpp=
class Fraction {
private:
int numerator; // 分子
int denominator; // 分母
public:
void reduce() { // 用來簡化分數的函式(約分)
int gcdValue = gcd(numerator, denominator); // 取分子和分母的最大公因數
numerator /= gcdValue;
denominator /= gcdValue;
}
int gcd(int a, int b) { // 用來算出最大公因數的function
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
int lcm(int a, int b){ // 用來計算最小公倍數的function
return (a / gcd(a, b)) * b;
}
// Implementation function
Fraction(int num, int denom) {
numerator = num;
denominator = denom;
if (denominator == 0) { // 如果分母 = 0 時
throw invalid_argument("Denominator cannot be zero"); // throw 出一個 Denominator cannot be zero 的錯誤訊息
}
reduce(); // 對輸入的分數約分
}
Fraction add(const Fraction& other){ // 與另一個分數相加
int commonDenominator = lcm(denominator, other.denominator); // 求通分的分母(用最小公倍數)
int num1 = numerator * (commonDenominator / denominator);
int num2 = other.numerator * (commonDenominator / other.denominator);
int newNumerator = num1 + num2;
return Fraction(newNumerator, commonDenominator); // 回傳相加之後的分數
}
Fraction subtract(const Fraction& other){ // 與另一個分數相減
int commonDenominator = lcm(denominator, other.denominator); // 求通分的分母(用最小公倍數)
int num1 = numerator * (commonDenominator / denominator);
int num2 = other.numerator * (commonDenominator / other.denominator);
int newNumerator = num1 - num2;
return Fraction(newNumerator, commonDenominator); // 回傳相減之後的分數
}
Fraction multiply(const Fraction& other){ // 與另一個分數相乘
int newNumerator = numerator * other.numerator; // 分子相乘
int newDenominator = denominator * other.denominator; // 分母相乘
return Fraction(newNumerator, newDenominator); // 回傳相乘之後的分數
}
Fraction divide(const Fraction& other){
if (other.numerator == 0) { // 如果除數(分數)是0
throw invalid_argument("Cannot divide by zero fraction"); // throw 出一個 Denominator cannot be zero fraction 的錯誤訊息
}
// 進行分數相除的計算
int newNumerator = numerator * other.denominator;
int newDenominator = denominator * other.numerator;
return Fraction(newNumerator, newDenominator); // 回傳相除後的分數
}
Fraction operator+(const Fraction&);
Fraction operator-(const Fraction&);
Fraction operator*(const Fraction&);
Fraction operator/(const Fraction&);
void print(){ // 將分數顯示出來
cout << numerator << "/" << denominator << endl;
}
};
```
----
#### Q. 看不懂剛剛的程式碼,學長可以下課了嗎啊啊啊ヾ(;゚;Д;゚;)ノ゙

----
### A. 沒事啦,今天包你學會( • ̀ω•́ )
---
## 我們先寫出第一個C++程式吧!
----
Hello World!
```cpp=
#include<iostream> // 使用iostream函式庫
using namespace std; // 使用std命名空間
int main(){ // 定義主要function
cout<<"Hello World!"<<endl; // 在電腦螢幕上印出引號內文字
return 0; // 結束程式並回傳代碼0
}
```
----
Result:

---
## C++ 運算子
----
### 算術運算子
| 加法 | 減法 | 乘法 |
| :---: | :---: | :---: |
| `a + b` | `a - b` | `a * b` |
| 除法 | 取mod(餘數) | |
| `a / b` | `a % b` | |
----
#### Example
```cpp=
#include<iostream>
using namespace std;
int main(){
int a = 4;
int b = 3;
cout<<a + b<<endl; // 7
cout<<a - b<<endl; // 1
cout<<a * b<<endl; // 12
cout<<a / b<<endl; // 1
cout<<a % b<<endl; // 1
cout<<b % a<<endl; // 3
return 0;
}
```
----
#### C++的算術運算也是先乘除後加減(**取餘數與乘除在同一順位**)
```cpp=
#include<iostream>
using namespace std;
int main(){
cout<<10 + 20 * 3<<endl; // 70
cout<<(10 + 20) * 3<<endl; // 90
return 0;
}
```
----
### 關係運算子
| 等於 | 不等於 | 大於 |
| :---: | :---: | :---: |
| `a == b`| `a != b` | `a > b` |
| 小於 | 大於等於 | 小於等於 |
| `a < b` | `a >= b` | `a <= b` |
----
#### Example
```cpp=
#include<iostream>
using namespace std;
int main(){
int a = 1;
int b = 2;
int c = 3;
cout<<(a==1)<<endl; // true
cout<<(a==b)<<endl; // false
cout<<(a!=c)<<endl; // true
cout<<(c>=b)<<endl; // true
cout<<(a<=1)<<endl; // true
}
```
----
### 邏輯運算子
| 且 | 或 | 非 | 邏輯互斥 |
| :---: | :---: | :---: | :---: |
| `a && b` | `a \|\| b` | `!a` | `a^b` |
----
#### Example
```cpp=
#include<iostream>
using namespace std;
int main(){
bool a = true;
bool b = false;
cout<<a<<endl; // 1
cout<<!a<<endl; // 0
cout<<(a&&b)<<endl; // 0
cout<<(a||b)<<endl; // 1
cout<<(a&&(!b))<<endl; // 1
cout<<(a^(!b))<<endl; // 0
}
```
---
## C++ 基本變數型態、宣告
----
### 變數宣告方式
`<變數類型> <變數名稱> [ = 值];`
----
### 命名變數需要注意的是...
* 變數必定是**英數字和底線**的組合
* 名稱的第一個字元**不能是數字**
* 避免與C++內鍵變數名或函式名重複(int, char, string, max 等)
* **駝峰**命名法、**底線**命名法
----
example
```cpp=
int firstVar = 2024;
int secondVar = 113;
int thirdVar;
```
----
### 變數的作用範圍
1. 全域變數:可以讓所有執行程式碼都取得的到
2. 區域變數:在那一個函式裡面才能取得
#### 注意:<font color="red">不要濫用全域變數</font>,不然可能會產生衝突
----
```cpp=
#include<iostream>
using namespace std;
int global_var = 10; // 全域變數(寫在最外面)
void func1(){
int local_var = 2;
cout<<local_var<<endl; // 2
cout<<global_var<<endl; // 10
}
int main(){
int local_var = 1;
cout<<local_var<<endl; // 1
cout<<global_var<<endl; // 10
func1();
}
```
----
#### 變數是可以被更改的
```cpp=
#include <iostream>
using namespace std;
int main()
{
int a = 10;
cout<<"a = "<<a<<endl;
a = 20;
cout<<"a = "<<a<<endl;
return 123;
}
```
----
Output:

----
#### 相對的,常數(const)是不能更改的
```cpp=
#include <iostream>
using namespace std;
int main()
{
const int a = 10;
cout<<"a = "<<a<<endl;
a = 20;
cout<<"a = "<<a<<endl;
return 123;
}
```

----
### int
```cpp=
int myGrade = 59;
int yourGrade = 100;
```
----
### int
* 是一種儲存**整數**的資料型別
* 有4bytes的儲存空間
* 可儲存-2,147,483,648 至 2,147,483,647的整數(超過會很可怕)
----
### int 運算子
1. '+' (`a+b`):回傳兩個int變數相加
2. '-' (`a-b`):回傳兩個int變數相減
3. '\*' (`a*b`):回傳兩個int變數相乘
4. '/' (`a/b`):回傳兩個變數相除
5. '%' (`a%b`):回傳a除以b的餘數
----
#### Example
```cpp=
int main(){
int a = 4;
int b = 3;
cout<<a + b<<endl; // 7
cout<<a - b<<endl; // 1
cout<<a * b<<endl; // 12
cout<<a / b<<endl; // 1
cout<<a % b<<endl; // 1
cout<<b % a<<endl; // 3
return 0;
}
```
----
### double
```cpp=
double d1 = 3.14159;
double d2 = 2.71828;
```
----
### double
* 是一種儲存**浮點數**的資料型別
* 有8bytes的儲存空間
* 可儲存1.7E-308 至 1.7E+308的浮點數
----
### double 運算子
* 與int大致相同
* double與int的相互計算時,儲存為int的變數會被強制轉型成double
----
### char
```cpp=
char c1 = 'A';
char c2 = 'a';
```
----
### char
* 是一種儲存**字元**的資料型別
* 有1byte的儲存空間
----
https://www.ascii-code.com/

----
### char 運算子
* 將字元轉換成ascii code的編號再進行數學計算
* 計算完回傳int資料型態
----
```cpp=
#include<iostream>
using namespace std;
int main(){
char c1 = 'A';
char c2 = ' ';
cout<<"c1: "<<c1<<endl; // A
cout<<"c2: "<<c2<<endl; // 空格
cout<<"(c1 + 1) = "<<(c1 + 1)<<endl; // 66
cout<<"(c1 + c2) = "<<(c1 + c2)<<endl; // 97
cout<<"('a'/2) = "<<('a'/2)<<endl; // 48
}
```
##### [GitHub 連結在此](https://github.com/tseng91301/bime_camp_tutorial/blob/main/example/char_calculate.cpp)
----
### Output:

#### Q. 那我們要如和輸出字元呢?
----
### 強制轉型(coercion)
也就是將某種資料型態轉換為另一種的過程,在程式進行的過程中十分常見。
----
### 例如...
```cpp=
#include<iostream>
using namespace std;
int main(){
int a1 = 12;
double a2 = 3.55;
cout<<(a1 + a2)<<endl; // 會將a1轉換成double型態再與a2計算
}
```
----
### 手動進行強制轉型
```cpp=
#include<iostream>
using namespace std;
int main(){
cout<<(char)65<<endl; // A
}
```
----
`(變數型態)<欲轉換的變數名稱 or 資料>`
```cpp=
(char)65;
```
`變數型態(<欲轉換的變數名稱 or 資料>)`
```cpp=
char(65);
```
---
## C++ 判斷式
```cpp=
int main(){
int num = 7;
if(num > 9){
cout<<"A"<<endl;
}else if(num <= 9 && num >= 1){
cout<<"B"<<endl;
}else{
cout<<"C"<<endl;
}
// OUTPUT: B
}
```
----
### if - else
```cpp=
if(判斷式或布林值){
滿足條件時執行的動作
}else if(判斷式或布林值){
滿足條件時執行的動作
}else if(判斷式或布林值)
.
.
.
}else{
不滿足上述所有條件時執行的動作
}
```
----
### 巢狀 if
```cpp=
#include <iostream>
using namespace std;
int main() {
int a = 10;
int b = 20;
if (a > 5) { // 外層的 if-else
if (b > 15) { // 內層的 if-else (滿足 a > 5 才會進來)
cout << "a is bigger than 5 and b is bigger than 15" << endl;
} else {
cout << "a is bigger than 5 but b is not bigger than 15" << endl;
}
} else {
cout << "a is not bigger than 5" << endl;
}
return 0;
}
```
##### [GitHub 連結在此](https://github.com/tseng91301/bime_camp_tutorial/blob/main/example/nested_if.cpp)
---
## C++ 迴圈
1. **for** loop
2. **while** loop
----
### for loop
```cpp=
for(設定變數初始值; 設定變數的上(下)限; 每次執行完對變數做的動作){
在迴圈中的程式碼
}
```
----
### Example
```cpp=
#include<iostream>
using namespace std;
int main(){
for(int a=1; a<=8; a+=1){
cout<<"Number: "<<a<<endl;
}
}
```
----
### Output

----
### while loop
```cpp=
while(判斷式或布林值){
迴圈內執行的程式碼
}
// 先判斷再執行
```
Or
```cpp=
do{
迴圈內執行的程式碼
}while(判斷式或布林值);
// 先執行再判斷
```
`若while內的判斷式值為false會跳出迴圈`
----
### 這兩個有什麼差異?!
猜猜這個程式會輸出什麼
```cpp=
#include<iostream>
using namespace std;
int main(){
do{
cout<<"I hope I won't be executed"<<endl;
}while(false);
}
```
##### 用各位電腦中的C++編輯器來揭曉答案吧
----
這個呢?
```cpp=
#include<iostream>
using namespace std;
int main(){
while(false){
cout<<"I REALLY don't want to be executed"<<endl;
}
}
```
----
### break, continue
1. break可以用來跳出一個迴圈,不管迴圈條件是否滿足
2. continue用來讓電腦馬上執行下一次迴圈
----
### break
```cpp=
#include<iostream>
#include<time.h>
using namespace std;
int main(){
srand(time(nullptr)); // 使用當前的時間製作一個rand種子值
while(1){
int rd = rand()%10; //產生0到9之間的隨機數
cout<<rd<<endl;
if(rd == 5){
break; // 如果隨機生成的數字 = 5時,跳出迴圈
}
}
}
```
----
### Output

----
### continue
```cpp=
#include<iostream>
using namespace std;
int main(){
for(int a=1; a<=50; a++){
if(a%5 != 0){ // 如果 a 無法被5整除
continue; // 則跳到下一次迴圈
}
cout<<a<<endl;
}
}
```
----
### Output

---
## 讓我們複習一下上次的教學內容
----
### 暖身 - 簡單迴圈
#### 還記得ascii code嗎?

----
#### 用迴圈的方法把編號33 ~ 123的字元都顯示出來(用字元的方式,不要是數字)
* 觀念:迴圈、強制轉型、cout
* 字元之間換行或空格均可
* 1pt/group
----
### if - else + 迴圈
#### 我們來做一個數字炸彈遊戲
1. 先讓電腦隨機生成一個數字
2. 不停重複讓使用者輸入數字
3. 當輸入的數字和生成的數字相同就輸了!!!
#### 1pt/group
----
#### 從這邊來改吧
```cpp=
#include<iostream>
#include<time.h>
using namespace std;
int main(){
srand(time(nullptr));
int randomNumber = rand()%100; // 隨機生成一個0 到 100之間的整數
while(true){
cout<<"Please input a number: ";
int userInput;
cin>>userInput; // 讓使用者輸入userInput這個數字用的程式碼
// 接下來靠你們了,要寫出判斷輸入的數字是否為生成數字並且跳出迴圈的程式碼
}
// 輸出遊戲結束的文字
cout<<"Boom!!!!!"<<endl;
cout<<"Game Over"<<endl;
return 0;
}
```
----
### 難度提升!
#### 這個遊戲一定是多個人玩才好玩吧,那我們再加入一些東西,讓他變multiplayer game (這裡先兩個人)
* 讓程式判斷現在玩的人是誰,並在螢幕上提示現在是輪到誰了
* 程式要知道是誰輸了,並且在螢幕上顯示
* 1pt/group
----
#### 從這邊來改吧
```cpp=
#include<iostream>
#include<time.h>
using namespace std;
int main(){
int numberOfPlayers = 2;
srand(time(nullptr));
int randomNumber = rand()%100; // 隨機生成一個0 到 100之間的整數
int nowPlaying = 0; // 用來儲存現在是第幾位玩家在玩
while(true){
cout<<"Player "<< " /*這邊要讓電腦顯示是第幾位玩家要輸入*/ " <<", Please input a number: ";
int userInput;
cin>>userInput; // 讓使用者輸入userInput這個數字用的程式碼
// 接下來靠你們了,要寫出判斷輸入的數字是否為生成數字並且跳出迴圈的程式碼
// 這邊可能要判斷是否要回到第一位玩家輸入
}
// 輸出遊戲結束的文字
cout<<"Boom!!!!!"<<endl;
cout<<"Player "<<nowPlaying + 1<<" lose the game."<<endl; // 記得 + 1,不然他會是從第0位玩家算起的
return 0;
}
```
----
### 難度提升!
#### 如果今天有很多人要玩怎麼辦??
* 加一個輸入讓使用者自己說要多少人
* 其他功能跟上一個程式一樣
* 提示:前一關都用if - else的同學可以試著用看看取餘數(參考就好)
* 1pt/group
----
### 範例輸入/輸出
```shell=
Input the number of players: 3
Player 1, Input a number: 1
.
.
.
Player 2, Input a number: 3
Player 3, Input a number: 12
Boom!!!!!
Player 3 lose!
```
----
這個我來現打程式碼吧!
---
## C++ 陣列

----
### 陣列介紹
* 由多個同一型態的變數組合而成
* 分為靜態陣列及動態陣列(pointer)
* 計數均**從0開始**
* 注意:靜態陣列必須先**指定元素數量**
----
### 如何新增一個陣列?
1. 指定資料型態
2. 設定陣列名稱(與變數命名限制相同)
3. 指定資料數量
4. Optional:寫入陣列內容
`資料型態 陣列名稱[數量]([更多維度]...);`
----
### Example
```cpp=
#include<iostream>
using namespace std;
int main(){
int arr1[10]; // 新增一個10項的陣列arr1
int arr2[10] = {1, 2, 3, 4, 5, 1, 2, 3, 4, 5}; // 新增一個10項的陣列arr並賦值
int two_dimension1[5][5]; // 新增一個 5x5 的陣列
int two_dimension2[5][5] = { // 新增一個 5x5 的陣列並賦值
{1, 2, 3, 4, 5},
{5, 4, 3, 2, 1}
};
}
```
----
### 更改/取用陣列內的元素
```cpp=
#include<iostream>
using namespace std;
int main(){
int arr1[10];
for(int a = 0; a < 10; a++){
arr1[a] = a+1;
}
for(int a = 0; a < 10; a++){
cout<<arr1[a]<<", ";
}
cout<<endl;
}
```
----
### 小練習 - 還是數字炸彈遊戲
* 之前的數字炸彈遊戲有一個問題,就是可以不斷輸入重複的數字
* 這裡使用陣列的方式,記錄所有已經輸入過的數字(**僅供參考**)
* 當使用者輸入以輸入過的數字時,電腦要提示說已經輸入過,並讓使用者再輸入一次(不斷重複值到使用者輸入還未被輸入的數字)
* 不只一種解法,嘗試用最快速的方法判斷數字是否被輸入過
* 3pts/group
----
### 另一個小練習
#### 現在已經有很多破解魔術方塊的機器人,但你想要自己做一個。
#### Day 1 讓機器人辨識到現在魔術方塊各是什麼顏色
----
#### 目標:
* 製做一個用來儲存魔術方塊顏色的陣列(這裡以2x2x2為例)因此有6面,每面有2x2個方塊(寫個三維陣列?)
* 讓使用者輸入目前的魔術方塊資料
* 輸出魔術方塊的第二面
* 我們用數字1~6代表顏色(或者也可以嘗試用英文字母看看)
* 1pt/group
----
範例輸入/輸出:
```shell=
Please input the 1th plane of the cube:
Row 1:
Column 1: 1
Column 2: 2
Row 2:
Column 1: 3
Column 2: 4
.
.
.
Please input the 6th plane of the cube:
Row 1:
Column 1: 3
Column 2: 4
Row 2:
Column 1: 5
Column 2: 6
The 2nd plane of cube is:
5, 6,
1, 2,
```
----
### 提示
```cpp=
#include<iostream>
using namespace std;
int main(){
int cube[6][2][2];
// 這裡可能要用到3層for 迴圈
cin>>cube[a][b][c];
// 這裡可能要用到3層for 迴圈
}
cout<<"The 2nd plane of cube is: "<<endl;
for(int a=0;a<2;a++){
for(int b=0;b<2;b++){
// 這邊要輸出什麼哩?
}
cout<<endl;
}
}
```
----
### answer
[GitHub 連結](https://github.com/tseng91301/bime_camp_tutorial/blob/main/practice/array_practice1.cpp)
----
### 警語:
* 請隨時注意當前陣列的長度
* 不要存取超過範圍的陣列內容(最常見的錯誤是取10位陣列的第10項或行列看錯)
----
### 一個簡單的錯誤示範...
```cpp=
#include<iostream>
using namespace std;
int main(){
int matrix[3][4] = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
for(int a=0;a<4;a++){
for(int b=0;b<3;b++){
cout<<matrix[a][b]<<" ";
}
cout<<endl;
}
}
```
----
### 希望讓陣列的大小是可以變化的?
```cpp=
/*這個程式碼是6小隊輔「阿瑋」教我的,他是修過資工系DSA課程的大電神*/
#include<iostream>
using namespace std;
int main(){
int amount = 10;
int *arr;
arr = (int*)malloc(sizeof(int) * amount); // 指定arr這個指標存放10個int的記憶體大小
for(int a=0;a<amount;a++){
arr[a] = a;
}
cout<<"The origin array: ";
for(int a=0;a<amount;a++){
cout<<arr[a]<<" ";
}
cout<<endl;
amount += 5;
arr = (int*)realloc(arr, sizeof(int) * amount); // 為arr重新分配15個int的記憶體大小
for(int a=10;a<amount;a++){
arr[a] = amount - a;
}
cout<<"The altered array: ";
for(int a=0;a<amount;a++){
cout<<arr[a]<<" ";
}
cout<<endl;
free(arr);
}
```
##### [GitHub 連結在此](https://github.com/tseng91301/bime_camp_tutorial/blob/main/example/array_example3.cpp)
----
當然,我們今天不會教這個,之後會教更簡單的工具,讓我們拭目以待( Φ ω Φ )
---
## C++ function
```cpp=
#include<iostream>
using namespace std;
int add_num(int i1, int i2){
int result = i1 + i2;
return result;
}
int main(){
int add_res = add_num(100, 150);
cout<<"add_res = "<<add_res<<endl;
}
```
----
## C++ function
用法:
```cpp=
返回值類型 函式名稱([參數列表]){
函式內的程式碼
return 回傳的值(若有需要)
}
```
----
### 小練習:自己做一個function
* 做一個函式,功能是計算直角三角形的斜邊高
* 需要有3個輸入,分別是兩個短邊和一個斜邊
* 經過函式的計算,算出三角形的斜邊高
* 記得要回傳double,畢竟可能是個小數
* 1pt/group
----
### 範例輸入/輸出:
```shell=
Input side1, side2 and hypotenuse height divide by blank: 3 4 5
The hypotenuse height is: 2.4
```
P.S 用其他的直角三角形組合(例如:5, 12, 13;7, 24, 25)
----
### 提示
```cpp=
#include<iostream>
using namespace std;
double calculate_hypotenuse_height( /* 這邊是不是需要指定一些參數? */ ){ // hypotenuse 是斜邊的意思
// 在這裡面計算上面的參數,並回傳結果(斜邊高)
}
int main(){
int s1, s2, hyp;
cout<<"Input side1, side2 and hypotenuse height divide by blank: ";
cin>>s1>>s2>>hyp;
cout<<"The hypotenuse height is: "<< /* 這裡要呼叫那個函式才能得到答案 */ <<endl;
return 0;
}
```
----
### answer
[GitHub 連結](https://github.com/tseng91301/bime_camp_tutorial/blob/main/practice/function_practice1.cpp)
----
### inline function
* 寫法跟一般函式一樣,只是前面加一個`inline`
* 程式在編譯後會像是將內容直接寫在主程式裡面一樣
* 會增加執行速度(不須進行function pointer跳轉)
* 但會讓執行檔變比較大
```cpp=
inline void hi(){
cout<<"Hello"<<endl;
return;
}
```
----
### 遞迴函數
* 在一個函數中執行一個相同的函數,以達到一些目的(一種策略)
* 要注意函數是否有中止條件,否則容易出現無窮迴圈
----
### Example (以費式數列計算為例)
```cpp=
#include <iostream>
using namespace std;
int fibonacci(int n) {
if (n == 0) {
return 0;
} else if (n == 1) {
return 1;
} else {
return fibonacci(n - 1) + fibonacci(n - 2);
}
}
int main() {
int number = 10;
cout << "Fibonacci number at position " << number << " is " << fibonacci(number) << endl;
// Output: Fibonacci number at position 10 is 55
return 0;
}
```
##### [GitHub 連結在此](https://github.com/tseng91301/bime_camp_tutorial/blob/main/example/fibonacci.cpp)
----
### Function Overload
* 使用相同的函數名稱創建多個函數
* 各個函數之間一定要使用***不同的參數種類***
* 當一個函數要處理多種資料型態時可能會用到
----
### Example
```cpp=
#include<iostream>
using namespace std;
int add_num(int i1, int i2){
int result = i1 + i2;
return result;
}
double add_num(double i1, double i2){
double result = i1 + i2;
return result;
}
int main(){
cout<<add_num(12, 13)<<endl; // 25
cout<<add_num(0.2, 0.4)<<endl; // 0.6
}
```
---
## C++ class
----
### class 架構
1. class 宣告 (class 名稱)
2. private 區塊 (只有在class內的function才能存取到的部分)
3. protected 區塊 (與private相似,只是繼承的class也能使用)
4. public 區塊 (外部也可以存取到的部分)
----
### A brief example of class
```cpp=
#include <iostream>
#include <stdexcept>
using namespace std;
/*寫完可以是看看自己寫一個==的邏輯運算子(Fraction無法直接使用==)*/
class Fraction {
private:
int numerator; // 分子
int denominator; // 分母
public:
void reduce() { // 用來簡化分數的函式(約分)
int gcdValue = gcd(numerator, denominator); // 取分子和分母的最大公因數
numerator /= gcdValue;
denominator /= gcdValue;
}
int gcd(int a, int b) { // 用來算出最大公因數的function
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
int lcm(int a, int b){ // 用來計算最小公倍數的function
return (a / gcd(a, b)) * b;
}
// Implementation function
Fraction(int num, int denom) : numerator(num), denominator(denom) {
if (denominator == 0) { // 如果分母 = 0 時
throw invalid_argument("Denominator cannot be zero"); // throw 出一個 Denominator cannot be zero 的錯誤訊息
}
reduce(); // 對輸入的分數約分
}
.
.
.
太多了...
.
.
.
Fraction result = f1.add(f2);
cout << "Sum: ";
result.print();
result = f1 + f2;
cout << "Sum (function): ";
result.print();
result = f1 - f2;
cout << "Difference: ";
result.print();
result = f1.subtract(f2);
cout << "Difference (function): ";
result.print();
result = f1 * f2;
cout << "Product: ";
result.print();
result = f1.multiply(f2);
cout << "Product (function): ";
result.print();
result = f1 / f2;
cout << "Quotient: ";
result.print();
result = f1.divide(f2);
cout << "Quotient (function): ";
result.print();
} catch (const exception& e) {
cerr << e.what() << endl; // e.what() 輸出上面throw的錯誤訊息, cerr輸出錯誤訊息
}
return 0;
}
```
##### [GitHub 連結在此](https://youtu.be/dQw4w9WgXcQ?si=kE_3cN1ZEJJn9ZyH)
----
###### [<span style="color: white;">好啦正常的在這裡</span>](https://github.com/tseng91301/bime_camp_tutorial/blob/main/example/class_example_new.cpp)
###### [https://github.com/tseng91301/bime_camp_tutorial/blob/main/class_example.cpp](https://youtu.be/dQw4w9WgXcQ?si=kE_3cN1ZEJJn9ZyH)
###### [<span style="color: white;">再騙人我是狗</span>](https://www.youtube.com/watch?v=cfe8TiNp1EY&ab_channel=PeterChi)
----
### 該來學MarkDown了吧
```
###### [<span style="color: white;">好啦正常的在這裡</span>](https://github.com/tseng91301/bime_camp_tutorial/blob/main/class_example_new.cpp)
###### [https://github.com/tseng91301/bime_camp_tutorial/blob/main/class_example.cpp](https://youtu.be/dQw4w9WgXcQ?si=kE_3cN1ZEJJn9ZyH)
###### [<span style="color: white;">再騙人我是狗</span>](https://www.youtube.com/watch?v=cfe8TiNp1EY&ab_channel=PeterChi)
```
----
### Implementation function(構件函數)
```cpp=
Fraction(int num, int denom) {
numerator = num;
denominator = denom;
if (denominator == 0) { // 如果分母 = 0 時
throw invalid_argument("Denominator cannot be zero"); // throw 出一個 Denominator cannot be zero 的錯誤訊息
}
reduce(); // 對輸入的分數約分
}
```
* 通常寫在public區塊
* 是一個class被宣告時會跑的function(初始化)
* 可以在裡面寫多個構件函數(function overload)
----
### class的內部函數
* 可以寫在class的大括號內(就跟一般的function相同)
* 若要寫在外面要加上`<class name>::`
```cpp=
Fraction add(const Fraction& other){ // 與另一個分數相加
int commonDenominator = lcm(denominator, other.denominator); // 求通分的分母(用最小公倍數)
int num1 = numerator * (commonDenominator / denominator);
int num2 = other.numerator * (commonDenominator / other.denominator);
int newNumerator = num1 + num2;
return Fraction(newNumerator, commonDenominator); // 回傳相加之後的分數
}
```
----
### 取用class的內部元素
* 從class外部只能用public內的變數或函數
* class內部能夠使用或更改private, protected內的變數值
* 用法(外部):
```cpp=
class_name.class_function();
```
----
### class的運算子定義(overload)
使用`operator<運算子類型>`函數來實現
```cpp=
Fraction Fraction::operator+(const Fraction& f2){ // 設定 + 法運算子
return add(f2);
}
Fraction Fraction::operator-(const Fraction& f2){ // 設定 - 法運算子
return subtract(f2);
}
```
----
### 各種operator...

<font size=5>更多operator overload 請見 [learn.microsoft.com](https://learn.microsoft.com/zh-tw/cpp/cpp/operator-overloading?view=msvc-170)</font>
----
### 對了!各位剛剛有沒有看到這個函數
```cpp=
int gcd(int a, int b) { // 用來算出最大公因數的function
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
```
----
#### 其實這個就可以用**遞迴函數**完成,讓程式更好看喔
* 提示:使用輾轉相除法
* 
* [YouTube 影片](https://www.youtube.com/watch?v=fGesPF3QA1U&ab_channel=Stepp%E5%AD%B8%E9%99%A2)
----
### 答案在這邊
[GitHub 連結](https://github.com/tseng91301/bime_camp_tutorial/blob/main/practice/gcd_cal.cpp)
---
### 接著,讓我們來探討這一行
```cpp=
using namespace std;
```
----
### namespace 是啥?可以吃嗎
* `namespace`是一種命名空間,裡面包含了各式各樣的function
* std是C++中的一個標準命名空間,裡面包含了string, vector等各種功能
----
### using namespace <命名空間名稱>
* 讓相關的物件和函數預設使用此命名空間底下的
* 若沒有預設使用,則要在每個相關物件底下都加上`命名空間名稱::`
```cpp=
#include<iostream>
int main(){
std::string outp = "abc";
std::cout<<outp<<std::endl;
}
```
----
### 如何自訂義namespace
```cpp=
#include<iostream>
namespace CustomNamespace { // 創建一個命名空間'CustomNamespace'
void func(){
std::cout<<"This is from CustomNamespace"<<std::endl;
}
}
void func(){
std::cout<<"This is from outside"<<std::endl;
}
int main(){
func();
CustomNamespace::func();
}
```
##### [GitHub 連結在此](https://github.com/tseng91301/bime_camp_tutorial/blob/main/example/custom_namespace.cpp)
----
### std 常用函數, 物件
----
### std::cout
不用多說了吧
----
### std::cin
* 與cout相反,是用來輸入文字的一種物件
* 用這種方法得到的文字沒辦法有空格
* 用`std::getline(std::cin, 要輸入的變數);`進行有空格的輸入
* Example:
```cpp=
#include<iostream>
int main(){
int inp;
std::cout<<"Input a number: ";
std::cin>>inp;
std::cout<<"You type: "<<inp<<std::endl;
}
```
----
### std::string
* 是一個用來儲存字串的class
* 使用時要引入cstring函式庫
* 包含很多字串處理的function(參考 https://cplusplus.com/reference/string/string/)
* std另有`std::to_string(<int, double...>);`用來將數字轉換為string
----
### string 用法:
```cpp=
#include<iostream>
#include<cstring>
using namespace std; // 使用std命名空間
int main(){
string s1 = "abc"; // 指定s1是"abc"
string s2;
cout<<"Input s2: ";
cin>>s2; // 讓用戶輸入s2
string s3 = s1 + s2; // 使用 '+' 將兩個string結合再一起,儲存結果於s3
cout<<s3<<endl; // 輸出s3字串
cout<<s3[3]<<endl; // 輸出s3的第3個字元
}
```
##### [GitHub 連結在此](https://github.com/tseng91301/bime_camp_tutorial/blob/main/example/string_example.cpp)
----
### 小練習 - 凱薩加密法
* 指定一個字串"`S VYFO XDE LSWO CY WEMR, KC GOVV KC XDE LSWOMKWZ, IOOOO!`"
* 輸入這個字串
* 對這個字串的每個字元進行減法運算(若超出A到Z範圍則+-26)
* 會得到一個**有意義的句子**
* 提示:會用到char運算、判斷式、string等
* 1pt/group
----
### 答案在這邊
[GitHub 連結](https://github.com/tseng91301/bime_camp_tutorial/blob/main/practice/prac_caesar_enc.cpp)
----
### std::vector
* 一種容器,用來存放多個變數在一起並有序排列
* 是[動態陣列(array)](https://github.com/tseng91301/bime_camp_tutorial/blob/main/dynamic_pointer.cpp)的進化版
* 使用時要從後面加入資料,也是從後面刪除資料
* 初始化vector時,要指定存放的變數資料型態(`vector<資料型態> name`)
* 更多資訊請見 https://cplusplus.com/reference/vector/vector/
----
### vector範例
```cpp=
#include<iostream>
#include<vector>
using namespace std;
int main(){
vector<int> scores; // 宣告一個vector並指定存放的資料型態為int
for(int a=0;a<100;a++){
scores.push_back(a+1); // 在後面插入a的值
}
cout<<"Size of scores: "<<scores.size()<<endl; // scores.size() 輸出scores目前的長度
scores[49] = 1000; // 將scores的第49項改成1000
for(int a=99;a>=0;a--){
cout<<scores[a]<<", ";
scores.pop_back(); // 刪除scores的最後一個元素
}
cout<<endl;
cout<<"Size of scores: "<<scores.size()<<endl;
}
```
##### [GitHub 連結在此](https://github.com/tseng91301/bime_camp_tutorial/blob/main/example/vector_example.cpp)
----
### 小練習2
#### 還記得第(12, 6)頁的魔術方塊題目嗎?我們試試看用vector寫出來
* 善用vector的功能,我們這次讓使用者可以自訂義要幾x幾x幾的魔術方塊
* 其他功能均相同
* 不用害怕,真的很簡單!
* 可以用上個魔術方塊程式來改
* 1pt/group
----
### 範例輸出
```shell=
Please input the side length of the cube: 3
Please input the 1th plane of the cube:
Row 1:
Column 1: 1
Column 2: 2
Column 3: 3
Row 2:
Column 1: 4
Column 2: 5
Column 3: 6
Row 3:
Column 1: 1
Column 2: 2
Column 3: 3
Please input the 2th plane of the cube:
Row 1:
Column 1: 3
Column 2: 2
Column 3: 1
Row 2:
Column 1: 6
Column 2: 5
Column 3: 4
Row 3:
Column 1: 5
Column 2: 4
Column 3: 3
Please input the 3th plane of the cube:
Row 1:
Column 1: 1
Column 2: 4
Column 3: 3
Row 2:
Column 1: 5
Column 2: 3
Column 3: 6
Row 3:
Column 1: 4
Column 2: 2
Column 3: 5
Please input the 4th plane of the cube:
Row 1:
Column 1: 3
Column 2: 5
Column 3: 4
Row 2:
Column 1: 2
Column 2: 3
Column 3: 6
Row 3:
Column 1: 5
Column 2: 1
Column 3: 4
Please input the 5th plane of the cube:
Row 1:
Column 1: 1
Column 2: 1
Column 3: 3
Row 2:
Column 1: 5
Column 2: 3
Column 3: 2
Row 3:
Column 1: 4
Column 2: 6
Column 3: 3
Please input the 6th plane of the cube:
Row 1:
Column 1: 1
Column 2: 3
Column 3: 5
Row 2:
Column 1: 4
Column 2: 6
Column 3: 2
Row 3:
Column 1: 3
Column 2: 4
Column 3: 5
The 2nd plane of cube is:
3, 2, 1,
6, 5, 4,
5, 4, 3,
```
----
### 提示1
* vector<>,在<>裡面加的東西可以是任何東東,要是裡面再包一個vector\<int\>,是不是變成陣列裡面包陣列?(二維陣列的意思)
* 要注意你在<>裡面給什麼,push_back()就要餵什麼!
----
### 提示2
```cpp=
#include<iostream>
#include<vector>
using namespace std;
int main(){
int sideLengthOfCube;
cout<<"Please input the side length of the cube: ";
cin>>sideLengthOfCube;
// 藉由提示1,所以三維陣列怎麼宣告呢?
for(int a=0;a<6;a++){
cout<<"Please input the "<<a + 1<<"th plane of the cube: "<<endl; // 這裡大家都用th,但其實1 是st,2 是nd,3 是rd,可以想看看怎麼改
vector<vector<int>> t1; // 第一層要初始化一個二維vector,放完資料再餵給三維vector吃
for(int b=0;b<sideLengthOfCube;b++){
cout<<"Row "<<(b+1)<<": "<<endl;
// 以此類推,所以這邊要放什麼呢 - A?
for(int c=0;c<sideLengthOfCube;c++){
cout<<"Column "<<(c+1)<<": ";
int t3;
cin>>t3;
// t3 是輸入的數字,要如何放到 A 裡面?
}
t1.push_back(t2); // 將資料加入二維vector
}
cube.push_back(t1); //將二維陣列放到三維vector裡面
}
cout<<"The 2nd plane of cube is: "<<endl;
for(int a=0;a<sideLengthOfCube;a++){
for(int b=0;b<sideLengthOfCube;b++){
// 要叫出vector裡面的值其實跟陣列的方法一樣喔,所以要放什麼?
}
cout<<endl;
}
}
```
----
### 答案在這邊
[GitHub 連結](https://github.com/tseng91301/bime_camp_tutorial/blob/main/practice/vector_practice1.cpp)
---
### 再看一次這個程式就了解這是什麼了吧
```cpp=
class Fraction {
private:
int numerator; // 分子
int denominator; // 分母
public:
void reduce() { // 用來簡化分數的函式(約分)
int gcdValue = gcd(numerator, denominator); // 取分子和分母的最大公因數
numerator /= gcdValue;
denominator /= gcdValue;
}
int gcd(int a, int b) { // 用來算出最大公因數的function
while (b != 0) {
int t = b;
b = a % b;
a = t;
}
return a;
}
int lcm(int a, int b){ // 用來計算最小公倍數的function
return (a / gcd(a, b)) * b;
}
// Implementation function
Fraction(int num, int denom) {
numerator = num;
denominator = denom;
if (denominator == 0) { // 如果分母 = 0 時
throw invalid_argument("Denominator cannot be zero"); // throw 出一個 Denominator cannot be zero 的錯誤訊息
}
reduce(); // 對輸入的分數約分
}
Fraction add(const Fraction& other){ // 與另一個分數相加
int commonDenominator = lcm(denominator, other.denominator); // 求通分的分母(用最小公倍數)
int num1 = numerator * (commonDenominator / denominator);
int num2 = other.numerator * (commonDenominator / other.denominator);
int newNumerator = num1 + num2;
return Fraction(newNumerator, commonDenominator); // 回傳相加之後的分數
}
Fraction subtract(const Fraction& other){ // 與另一個分數相減
int commonDenominator = lcm(denominator, other.denominator); // 求通分的分母(用最小公倍數)
int num1 = numerator * (commonDenominator / denominator);
int num2 = other.numerator * (commonDenominator / other.denominator);
int newNumerator = num1 - num2;
return Fraction(newNumerator, commonDenominator); // 回傳相減之後的分數
}
Fraction multiply(const Fraction& other){ // 與另一個分數相乘
int newNumerator = numerator * other.numerator; // 分子相乘
int newDenominator = denominator * other.denominator; // 分母相乘
return Fraction(newNumerator, newDenominator); // 回傳相乘之後的分數
}
Fraction divide(const Fraction& other){
if (other.numerator == 0) { // 如果除數(分數)是0
throw invalid_argument("Cannot divide by zero fraction"); // throw 出一個 Denominator cannot be zero fraction 的錯誤訊息
}
// 進行分數相除的計算
int newNumerator = numerator * other.denominator;
int newDenominator = denominator * other.numerator;
return Fraction(newNumerator, newDenominator); // 回傳相除後的分數
}
Fraction operator+(const Fraction&);
Fraction operator-(const Fraction&);
Fraction operator*(const Fraction&);
Fraction operator/(const Fraction&);
void print(){ // 將分數顯示出來
cout << numerator << "/" << denominator << endl;
}
};
```
---
#### 如果可以了

---
#### 那就...

---
### 進行實作的部分吧!!

###### 3x 圖片來源: IG: @xup6kun
----
### ZeroJudge - 陪伴我高中三年的程式解題系統

----
### [a004. 文文的求婚](https://zerojudge.tw/ShowProblem?problemid=a004)
#### 提示:這一題(輸入直到EOF)的cin輸入要這樣寫:
```cpp=
int year;
while(cin>>year){
// Your code
}
```
* 0.5pt/group
----
### [a244. 新手訓練 ~ for + if](https://zerojudge.tw/ShowProblem?problemid=a244)
#### 提示:
* 兩個數字相乘有時候會超出int範圍,用`long long`計算吧
```cpp=
long long n1, n2;
```
* 這題用`switch`可以讓程式碼比較好看,但`if-else`也沒問題~
* 0.5pt/group
----
### [a006. 一元二次方程式](https://zerojudge.tw/ShowProblem?problemid=a006)
#### 題示:要使用C++的開根號、次方功能,要引入math.h函式庫
```cpp=
pow(2, 10); // 2^10
sqrt(2); // 2^(1/2)
```
* 0.5pt/group
----
### 對了,在這邊容我偷偷自肥一下
* Instagram: [@t.c.k_319](https://www.instagram.com/t.c.k_319/)
* GitHub: [tseng91301](https://github.com/tseng91301)
<font size=3>咖哩不能拌,鑫鑫腸不能吃 -- 6小隊輔「阿瑋」 曰</font>
* ?pt(s)/group
----
### [b294. 經濟大恐荒](https://zerojudge.tw/ShowProblem?problemid=b294)
0.5pt/group
----
### [a010. 因數分解](https://zerojudge.tw/ShowProblem?problemid=a010)
0.5pt/group
----
### [a040. 阿姆斯壯數](https://zerojudge.tw/ShowProblem?problemid=a040)
#### 提示:雖然C++內建有pow這個開次方的function,但他似乎[不太精準](https://learn.microsoft.com/zh-tw/cpp/c-runtime-library/reference/pow-powf-powl?view=msvc-170)?
1pt/group
----
### [o077. 2. 電子畫布](https://zerojudge.tw/ShowProblem?problemid=o077)
#### 提示:
* 這一題寫完可以[去考APCS](https://apcs.csie.ntnu.edu.tw/)
* 雖然是陣列題,但也可以用vector(推薦)
3pts/group
----
### [a065. 提款卡密碼](https://zerojudge.tw/ShowProblem?problemid=a065)
0.5pt/group
----
### [a121. 質數又來囉](https://zerojudge.tw/ShowProblem?problemid=a121)
#### 提示:雖然題目上沒有說,但似乎要這樣寫
```cpp=
while(cin>>l>>h){
// Your code
}
```
1pt/group
----
### [a224. 明明愛明明](https://zerojudge.tw/ShowProblem?problemid=a224)
#### 提示:應該不會有人想要真的將字串排列組合吧
#### 有沒有什麼規律??
1pt/group
{"title":"C++程式教學","description":"image","contributors":"[{\"id\":\"49b092e5-357f-4529-be92-3ab18a9c88fb\",\"add\":72396,\"del\":37450}]"}