---
# System prepended metadata

title: C/C++
tags: [programming, C/C++]

---

# 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;` 結合前者兩種，指標和指向的物件都非同尋常，都是常量
## 存取權限
![](https://i.imgur.com/uLJenUv.png)

## 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 函式庫
![](https://i.imgur.com/S5z0xgu.png)
```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
```





