## 第五堂社課
---
## 複習
----
## C 風格陣列
```cpp=
#include<iostream>
using namespace std;
int main(){
int a[3]={1,2,0};// 陣列的宣告與定義
a[2]=3;// 陣列的改變
for(int i=0;i<3;i++)cout<<a[i]<<endl;//陣列的引用
}
```
----
## C++ `std::vector`
```cpp=
#include<iostream>
#include<vector>
using namespace std;
int main(){
// std::vector 的宣告與定義
vector<int>a(3,0);
vector<int>b({1,0,-1});
// std::vector 的改變
b[1]=1;
b.at(2)=2;
// std::vector 的引用
cout<<a[0];
cout<<b.at(1);
}
```
----
## C++ ```std::vector``` 的基礎操作
`push_back()` : 在陣列的最後新增元素
`insert()` : 在指定位置插入元素
`pop_back()` : 刪除陣列最後方的元素
`erase()` : 刪除指定位置或指定記憶體區間的元素
`clear()` : 清空 `std::vector` 陣列
`size()` : 讀取陣列長度
`resize()` : 調整陣列長度
`empty()` : 讀取陣列是否為空
----
## 範例
```cpp=
#include<iostream>
#include<vector>
using namespace std;
int main(){
vector<int>a;
for(int i=0;i<10;i++)a.push_back(i);// 0 1 2 3 4 5 6 7 8 9
a.insert(a.begin()+4,-1);// 0 1 2 3 -1 4 5 6 7 8 9
a.pop_back();// 0 1 2 3 -1 4 5 6 7 8
a.erase(a.begin()+4);// 0 1 2 3 4 5 6 7 8
a.erase(a.end()-2,a.end());// 0 1 2 3 4 5 6
cout<<a.size()<<endl;// 7
cout<<a.empty()<<endl;// 0
a.resize(a.size()+2);// 0 1 2 3 4 5 6
cout<<a.size()<<endl;// 9
cout<<a.empty()<<endl;// 0
a.clear();//
cout<<a.size()<<endl;// 0
cout<<a.empty()<<endl;// 0
}
```
---
## ```char``` 字元
----
## 字元是什麼
```char``` 是 C++ 中最基本的字元型別,儲存單一字元
而這些字元的儲存會使用 ASCII 碼
----
## ASCII 碼
ASCII 碼是「美國資訊交換標準代碼」,是一種電腦編碼系統,用來將英文字母、數字和符號轉換成電腦能讀取的二進位代碼,以便進行資訊交換和傳輸。
----
## ASCII 碼對照表

