owned this note
owned this note
Published
Linked with GitHub
# C++ 語法筆記
## 目錄
> :::spoiler 清單
> [TOC]
> :::
---
## cin
### cin.get()
接收單字元,會接受空格、\n,用if判斷停止點
用法:
1.
```cpp
char a;
cin.get(a);
```
2.
```cpp
char a[10];
cin.get(a, 10);
※實際上會接收0~8字元
a[9] == '\0' //自動添加
```
3.
```cpp
僅忽略掉1個輸入字元
cin.get();
```
### cin.getline()
接收字串,用char[]接收
同cin.get(),但可新增遇某字元自動為止功能
cin.getline(接收對象, 接收個數, 遇某字元則停)
接收個數一樣為n-1,最後一位會被寫入'\0'
最後字元若未填預設為'\0'
e.g.
```cpp
char a[5] = {'z', 'z', 'z', 'z', 'z'};
cin.getline(a, 4, '3');
for (int i = 0; i < 5; i++){
cout << a[i] << ',';
}
//1,2,,z,z,
```
若先遇到某字元,則前面照常寫入,該字元改為'\0'寫入位置
反之,個數先滿則停,且第n個同樣被寫成'\0'
### getline()
來源流(cin、stream),用string接收,但可以接收換行(需要配合截斷字元)
將cin用getline寫進string
```cpp
string str;
getline(cin, str, '截斷字元');//str接收後不包含被截斷字
//若無給予截斷字元參數,預設為直到\n停止,反之截斷前所有\n都會被吃進去
```
若輸入字串在getline();被截斷
截斷後的值下一位開始依然存在stream
若再使用getline後續會被取出
e.g.
```cpp
string str;
getline(cin, str, 'A');
cout << str << endl;
getline(cin, str, 'B');
cout << str << endl;
getline(cin, str);
cout << str << endl;
```
只輸入:"This_is_an_Apple,_not_a_Banana."
產生三行輸出:
This_is_an_
pple,_not_a_
anana.
接收不定量的數值,中間會用","隔開
```cpp
vector <int> numbers;
string in_str;
while (getline(cin, in_str) {//相當於抓cin換行前的所有內容
if (in_str == "\0") {//如果enter輸入值是空的
break; //推入陣列直接結束程式,防報錯
} //測資有限制可不加
}
stringstream str_stream(in_str);//把in_str寫入過渡用sstream
string text;
while (getline(str_stream, text, ',')) {
numbers.pushback(stoi(item));
} //因為截斷字元不保留,剩餘內容保留特性
//以','為切點被切割的數字都會被推進vec,最後為'\n'照樣會截斷捨去
```
## cout
### 控制整體輸出小數位
控制小數位數,並自動四捨五入
```cpp
#include <iomanip>
//輸出到小數點後第n位
cout << fixed << setprecision(3) << 3.14159;
//3.141
```
使用後會影響整個檔案的cout
取消後續cout影響
```cpp
cout << defaultfloat;
```
將對fixed的影響清除(小數),但setprecision(位數)狀態依然保持
僅能再使用setprecision() 重新覆蓋定義
以上對int不影響
## 三大處理(int, string, char)
### 轉換
- 字元轉int
```cpp
char a;
a - '0' = //實際數值
```
- string導到現有char[]
可取片段string來源,可接上或覆蓋部分char片段
```cpp
string str = "ABChello";
char p[10] = {};
str.copy(p + 2, 5, 3); //str複製到p,複製str[3]開始5個字元
//(到str[7]),到p[2]開始(略過p[0],p[1])
```
- int跟string互轉(stream)
```cpp
#include <sstream>
//s1為過渡媒介
stringstream s1;
s1.str("");
s1.clear();
1. int轉string
int num;
string op;
s1 << num;
s1 >> op
2. string轉int
int op_num;
string ip_str;
s1 << ip_str;
s1 >> op_num;
```
- int跟string互轉(to_string, stoi)
a可以是int、double等float...
數值轉字串
```cpp
to_string(a);
```
將數字的字串轉成int
```cpp
a = "1024";
int num = stoi(a);
```
注意stoi處理時會自動把"前面"的空格省略,並往後取到非數值前
e.g.
輸入:" 23a"
->stoi取得值 : 23
輸入 : " 90 12a"
->stoi取得值 : 90
//注意,第一個'-'會當成負號讀入,往後的負號會忽略
輸入 : " -23-4a"
->stoi取得值 : -23
### int主體
- int拆分
字串拆分重組數字
```cpp
num = num * 10 + (a - '0');
```
e.g.
```cpp
num = 120;
1 * 10 + (a – '0') = 12 //*10左移效果+個位數 達成拆分合體
```
### string主體
- 子函數大全
- append() - 接上字串
1. 把str1內容接到str2後
> str1.append(str2);
2. 接上片段
>str2.append(str1, 開始位, [數量])
3. 接上指定字串//限已知字串
>str2.append("Text", [從頭開始數量])
>
亦可用3參數,注意2參數判定不同
4. 接上指定數量字元
>str2.append(數量, '字元')
- assign() - 賦予字串在str.end()
1. 複製
> str2.assign(str1);
使得str2 == str1
2. 複製片段
> str2.assign(str1, 開始位, [複製數量])
3. 賦予指定字串//限已知字串
> str2.assign("Text", [從頭開始數量])
亦可用3參數,注意2參數判定不同
4. 賦予指定數量字元
> str2.assign(數量, '字元')
- replace() - 取代子字串
1. ordinary
將1~2參數範圍取代成str2
> str1.replace(str1開始位, 選取數量, str2);
2. 找出指定位置後取代
> str1.replace(str1.find("text"), 選取數量, 字串);
find結果的begin~選取量,取代為指定字串
- insert() - 插入字串
>str1.insert(開始位, 字串)
>
- erase() - 清除部分內容
> str1.erase(開始位, 清除量)
- size() - 字串目前大小
> str1.size()
- find() - 尋找字串
善用未找到時 `== string::npos`
1. 以是否存在取bool
```cpp
if (str1.find(str2) != string::npos) {//在str1有找到str2
//...
}
else {
//...
}
```
2. 找出指定字元或串在第幾個位置
注意回傳值是查詢值第一位對應
```cpp
int pos;
pos = str1.find(str2);
```
3. 從頭開始找出字串中任何一個字元就回傳位置
```cpp
int pos;
pos = str1.find_first_of(str2);
```
取反:從頭找任何一個不包含的字元位置
```cpp
pos = str1.find_first_not_of(str2);
```
4. 從尾開始找出字串中任何一個字元就回傳位置
```cpp
pos = str1.find_last_of(str2);
```
取反:從尾找任何一個不包含的字元位置
```cpp
pos = str1.find_last_not_of(str2);
```
- swap() - 普通交換兩字串
```cpp
str1.swap(str2);//兩者內容互換
```
- substr() - 取得字串中部分內容
```cpp
string temp;
temp = str1.substr(開始位, 數量)
//數量寫超過下標時,只取到下標為止不報錯
```
- empty() - 偵測是否為空回傳bool
```cpp
bool isEmpty;
isEmpty = str1.empty();
```
- erase-remove - 清除字串中所有特定字元
```cpp
str.erase(remove(str.begin(), str.end(), 'T'), str.end());
```
- char主體
- cctype - 字元判斷與轉換
```cpp
#include <cctype>
```
- 判斷
以bool存取
- isupper():判斷字元是否為大寫字母
- islower():判斷字元是否為小寫字母
- isalpha():判斷字元是否為字母
- isdigit():判斷字元是否為純數字
- isalnum():判斷字元是否為數字或大小字母轉換
- 轉換
- toupper():字元轉大寫
- tolower():字元轉小寫
<br>
> char[]以index計數
注意寫int[]、char[]時的index計數器關係
最後index數值會 = size
<br>
## 陣列
### 將一維陣列清空/寫值
```cpp
int arr[];
fill(arr, arr + size, 0);
```
### 清除二維陣列
```cpp
int num[100][100];
memset(num, 0, sizeof(num));
//限定為0,否則只能用雙重for 或 for + fill
```
### vector主體
```cpp
#include<vector>
```
- 預宣告空間初始化
```cpp
vector<int> num(10, 0); //初始化產生num[0~9],數值為0
```
- 標準遍歷式
```cpp
vector<int> num;
for (auto it = num.begin(); it != num.end(); it++) {
cout << *it << endl;
}
```
- 取遍歷值
```cpp
vector<int> num;
for (auto i : num) {
cout << i << endl;//i為遍歷num的值
}
```
- Sort
```cpp
vector<int> v;
```
- 升序
```cpp
sort(v.begin(), v.end());
```
- 降序(利用r反向)
```cpp
sort(v.rbegin(), v.rend());
```
- 翻轉應用
```cpp
vector<int> v;
reverse(v.begin(), v.end());
```
> 一維陣列 a1, n 互換 a1 + 1, n - 1互換...
二維陣列 只換i(直行)不換j(橫列)
- 查值系列 & iter轉idx
```cpp
vector<int> v;
auto iter = find(v.begin(), v.end(), 10);
if (iter != v.end()) {
int idx = iter - v.begin();
cout << idx;
}
else {
cout << "v沒有10";
}
```
- 兩組vector<int>對應位置合併相加
```c++
vector<int> v1, v2;
int max_size = max(v1.size(), v2.size());
v1.resize(max_size);
v2.resize(max_size);
vector<int> result(max_size);
transform(v1.begin(), v1.end(), v2.begin(), result.begin(), plus<int>());
//result每位將被寫入對應的位數相加
```
- 拼接兩vector
```cpp
vector<int> v1, v2;//其他型別無異
v1.insert(v1.end(), v2.begin(), v2.end());
```
- 排序後刪除重複值
```cpp
vector<int> v = { 1, 2, 4, 3, 5, 2 };
sort(v.begin(), v.end());//先排序
//unique(iter.begin(), iter.end()) 把相鄰重複值扔到back
//erase 移除指定範圍(iter.begin(), iter.end())
v.erase(unique(v.begin(), v.end()), v.end());
//因為unique會回傳排好後+1的位置,等於要移除範圍的begin
```
- 二維串列(vector)使用
```cpp
vector<int> a[10];
```
a產生10個 i (0~9),利用pushback增加 j
利用a[i][j]格式取值
```cpp
a[4].pushback(1); //a[4][0] == 1
a[4].pushback(2); //a[4][1] == 2
a[3].pushback(3); //a[3][0] == 3
```
### queue
一邊檢索,一邊增加預備檢索序列
```cpp
#include <queue>
queue<int> q;
```
- q.push():推入尾值
- q.pop():移除首值
- q.back():取得尾值
- q.front():取得首值
- q.size():回傳q目前長度
- q.empty():回傳q是否為空
### set
```cpp
#include <set>
```
set會自動去除重複元素以及排序
```cpp
set<int> a_set{ 1, 3, 2 };//成為1 2 3
set<int, greater<int> > a_set{ 1,3,2 };//降序(3 2 1)
```
- a_set.insert():插入元素
- a_set.erase():清除某個元素
- a_set.clear():清空a_set
- a_set.empty():判斷a_set是否為空
- a_set.size():取得a_set目前大小
移動iter指向
```cpp
auto it = a_set.lower_bound(1);//it指到第一個 >= 1的位置
auto it = a_set.upper_bound(1);//it指到第一個 > 1的位置
```
清除指定元素,並記錄是否有進行清除動作
```cpp
bool is_erased = a_set.erase(2);
if (is_erased) {
cout << "成功清除 2" << endl;
}
else {
cout << "不存在 2" << endl;
}
```
尋找某值是否存在
```cpp
if (a_set.find(1) == a_set.end()) {
cout << "不存在1" << endl;
}
else {
cout << "找到1" << endl;
}
```
### deque
頭尾都能增加元素的雙向佇列
在中間插入元素的效率較高
但占用記憶體空間較vector多
隨機插入效率高(insert、erase)
隨機訪問效率低(find、dq[index])
隨機訪問頻率較高選擇vector
頭尾兩端都需要添加元素選擇deque
```cpp
#include <deque>
deque<int> dq;
deque<int>::iterator it;
```
dq.push_back():推入尾值
dq.pop_back():移除尾值
dq.push_front():推入首值
dq.pop_front():移除首值
dq.insert(iter, 1):在iter的位置插入1
dq.erase(iter):
dq.clear():
dq.empty():
dq.size():
### map
寫入key跟value後,會依照初始宣告自動排列
map中key不會重複,呼叫時即以key當作陣列的index使用
架構: //key跟value分別填入資料型別
1. 升序排列
map<key, value> a_map;
2. 降序排列
map<key, value, greater<key> > a_map; //注意隔開> >
map<char, int, greater<char> > a_map;
//insert不要在比賽使用,判斷型別複雜
a_map['a'] = 93;
a_map['b'] = 24;
a_map['c'] = 10;
cout << a_map['a'] << endl;//輸出93
cout << a_map['T'] << endl;
//注意! T不存在,執行後會輸出0,
//且map紀錄一筆'T', 0,在遍歷時會被掃到
a_map.erase('a');
for (auto s: a_map) {
//first取出key,second取出value
cout << s.first << ", " << s.second << endl;
//分別輸出b, c, T
}
a_map.clear();
a_map.empty();
a_map.size();
map實際應用:
處理來源非連續數字,且最終不需輸出原本名稱(反之要用struct)
int getID(string p) {//將物件名稱寫入item取得ID
if (node.find(p) == node.end()) {//沒找到key = p的item
node[p] = node.size();
}
return node[p];
}
### 求極值
#include <algorithm>
注意要用 *min / max_element
求max
1.vector
int maxValue = *max_element(v.begin(), v.end());
2.一般陣列
int maxValue = *max_element(num, num + 5);//(size = 5)
求min
1.vector
int minValue = *min_element(v.begin(), v.end());
2.一般陣列
int minValue = *min_element(num, num + 5);//(size = 5)
### 求極值位置
注意求位置用一般max / min_element
#include<algorithm>
求max
1.vector
int maxPos = max_element(v.begin(), v.end()) - v.begin();
2.一般陣列
int maxPos = max_element(num, num + 5) - num;//(size = 5)
求min
1.vector
int minPos = min_element(v.begin(), v.end()) - v.begin();
2.一般陣列
int minPos = min_element(num, num + 5) - num;//(size = 5)
### 已知寬度二維陣列讓外部函式修改
//用於需要在外部改值,不傳回。在void的變更會直接改變main的num值
void A(int **num, int i_size, int j_size) {
//code 正常用Num[i][j]存取相同位置
}
int main() {
int num[][5];
int *p[3] = { num[0], num[1], num[2] };//複製一份傳遞用
//此處*p[3]決定i長度 //取i,注意順序有差
int i_size = 3;
A(p, i_size, 5);
}
### 找最大連續子數列
int GetMax(vector<int> num, int size) {
int now = 0, max_n;
max_n = num[0];
for (int i = 0; i < size; i++) {
now += num[i];
if (now > max_n) {
max_n = now;
}
else if (now < 0) {
now = 0;
}
}
return max_n;
}//建議用於結果會 >= 0,全負數依然會報長度0,需依題意調整
## Keyword
### const
> 常數,賦予不可變更的特性
- const 變數
```c++
const int n = 5;
n = 10; // compile error
```
> 將int n 設為唯讀,不允許assignment,會報錯
## 英文名詞定義
- assignment
> 賦值的操作,即 `=`
---
###### tags: `C++`