---
# System prepended metadata

title: C/C++基礎

---

# 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


---

 ![](https://hackmd.io/_uploads/HJSMQ-39h.png)

 

---


範例題：
> 依據下列表格中的等級表，使用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` 同理相同的東西