# C/C++
###### tags: `programming` `C/C++`
編譯ctrl+shift+b 執行ctrl+alt+n
[其他C++參考文獻](https://hackmd.io/@learnc/S18oUSBxK?utm_source=preview-mode&utm_medium=rec#C)
## 為何 c++ 不建議使用 malloc (動態配置記憶體空間)
> 在 C++ 中,malloc 函数和 free 函数是用于分配和释放内存的 C 标准库函数。在 C++ 中,更推荐使用 new 和 delete 运算符来进行内存的动态分配和释放。
>
> 以下是一些原因:
>
> * 构造函数和析构函数: malloc 分配的内存是未初始化的,而 new 运算符分配的内存会调用对象的构造函数进行初始化。同样,free 不会调用对象的析构函数,而 delete 运算符会。
>
> * 类型安全: new 和 delete 是类型安全的,它们在运行时处理类型信息,可以正确地匹配对象的大小并执行适当的构造和析构。malloc 和 free 不具备这种类型安全性。
>
> * 异常处理: 如果 new 运算符分配失败,它会抛出 std::bad_alloc 异常,允许你在异常处理中采取适当的措施。malloc 返回 NULL,需要显式地检查返回值。
>
> * 数组: new 和 delete 可以方便地用于动态数组的分配和释放,而 malloc 和 free 不支持数组的构造和析构。
>
> * 更直观: 在 C++ 中,使用 new 和 delete 更符合 C++ 的设计理念,更直观地表达了动态分配和释放内存的目的。
>
> 综上所述,尽管在 C++ 中可以使用 malloc 和 free,但通常更推荐使用 new 和 delete 运算符,因为它们提供了更好的类型安全性、更好的异常处理机制,同时更符合 C++ 的设计理念。
若要使用malloc 需要改寫為
例1 `int *x = (int*)malloc(sizeof(int))`
例2 `struct Node *node = (Node*)malloc(sizeof(struct Node));`
## ( ** ) 指標的指標/雙重指標
透過雙重指標改變指標變數的值
```c=
void foo(int** p) {
*p = malloc(sizeof(int)); //改變*p的值
}
```
如果指標要取得struct結構的成員要用->來存取成員
```c++=
typedef struct node{int data; struct node* next; }NODE; //NODE 變數
NODE* node;
node->data = data; //存取成員data
node->next = *top; //賦值
```
## const修飾符+指標
* `const int* p;` 表示p是一個指標,p本身平凡無比,但是p所指向的物件是一個特殊的物件-整型常量 (不能賦值)
* `int* const p;` 這個p指標不是一個普通的指標,它是個常量指標,即只能對其初始化,而不能賦值,另外,這個指標所指向的物件是一平凡的int型變數 (只能初始化)
* `const int* const p;` 結合前者兩種,指標和指向的物件都非同尋常,都是常量
## 存取權限

## operator overloading (運算子重載)
如果沒加&的話就會是複製的而不是原本的
通常運算子重載的參數要加const,避免被意外的更改
回傳值也通常是用*this,以便可以連續賦值多個對象
```c++=
#include <iostream>
class A {
public:
int x;
A(int x) : x(x) {}
A& operator=(const A& other) {
x = other.x;
return *this;
}
};
int main() {
A a(10);
A b(20);
b = a;
std::cout << b.x << std::endl; // 输出10
return 0;
}
```
## override/overload/Polymorphism 覆寫/多載/多型
https://medium.com/@c824751/override-%E8%A6%86%E5%AF%AB-overload-%E5%A4%9A%E8%BC%89-polymorphism-%E5%A4%9A%E5%9E%8B-%E7%9A%84%E5%B7%AE%E7%95%B0-3de1a499de29
### override 覆寫
Number *r = new Complex(8,9);
```c++=
class Number{
private:
int a;
public:
Number():a(7){}
int get(){return a;}
int setA(int v){a = v;}
};
class Complex : public Number{
private:
int *b;
public:
Complex(){
setA(4);
b = new int(5);
}
Complex(int x,int y){
setA(x);
b = new int(y);
}
int get(){return b[0];}
};
int main(){
Number *r = new Complex(8,9);
cout<<r->get()<<endl;
}
```
因為Number *r = new Complex(8,9);
當去掉用 r的物件變數時只能使用Number的成員函式
父類別的物件變數只能用父類別的成員變數及成員函式
子類別則可以使用父類別的
其他觀念:如果該function 在父類有加virtual 則會被覆寫,執行子類的function
### 多載
為何會有多載? 當今天一個功能需要因為不同需求帶入不同的參數列時,思考這樣需要多少個函式來做
多載可以根據帶進來的參數列決定要做哪個函式
## Constructor/Destructor (建構子/解構子) - 順序
建構子 由上而下
解構子 由下而上
子類別到父類別
一般類別生命週期結束會自動呼叫解構子
delete 時會呼叫解構子
## 淺層拷貝/深層拷貝
c++在傳入參數時需要加const
## 虛擬函式
* virtual 建構子
* virtual 解構子
* virtual 解構子 = 0 (純虛擬函式)
* 補充:const = 0; (不能改變值)
像是110 6-6:const = 0,可以透過 double perimeter() const override 來判斷要加const,因為如果父類別加上const 子類別也要加上const修飾詞
還沒要在該類別中實作
純虛擬函式是為override
## 繼承建構子
看繼承
```c++=
Bird(double weight, string name, bool canFly):Pet(weight, name){
...
}
```
## new
```c++=
Circle *c1 = new Shape();
// 建立一個Circle類別型別的c1指標變數,並指向一個新創建的Shape類別
```
前提是 Shape必須是Circle的子類別,否則非法,因為兩者不同型別
例如:
```c++=
Circle c1;
Shape s1;
s1 = c1;
//不同型別,否則是繼承關係,或用重載運算子
```
例如:
```c++=
#include <iostream>
class A {
public:
int x;
A(int x) : x(x) {}
A& operator=(const A& other) {
x = other.x;
return *this;
}
};
int main() {
A a(10);
A b(20);
b = a;
std::cout << b.x << std::endl; // 输出10
return 0;
}
```
其他補充:如果一個類別作為父類別,且繼承後,該父類別不用建立沒關係
## 建構子初始化方式
預設建構子
```c++=
class Box {
public:
Box() { /*perform any required default initialization steps*/}
// All params have default values
Box (int w = 1, int l = 1, int h = 1): m_width(w), m_height(h), m_length(l){}
...
}
```
多載範例
```c++=
class Box {
public:
// Default constructor
Box() {}
// Initialize a Box with equal dimensions (i.e. a cube)
explicit Box(int i) : m_width(i), m_length(i), m_height(i) // member init list
{}
// Initialize a Box with custom dimensions
Box(int width, int length, int height)
: m_width(width), m_length(length), m_height(height)
{}
int Volume() { return m_width * m_length * m_height; }
private:
// Will have value of 0 when default constructor is called.
// If we didn't zero-init here, default constructor would
// leave them uninitialized with garbage values.
int m_width{ 0 };
int m_length{ 0 };
int m_height{ 0 };
};
```
## vector 函式庫

```c++=
vector<int> my_vec;
my_vec.push_back(9); //由前面插入 9,4,5,...
my_vec.pop_back(); //由後面end取出
my_vec.at(0); //at在編譯時會去check範圍,若超出範圍..較嚴謹
my_vec.front(); //第一個元素
my_vec.back(); //最後一個元素
my_vec.size(); //回傳size,{9,4,5,3}回傳4
vector<int> vec(5,6); //給予5個空間,初始值是6,vec={6,6,6,6,6}
vec.insert(vec.begin()+1, 0); //在第一筆資料+1,插入0,{6,0,6,6,6,6}
vec.erase(vec.begin()); //刪除第一筆資料(begin),vec={0,6,6,6,6}
vec.erase(vec.begin(), vec.begin()+2); // 刪除begin到begin下兩個位置的資料,不包含begin下兩個位置的資料,所以6,6,6
sort(my_vec.begin(), my_vec.end()); //從begin到end排序
iterator有較高的通用性,有些容器不支援隨機存取像陣列
my_list_1.splice(my_list_1.end(), my_list_2); //splice,mylist2資料連接到mylist1的end,mylist1會變成mylist1+mylist2,mylist2會變空值
```
關於vector迭代器類型:
```c++
for(vector<int>::iterator it = number.begin();
it != number.end();
it++) {
auto n = *it; 因為it迭代器是一種抽象概念不屬於任何型別,所以需要透過改變位置方式來賦予n
cout << n << endl;
}
```
## 字串組合
注意會有overflow(溢位)
strcat
strcpy
* 字串比較:strcmp(const char *str1, const char *str2):
* 如果 str1 < str2 返回值<0
* 如果 str1 > str2 返回值>0
* 如果相等則 =0
## template 模板
根據不一樣的參數列帶進去,產生不一樣的函數出來
```c++=
template<class T>
T max(T a, T b){ //T型態
return (a>b)?a:b;
}
double a,b,c;
int d,e,f;
a = max<double>(b,c); //所有T被置換成double型態
d = max<int>(e,f); //被置換成int型態
```
## 其他
### 輾轉相除法
```pytoh=
# 找質數 f(20) 輸出 [2,3,5,7,11,13,17,19]
def g(N):
for i in range(2,N):
if N%i == 0: return False
return True
def f(N):
data = [i for i in range(2,N) if g(i) == True]
return data
```
### 排列組合
```python=
# 排列組合 h('ABCD') is ["ABCD","BACD","CABD","DABC"]
def h(data):
result = []
length = len(data)
for s in range(length):
x = data[s]
y = data[0:s] + data[s+1:length]
print(data[5:length])
result = result + [x+y]
return result
```
### ASCII
0:48
A:65
a:97
### c++陣列取長度
```c++=
// 111 problem 3
typedef struct student{
char id[10];
char name[30];
float grade;
int quizs[NUM_OF_QUIZ];
}STUDENT;
STUDENT students[] = {{"t011","John",0.0,{80,85,70}},
{"t020","Eric",0.0,{90,95,80}},
{"t022","Mary",0.0,{90,95,90}},
{"t003","Apple",0.0,{90,85,80}} };
numOfStudents = sizeof(students)/sizeof(students[0]);
```
### 運算子 & 其他基本觀念(陷阱)
* ~ 二進制倒數
* ! 十進制 非0則1 非1則0,例如:12->0
* << 二進制遞增,例 c<<2 c遞增兩位
* %3.1f 共3位保留小數點後一位
* 被除數、除數都是整數,結果也會是整數。
* double 型別如果運算值是整數則回傳結果也會是整數,除非是float才會變小數
### enum
依照前數值遞增,若沒初始值就從0開始
```c++=
enum FOOD {fish=-1, eggs, meat=3, milk, bean};
// eggs為0
// milk為4
// bean為5
```
### 問函式型態
看return回傳值
### 作用域
區域變數觀念,函式帶的參數是copy一份到函式內,return後由外面拿出來要在賦值才能改變全域變數的值
### python陣列索引
[起始:結束:每往後跳幾個索引]
結果值不會包含結束,但會包含起始
### lambda
```python=
# Lambda function to check if a given vaue is from 10 to 20.
test = lambda x : True if (x > 10 and x < 20) else False
# Check if given numbers are in range using lambda function
print(test(12))
print(test(3))
print(test(24))
```
```
True
False
False
```