----
## 字元的運算
因為有了 ASCII 碼,我們可以對字元做簡單的運算
```cpp=
#include<iostream>
using namespace std;
int main(){
char a='a',b='b',c='1',d='d',e='e',f='f';
int C=c-'0';
cout<<a-b<<endl;//-1
cout<<C<<endl;//1
cout<<int(d)<<endl;//100
cout<<(e>f)<<endl;//0
}
```
----
## `cctype` 函式
在對字元進行操作時,有一些比較方便的函式在 `C++ <cctype>` 內:
```cpp=
#include<iostream>
#include<cctype>
using namespace std;
int main(){
char a='a';
cout<<isalpha(a)<<endl;//是否為字母
cout<<isupper(a)<<endl;//是否為大寫字母
cout<<islower(a)<<endl;//是否為小寫字母
cout<<isdigit(a)<<endl;//是否為數字
cout<<isalnum(a)<<endl;//是否為數字或字母
cout<<isspace(a)<<endl;//是否為空格 ' '
cout<<isblank(a)<<endl;//是否為空格 ' ' 或 '\t'
cout<<toupper(a)<<endl;//將 a 從小寫轉換成大寫的 ASCII
cout<<tolower(a)<<endl;//將 a 從大寫轉換成小寫的 ASCII
}
```
---
## C++ ```std::string```
----
## 為何要用 ```std::string```
```std::string``` 是 C++ 標準函式庫 ```<string>``` 中資料結構。與 ```char []``` 不一樣的地方是,他可以自動調整大小,不需要另外去做動態分配的部分,十分的方便,一定要學起來。
----
## 使用 ```char []```
```cpp=
#include<iostream>
using namespace std;
int main(){
char a[10];//必須事先定義陣列長度
for(int i=0;i<10;i++)cin>>a[i];
cin>>a[10];//(X)
}
```
當我們需要的陣列長度大於一開始宣告的 ```char []``` 長度時,就沒辦法輸入了,如果真的硬要使用的話就會需要用到動態分配記憶體的概念
----
## 使用 `std::string`
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a;
cin>>a;
a.resize(a.size()+1);
cin>>a[a.size()-1];
}
```
當我們想要增長 ```std::string``` 時,只需要用簡單的修飾器(後面會教)就可以完成;
----
## `std::string` 的宣告與定義
```cpp=
std::string 字串名稱 = "字串值";
std::string 字串名稱("字串值");
```
字串值:可以是任意數字、字母和符號
**注意** : 單一字元使用單引號 ```' '```,字串則使用 ```" "```
----
## 範例
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a="Xiaochengyi";
string b="kaikai"
}
```
----
## `std::string` 的引用
我們可以使用 ```[]operator``` 和 ```at()``` 引用 ```std::string``` 的資料,也可以直接寫字串名稱引用整個字串
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a="Xiaochengyi";
//字串的索引(項數)是從 0 開始的
cout<<a[0]<<endl;//X
cout<<a.at(1)<<endl;//i
cout<<a<<endl;//Xiaochengyi
}
```
---
## C++ ```std::string``` 基礎操作
----
## 字串的相加 `+`
當我們想要將兩個字串串接在一起時,可以使用 `+`
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a="xiaoxiao",b="Xiaochengyi";
cout<<a+b<<endl;//xiaoxiaoXiaochengyi
}
```
----
## 字串的相加 `append()`
除了使用 `+` 將兩個字串串接在一起,也可以使用 `append()`
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a="xiaoxiao",b="Xiaochengyi";
a.append(b);
cout<<a<<endl;//xiaoxiaoXiaochengyi
}
```
----
## 整行輸入 ```getline()```
因為正常來說 ```std::string``` 的輸入在遇到空格後就會結束,所以我們可以使用 ```getline(輸入串流,字串名稱)``` 輸入整行的包含空格的字串
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a;
getline(cin,a);//輸入整行包含空格的字串
}
```
----
## 新增元素 ```push_back()```
我們可以使用 ``` push_back()```在字串的最後新增元素
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a;
for(int i=0;i<10;i++)a.push_back(i+65);
cout<<a<<endl;//ABCDEFGHIJ
}
```
----
## 插入元素 `insert()`
我們可以使用 `insert(iterator,value)` 在指定位置插入元素
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a="Xiaochengyi";
a.insert(4,"xiao");//Xiaocxiaohengyi
}
```
----
## 刪除元素 `pop_back()`
我們可以使用 `pop_back()` 刪除字串最後方的元素
```cpp=
#include<iostream>
#include<vector>
using namespace std;
int main(){
string a="Xiaochengyi";//Xiaochengyi
a.pop_back();//Xiaochengy
a.pop_back();//Xiaocheng
}
```
----
## 尋找子字串 `find()`
當我們需要在字串中尋找對應的子字串,則可以使用 `find()` 尋找該子字串第一個被發現的位置
```cpp=
#include<iostream>
using namespace std;
int main(){
string a="Xiaochengyi";
cout<<a.find("Xiao")<<endl;// 0
cout<<a.find("xiao")<<endl;// 亂碼(找不到)
}
```
----
## 擷取子字串 `substr()`
當我們需要把某個字串的其中一部份擷取下來時,就可以使用 `substr(位置,長度)`
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a="Xiaochengyi";
cout<<a.substr(4,7)<<endl;//chengyi
}
```
----
## 刪除元素 `clear()`
我們可以使用 `clear()`清空字串
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a="Xiaochengyi";//0 1 2
a.clear();//
}
```
----
## 讀取字串長度
## ```size()``` 和 ```length()```
我們可以使用 ```size()``` 和 ```length()``` 讀取字串長度
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a="ABC";
cout<<a.size();//3
cout<<a.length();//3
}
```
----
## 調整字串長度 ```resize()```
我們可以使用 ```resize()``` 調整字串長度
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a="Xiaochengyi";
cout<<a.size();//11
a.resize(a.size()+1);
cout<<a.size();//12
}
```
----
## 讀取字串是否為空 ```empty()```
我們可以使用 ```empty()``` 讀取陣列是否為空
```cpp=
#include<iostream>
#include<string>
using namespace std;
int main(){
string a="Xiaochengyi";
cout<<a.empty();//0
a.clear();
cout<<a.empty();//1
}
```
---
## 變數的域
----
## 什麼是變數的域
在目前學習的變數中,基本上都處於主程式 `main` 中,但是實際上,變數的作用是有範圍的,主要是以大括號 `{}` 為分界
----
## 範例
```cpp=
#include<iostream>
using namespace std;
int a=0;// 全域變數
int main(){
cout<<a;// 0
int a=1;// 區域變數
{
cout<<a;// 1
int a=2;// 區域變數
{
cout<<a;// 2
int a=3;// 區域變數
cout<<a;// 3
}
cout<<a;// 2
}
cout<<a;// 1
}
```
---
## 函式
----
## 為甚麼要用函式 ?
在我們寫程式的過程中,難免會遇到很多需要使用同樣的架構,卻是使用不同變數的情況。雖然說有些情況可以直接用迴圈解決,但是在不可抗力且為了追求程式的可閱讀性之情況下,使用函式是一個不錯的選擇
----
## 不使用函式
```cpp=
/*This is a C++ code of 1A2B edited by Gemini 3 Pro*/
#include<iostream>
#include<cstdlib>
using namespace std;
int main(){
int Ans[4],Giv[4],A{},B{},Times{};
char choice;
bool isDuplicate;
cout<<"Write in 4 different numbers between 0~9\n";
while(true){
cout<<"Continue?(y/n)\n";
cin>>choice;
if(choice=='y'){
system("cls");
break;
}
else if(choice=='n'){
system("cls");
cout<<"GAME OVER\n";
exit(0);
}
else cout<<"We're not sure what you meant\n";
}
for(int i=0;i<4;i++){
while(true){
isDuplicate=false;
cin>>Ans[i];
for(int j=0;j<i;j++) if(Ans[j]==Ans[i]||Ans[i]<0||Ans[i]>9){
isDuplicate=true;
break;
}
if(isDuplicate){
cout<<"This number is unacceptable\nPlease think of another suitable number\n";
while(true){
cout<<"Continue?(y/n)\n";
cin>>choice;
if(choice=='y'){
system("cls");
break;
}
else if(choice=='n'){
system("cls");
cout<<"GAME OVER\n";
exit(0);
}
else cout<<"We're not sure what you meant\n";
}
}
else break;
}
}
cout<<"Are you ready for the numbers?\n";
while(true){
cout<<"Continue?(y/n)\n";
cin>>choice;
if(choice=='y'){
system("cls");
break;
}
else if(choice=='n'){
system("cls");
cout<<"GAME OVER\n";
exit(0);
}
else cout<<"We're not sure what you meant\n";
}
cout<<"Please guess 4 different numbers between 0~9\n\"A\" means how many correct ones are at the correct places\n\"B\" means how many correct ones are at the wrong places\n";
while(true){
cout<<"Continue?(y/n)\n";
cin>>choice;
if(choice=='y'){
system("cls");
break;
}
else if(choice=='n'){
system("cls");
cout<<"GAME OVER\n";
exit(0);
}
else cout<<"We're not sure what you meant\n";
}
cout<<"Please write in the four different numbers you guess\n";
while(true){
Times++;
for(int i=0;i<4;i++){
while(true){
isDuplicate=false;
cin>>Giv[i];
for(int j=0;j<i;j++) if(Giv[j]==Giv[i]||Giv[i]<0||Giv[i]>9){
isDuplicate=true;
break;
}
if(isDuplicate){
cout<<"This number is unacceptable\nPlease think of another suitable number\n";
while(true){
cout<<"Continue?(y/n)\n";
cin>>choice;
if(choice=='y'){
system("cls");
break;
}
else if(choice=='n'){
system("cls");
cout<<"GAME OVER\n";
exit(0);
}
else cout<<"We're not sure what you meant\n";
}
}
else break;
}
}
A=0;
B=0;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(Ans[i]==Giv[j]){
if(i==j) A++;
else B++;
break;
}
}
}
cout<<"\t|\t"<<A<<" A "<<B<<" B\n";
if(A==4) break;
}
cout<<"You got the correct numbers!\nYou totally use "<<Times<<" times!";
return 0;
}
```
----
## 使用函式
```cpp=
/*This is a C++ code of 1A2B written by Darrenw1004*/
#include<iostream>
#include<cstdlib>
using namespace std;
void Continuer();
void Input(int Func[],bool UsingJudge);
void Judge(int Ans[],int Giv[],int &A,int &B);
int main(){
int Ans[4],Giv[4];
int A{},B{},Times{};
cout<<"Write in 4 different numbers between 0~9\n";
Continuer();
Input(Ans,1);
cout<<"Are you ready for the numbers?\n";
Continuer();
cout<<"Please guess 4 different numbers between 0~9\n\"A\" means how many correct ones are at the correct places\n\"B\" means how many correct ones are at the wrong places\n";
Continuer();
cout<<"Please write in the four different numbers you guess\n";
while(true){
Times++;
Input(Giv,1);
Judge(Ans,Giv,A,B);
cout<<"\t|\t"<<A<<" A "<<B<<" B\n";
if(A==4){
break;
}
}
cout<<"You got the correct numbers!\nYou totally use "<<Times<<" times!";
return 0;
}
void Continuer(){
char choice={};
cout<<"Continue?(y/n)\n";
cin>>choice;
if(choice=='y'){
system("cls");
}
else if(choice=='n'){
system("cls");
cout<<"GAME OVER\n";
exit(0);
}
else{
cout<<"We're not sure what you meant\n";
Continuer();
}
}
void Input(int Func[],bool UsingJudge){
for(int i=0;i<4;i++){
while(true){
bool isDuplicate{};
cin>>Func[i];
if(UsingJudge){
for(int j=0;j<i;j++){
if(Func[j]==Func[i]||Func[i]<0||Func[i]>9){
isDuplicate = true;
break;
}
}
if(isDuplicate){
cout<<"This number is unacceptable\nPlease think of another suitable number\n";
Continuer();
}
else{
break;
}
}
else{
break;
}
}
}
}
void Judge(int Ans[],int Giv[],int &A,int &B){
A=0;
B=0;
for(int i=0;i<4;i++){
for(int j=0;j<4;j++){
if(Ans[i]==Giv[j]){
if(i==j){
A++;
}
else{
B++;
}
break;
}
}
}
}
```
----
## 函式的宣告
```cpp=
資料型別 函式名稱(參數);
```
參數 : 函式內部的區域變數,各個參數之間以 `,` 隔開
----
## 函式的定義
```cpp=
資料型別 函式名稱(參數){
定義
}
```
----
## 函式的引用
```cpp=
函式名稱(引數);
```
引數 : 傳入函式的實際數值或變數,各個引數之間以 `,` 隔開
----
## 函式規則
1. 函式的宣告必須先於函式的引用
2. 函式的定義可以與宣告拆開,並且不一定需要先於函式的引用
3. 函式不一定會有參數
4. 函式不一定會有回傳值
5. 函式的引用不一定會有引數
----
## 函式架構
```cpp=
資料型別 函式名稱(參數){
陳述句;
return 回傳值;
}
```
回傳值 : 回傳值須與函式的資料型別相同。若無,則回傳值設為 `0` 表函式結束或直接省略
----
## 範例
```cpp=
#include<iostream>
using namespace std;
// 函式的宣告
void myCout(int a);// 函式的定義先於函式的引用
int main(){
int x=1;
// 函式的引用
myCout(x);
}
// 函式的定義
void myCout(int a){
cout<<a<<endl;
}
```
----
## 函式的參數
函式的參數主要是定義只在該函式中出現的區域變數。我們可以在引用時,使用引數將值傳入函式參數中,以達到對函式參數賦值的效果
----
## 範例
```cpp=
#include<iostream>
using namespace std;
// 函式的宣告
int myPlus(int a,int b);// 函式的定義先於函式的引用
int main(){
int x=1,y=2;
// 函式的引用: 因為函式是 int 型態的,所以我們把它當作一個 int 型態的變數使用,故可以輸出
cout<<myPlus(x,y)<<endl;
}
// 函式的定義
int myPlus(int a,int b){
return a+b;
}
```
---
## 遞迴
----
## 什麼是遞迴
遞迴就是函式中一直套函式,然後在達到某一個條件後停止開始回傳值。這與迴圈有部分相似,但是也有它不同之處。
----
## 使用遞迴
```cpp=
#include<iostream>
using namespace std;
int Fib(int n){
if(n==0)return 0;
if(n==1)return 1;
return Fib(n-1)+Fib(n-2);
}
int main(){
int n;
cin>>n;
cout<<Fib(n)<<endl;
}
```
----
## 使用迴圈
```cpp=
#include<iostream>
using namespace std;
int main(){
int a=0,b=1,c,n;
cin>>n;
for(int i=0;i<n;i++){
c=b;
b+=a;
a=c;
}
cout<<b<<endl;
}
```