# C/C++基礎
# 零---補充
## 一、基本運算子
1. 邏輯
運算符號: \+ \- \* \/ %(取餘數
* 優化c++
* `ios::sync_with_stdio(false), cin.tie(nullptr);`
* 前者解除同步;後者輸出終端改成全輸入後再一次輸出。
* 解除同步後小心處理輸入。
| 運算子 | 意義 |
| ------ | ------ |
| && | AND,且 |
| \|\| | OR,或 |
| ! | NOT,否 |
## 二、其他常用的運算子
1. 增遞/減遞運算
| 運算子 | 意義 |
|:------:|:----------:|
| ++ | 變數值加 1 |
| - - | 變數值減 1 |
* i++:先執行整個敘述後, 再將 i 的值加 1
* ++i:先將 i 的值加 1, 再執行整個敘述
* 特別的在for迴圈中,第三區塊是等所有程式執行完才進行。
因此i++跟 ++i沒有太多差別(無運算式) 差在是否複製舊副本與回傳值,於int影響甚小。
2.
| 運算子(?:) | 意義 |
| -------- | -------- |
| 條件判斷 ? 運算式 1 : 運算式 2||
```
if(判斷條件)
運算式 1;
else
運算式 2;
```
| 實例1 | 實例2 |
| ---------------------- | ----- |
| a = (x > 100) ? b : c; | abs = (a > 0) ? a : -a; |
```
if (a > 0)
abs = a;
else
abs = -a;
```
---
# 壹、格式化的輸入與輸出
```
#include <stdio.h>#將檔案<stdio.h>匯入進來
int main(){
printf("Hello world!");
return 0;
}
```
[https://web.fg.tp.edu.tw/~earth/vision/study/cprogram06/C_handout.pdf](https://)
## 一、標準輸出指令
`printf("格式字串", N1, N2,...);`
`scanf("格式字串",&N1,&N2,...);`
### Printf
```
int main(){
int a = 1 ;
printf("Hello \n%d", a);
return 0;
}
```
### Scanf
```
int main(){
int a,b;
scanf("%d%d",&a,&b);
printf("%d,%d",a,b);
}
```
* 注意!如果要讀取字元陣列時,`str`它被當作指向字串的指標使用,所以在 scanf 函式中,我們直接使用陣列名稱 str 來讀取字串。因為 str 已經是一個指向陣列的指標,使用 & 運算子會導致類型不匹配
> 字串為字元的陣列
* 各式字串如需要引入一個參數需加上%後面再加上資料型態,如%d、%s,此為修飾子
## 二、跳脫字元(Escape Sequence)
| \n 換行 | \\" 雙引號 | \\' 單引號 | |
| --------------------- | -------------------- | ---------- | ------- |
| \f 換頁 | \t 跳格 | \b 倒退 | |
| \x ASCII 碼 (16 進位) | \d ASCII 碼 (8 進位) | \\\ 反斜線 | \\/ 斜線 |
**例子 執行結果**
```
printf("\tThis line begins with tab.\n");
printf("It\'s a \"C Tutorial\".\n");
printf("This is backslash: \\.\n");
printf("\\101 is \101.\n");
printf("\\x41 is \x41.\n");
```
> This line begins with tab.
> It's a "C Tutorial".
> This is backslash: \.
> \101 is A.
> \x41 is A.
## 三、修飾子
可用於引入參數
| -:向左靠齊 | +:印出正負號 | %c:字元 |
| -------- | -------- | -------- |
| %s:字串 %d:十進位整數 | %f:浮點數 (小數點型式) | %l:長整數,加在 d、u…之前 |
| %u:無號十進位整數 | %e:浮點數 (指數 e 型式) | Nope |
---
# 貳、流程控制
## 一、if 指令
### 巨集
> define name 函式
```
#define MAX(a, b) (a>b ? a:b)
int main(){
int x, y;
printf("輸入N1:");
scanf("%d",&x);
printf("輸入N2:");
scanf("%d",&y);
printf("兩數最大值為:%d\n",MAX(x, y));
}
```
```
if (條件判斷式)
{
指令1;
...2;
...3;
.....
}
```
```
```
### 單一條件不用加{}
```
if (條件判斷)
指令1 ;
```
### ALL
```
int main(){
int a;
printf("輸入成績:");
scanf("%d",&a);
if (a>=60 && a<=100)
printf("及格\n");
else if (a>100)
printf("error!\n");
else
printf("不及格\n");
}
```
## 二、switch指令
### case、default
---

---
範例題:
> 依據下列表格中的等級表,使用switch完成分數的判斷,且在使用者輸入成績後顯示出等級
| 等第 | 分數 |
|:--------:|:--------:|
| A | 90~100 |
| B | 80~90 |
| C | 70~79 |
| D | 60~69 |
| E | 0~59 |
```
switch (運算式)
{
case 選擇值 1:
敘述主體 1;
break;
case 選擇值 2:
敘述主體 2;
break;
…
case 選擇值 n:
敘述主體 n;
break;
default:
敘述主體;
}
```
Answer:
```
int main(){
int a;
printf("輸入成績:");
scanf("%d",&a);
switch ( a/10 ){
case 10:
printf("A");
break;
case 9:
printf("A");
break;
case 8:
printf("B");
break;
case 7:
printf("C");
break;
case 6:
printf("D");
break;
case 0 ... 5: /* gcc擴充套件允許對比特定範圍 (0~5)*\
printf("E");
break;
}
}
```
### for 迴圈
```
for(變數起始1;條件;變數增減){
程式1;
for(變數起始2;條件;變數增減){
程式2;
}
}
```
### while
```
while(條件判斷){
程式區;
}
```
### do-while (後測試型迴圈)
> do裡的程式碼會被先執行一次
```
do{
:
程式區;
}
while(條件判斷);
```
### break、continue
* break跳脫迴圈不再執行下列程式
* continue持續執行迴圈並跳過下列程式
# 參、陣列、字串、矩陣、結構與檔案
## 一、陣列
### 一維
* 元素個數可未設定(自動)
* 超過個數長度時將自動設定為0
```
int arr[] = {
[0] = 3,
[1] = 4,
[2] = 5,
[3] = 6,
[4] = 7,
};
```
```
資料型態 陣列名稱 [長度];
```
或者
```
資料型態 陣列名稱 [大小]={初始值1,..2,..3,...};
```
### 二維
* 若初始值個數少於設定長度其餘將設定為0
* c/c++以列為主軸
| x | 行[0] | 行[1] | 行[2] |
|:-----:|:----:|:----:|:----:|
| 列[0] | [0][0] | [0][1] | [0][2] |
| 列[1] | [1][0] | [1][1] | [1][2] |
```
資料型態 陣列名稱 [列個數] [行個數];
```
```
資料型態 陣列名稱 [列個數] [行個數] ={{var1,var2,var3},{var4,var5,var6}};
```
## 二、結構
### struct
```
struct 結構名稱
{
資料型態 成員1;
資料型態 成員2;
......
}s1,s2;
```
* 定義結構變數
`struct name s1,s2;`
* 點運算子(用於存取)
`結構變數.成員名稱;`
* 成績&名子
```
int main(){
struct rank
{
char name[10];
int score;
} s1,s2 ;
strcpy(s1.name,"KATE");
s1.score = 900;
s2 = s1;
printf("%s%d",s2.name,s2.score);
return 0;
}
```
### 巢狀struct
```
struct 結構名稱1
{
資料型態 成員1;
資料型態 成員2;
......
};
struct 結構名稱2
{
......
struct 結構名稱1 變數名稱;
};
```
### 結構陣列
* 宣告
`struct 結構名稱 陣列名稱 [長度];`
* 存取
`陣列名稱 [索引值].陣列成員名稱`
```
struct 結構名稱
{
......
資料型態 陣列名稱 [個數];
};
```
`struct 結構名稱 陣列名稱 [個數];`
* 存取
`陣列名稱 [索引值].陣列成員名稱[索引值]`
* 下圖為建立5個元素的結構陣列
```
struct student
{
char name[10];
int score;
};
struct student class1[5];
```
# 容器 vector、map、queue、stack
## map vs unorder_map
### map
基礎建立於樹狀(紅黑樹)存取資料,遍歷時會自動排序好鍵(key),因此在查找與插入為O(log n)。
適合用在大於某個值得最小key等或是區間查詢。
* find() 找尋某個值,回傳該值。
* map->second 回傳鍵值。
* count() 回傳元素有幾個。
### unorder_map
基礎建立於雜湊&&沒有順序之差。因此在查找與插入為O(1),但需要消耗較多記憶體空間。
適合使用大量查詢判斷是否有該值存在、以及鍵值為何。
Key 數量大則很適用使用。
* 使用at()如果不存在,會直接out of range;
* 如果發生碰撞問題會退化O (n)
* 不允許重複元素
* reserve可避免rehash問題,影響執行效率。
### vector
動態的容器,每次push_back()、insert,都會重新分配記憶體。
* reserve()分配記憶體。
* assign(n,value),重構並指定數值。
`visited.assign(n+1, vector<bool>(m+1, false));`(二維靜態)
`vector<vector<int>> v(n);`(二維動態)
* push_back()放入尾端
* size()陣列元素的總數
* begin()指著第一個元素,end()指著最後元素的下一個
it++ 會保留舊副本; ++ it 則會直接下一個,在map等效率很重視++it
* empty()回傳是否為空,true or false
```cpp!
for(auto it = v.begin(); it!= v.end();++it){
cout<<*it<<' ';
}
```
# 各種有用的 (auto、auto&、string...)
## auto、auto&
auto用於複製一份資料。可iterate nums陣列。
```cpp!
nums[4]={0,1,2,3,4};
for(auto x:nums){
x=0;
}
//nums->0 1 2 3 4
```
auto& 直接修改值本身
```cpp!
nums[4]={0,1,2,3,4};
for(auto &x:nums){
x=0;
}
//nums->0 0 0 0 0
```
## string
`string +=`:添加字串
`string+`:字串相加
`at(i)`:存取索引值\[i\]的字元,存取越界會拋出一個例外
`find(char,start)`:字串搜尋,回傳字串首個位置。
`substr(n,m)`:取得子字串,從n開始往印出m個字母。
`empty()`:回傳是否為空,空則回傳true
`size()`:回傳目前長度
`length()`:回傳目前長度
`append()`:添加字串
`size_t`:容器長度的一種類型
`string::npos`:表示容器類型的最大值(常數)與size_t最大值相等,通常用於判斷不存在的位置。
```cpp!
for (auto &c : str) {
cout << c << '\n';
}
}
```
取得str的地址開始疊代。
* 如果使用運算式相加會複製一份,可以使用append or += 提升效率
### stoi
將字串轉為數字
`stoi(string)`
### getline
讀取一行字串(吃空白)
`getline(cin,string)`
stringstream類別
`#include <sstream>`
可用於將字不斷拆分
```
stringstream ss(s)
while(getline(ss,string,'區分的字元'))
```
## rotate
將陣列元素往後位移n個,中間begin使前方往後n個元素;反之end使後方往前n個元素。
`rotate(v.begin(),v.begin/end(),n)` ;`#inlcude<algorithm>`
## sort vs qsort函式
結論是c++ stl sort一定比c的qsort快
以下為使用方法
### sort
一般陣列 : sort(a,b) 指從a位置排到b位置 ,大到小則在sort(a,b,cmp) cmp中加入 `greater<int>()`
vector : sort(v.begin(),v.begin()+n) 也為相同道理,只是stl容器需要使用begin()+n來指定起終點。大到小同理`greater<int>()` 或是善用反向迭代 `sort(v.rbegin(),v.rend())`
```cpp!
#include <iostream>
#include <algorithm>
#include<vector>
using namespace std;
int main(void) {
int v[6]={2,7,3,1,4,5};
vector<int> v2={2,7,3,1,4,5};
sort(v,v+6); sort(v2.begin(),v2.end());
for(int i=0;i<6;i++) {
cout<<v[i]<<" ";
}
cout<<"\n";
for(int i=0;i<6;i++) {
cout<<v2[i]<<" ";
}
cout<<"\n";
}
```
struct : 多加一個比較函式,看要針對結構哪個排序。 a.score < b.score 回傳true 表示每個a<b,由小到大排,反之大到小。
```cpp!
#include <iostream>
#include <algorithm>
using namespace std;
struct node {
string name;
int score;
}s[3];
bool cmp(node a,node b) {
return a.score < b.score;
}
int main(void) {
s[0].name="Ken";s[0].score=70;
s[1].name="Yellow";s[1].score=50;
s[2].name="Green";s[2].score=60;
for(auto st: s) {
cout<<st.name<<" score:"<<st.score<<endl;
}
sort(s,s+3,cmp);
for(auto st: s) {
cout<<st.name<<" score:"<<st.score<<endl;
}
}
```
### qsort
一般陣列: qsort(陣列,數量,記憶體形式,比較函式)。 指向int指向a,a-b為小到大, b-a為大到小。
```cpp!
#include <iostream>
using namespace std;
int cmp(const void* a,const void* b) {
return (*(int *)a) - (*(int *)b);
}
int main(void) {
int v[5]={3,4,2,1,5};
for(auto st: v) {
cout<<st<<" ";
}
cout<<endl;
qsort(v,5,sizeof(int),cmp);
for(auto st: v) {
cout<<st<<" ";
}
}
```
struct : cmp中由int位置改成 struct node(結構名稱)。意思為struct node 指向 a 指向score, a-b為小到大, b-a為大到小。
```cpp!
#include <iostream>
#include <algorithm>
#include<vector>
using namespace std;
struct node {
string name;
int score;
}s[3];
int cmp(const void* a,const void* b) {
return ((struct node *)a)->score - ((struct node *)b)->score;
}
int main(void) {
s[0].name="Ken";s[0].score=70;
s[1].name="Yellow";s[1].score=50;
s[2].name="Green";s[2].score=60;
for(auto st: s) {
cout<<st.name<<" score:"<<st.score<<endl;
}
qsort(s,3,sizeof(struct node),cmp);
for(auto st: s) {
cout<<st.name<<" score:"<<st.score<<endl;
}
}
```
# 那些已經被complier優化掉的東西
1. `i++` vs `++i` 在組合語言中已經被調整為相同的東西, 速度差異微乎其微乃至無影響。
2. `n*2^x` vs `n<<x` 組合語言為轉為相同的東西,電腦是二進制當*2^n會與位元位移相同。
3. `a>b?a:b` vs `if(a>b) return a else b` 同理相同的東西