## 第五堂社課 --- ## 複習 ---- ## 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 碼對照表 ![image](https://hackmd.io/_uploads/Hy-oR53eWl.png) ---- ## 字元的運算 因為有了 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; } ```