---
# System prepended metadata

title: C++ 指標與參考
tags: [C++]

---

# C++ 指標與參考
[toc]

## 指標（Pointer）
C++ 的原生指標定義為：
```c=
#include <iostream>

int main(int argc, char** argv) {
    int a = 6;
    int* p = &a;
    
    std::cout << "The value of variable a: " << a << std::endl;
    std::cout << "The address of variable a: " << &a << std::endl;
    
    std::cout << "The value of the referenced variable by pointer p: " << *p << std::endl;
    std::cout << "The value of pointer p: " << p << std::endl;
    std::cout << "The address of pointer p: " << &p << std::endl;

    return 0;
}
```
> `*` 稱之為解引用運算元（dereference operator），在這邊 `&` 為取址運算元（address-of operator）

指標 `p` 本身儲存是所指向資料的記憶體位址，如果輸出 `p` 的話看到的只是指向資料的記憶體位址，必須搭配解引用運算元 `*p`，才能取得指標所指向的資料。

### Null Pointer
原生指標可以是 nullptr（建議不要使用 NULL），例如：
```c=
int* p = nullptr;
```
> 指標 p 的值會是 0x0000000，沒有任何記憶體位置可以參考，使用 `*p` 將會出錯哦。

### Void Pointer
沒有指定特定資料型態的指標，可以好處是可以自由切換資料型態，但輸出時需要轉型。
```cpp=
#include <iostream>

int main(int argc, char** argv) {
    int a = 5;
    char e = 'e';
    void* p;

    p = &a;
    std::cout << "The value of the referenced variable by pointer p: " << *static_cast<int*>(p) << std::endl;
    std::cout << "The value of pointer p: " << p << std::endl;
    std::cout << "The address of pointer p: " << &p << std::endl;

    p = &e;
    std::cout << "The value of the referenced variable by pointer p: " << *static_cast<char*>(p) << std::endl;
    std::cout << "The value of pointer p: " << p << std::endl;
    std::cout << "The address of pointer p: " << &p << std::endl;

    return 0;
}
```
### 複雜指標
```cpp=
int a = 5;    // 一般變數
int* b = &a;  // 指向 int 的指標
int** c = &b; // 指向 int* 的指標
int**& d = c; // int** 指標的參考
```

### 指標與陣列
```cpp=
int b[3] = { 0, 1, 2 };  // 宣告一維陣列
int* a = b;              // 指向陣列的指標
int* c = &b[0];          // 指向 b[0] 的指標

// 二維陣列
int d[2][3] = { {4, 5, 9}, {1, 2, 10} };
int* e = d[0];
int* f = &d[0][0];

int* g[2] = { d[0], d[1] };
int** h = g;
int i = h[0][2];   // it's 9.
```

## 參考（Reference）
參考是 C++ 才有的功能，可以簡單看做別名（Alias）的意思。
```cpp=
int n = 10;      // 宣告變數
int* p = &n;     // 宣告指標
int& r = n;      // 定義參考，變數 n 的別名
```
參考不會複製該物件（記憶體區塊），缺點是參考不可以是 NULL、必須要有初始值，且不能參考右值（rvalue）。這邊的 `&` 並不是取址運算元哦！稱之為參考運算元（reference operator）

> 參考與指標最大的不同在於，用在函數當參數使用時，指標實際上依舊是 Call by Value，而真正的 Call by Reference 是 C++ 的參考才具有的。
```cpp=
#include <iostream>

void magic(int a, int b) {
    std::cout << "Call by value" << std::endl;

    std::cout << "The Value of a in magic: " << a << std::endl;
    std::cout << "The Address of a in magic: " << &a << std::endl;
    std::cout << "The Value of b in magic: " << b << std::endl;
    std::cout << "The Address of b in magic: " << &b << std::endl;
}

void magic2(int* a, int* b) {
    std::cout << "Call by pointer" << std::endl;

    std::cout << "The Value of a in magic: " << *a << std::endl;
    std::cout << "The Address of a in magic: " << a << std::endl;
    std::cout << "The Value of b in magic: " << *b << std::endl;
    std::cout << "The Address of b in magic: " << b << std::endl;

    std::cout << "The address of pointer a: " << &a << std::endl;
    std::cout << "The address of pointer b: " << &b << std::endl;
}

void magic3(int& a, int& b) {
    std::cout << "Refernce" << std::endl;

    std::cout << "The Value of a in magic: " << a << std::endl;
    std::cout << "The Address of a in magic: " << &a << std::endl;
    std::cout << "The Value of b in magic: " << b << std::endl;
    std::cout << "The Address of b in magic: " << &b << std::endl;
}

int main(int argc, char** argv) {
    int a = 5;
    int b = 6;

    int* pa = &a;
    int* pb = &b;

    std::cout << "In Main Program" << std::endl;
    std::cout << "The Value of a in magic: " << a << std::endl;
    std::cout << "The Address of a in magic: " << &a << std::endl;
    std::cout << "The Value of b in magic: " << b << std::endl;
    std::cout << "The Address of b in magic: " << &b << std::endl;

    std::cout << "The address of pointer pa: " << &pa << std::endl;
    std::cout << "The address of pointer pb: " << &pb << std::endl;

    magic(a, b);
    magic2(pa, pb);
    magic3(a, b);

    return 0;
}
```
透過以上程式會發現，在 `main()` 當中的指標 `pa` 與 `pb` 與函數 `magic2()` 當中的指標 `a` 和 `b` ，兩邊的指標記憶體是不相同的，也就是說如果在函數 `magic2()` 修改了指標 `a` 和 `b` 的值（記憶體位置），在 `main()` 中的指標 `pa` 與 `pb` 並不會跟著連動。

參考也可以參照指標，語法如下：
```cpp=
int a = 5;     // 一般變數
int &b = a;    // a 的參考（ａ的別名）
int* p = &a;   // 宣告指標
int*& r = p;   // int* 指標的參考
int&* g = p;   // error: cannot declare pointer to 'int&'
```
> 要怎麼理解 `int*&`，從右往左讀就對了，所以它是一個 "參考"，參考什麼呢？是整數指標 `int*`；然後需要特別注意一下 `int&*` 是不合法的。

## Template
https://vinesmsuic.github.io/2020/01/12/c++-template/#template-specialization
https://docs.microsoft.com/zh-tw/cpp/cpp/templates-cpp?view=msvc-170
https://hackmd.io/@butastur/cpp11-templates-1
https://www.rocksaying.tw/archives/3641717.html
https://magicjackting.pixnet.net/blog/post/221968938

###### tags: `C++`