Skip to content

指標 (Pointer)

指標 (Pointer) 與相關運算子

一個變數除了對應一種資料型態、一個值,還對應了一個位址(儲存該變數的記憶體位置)。要知道一個變數的位置,可以用傳址運算子 & ,並附值給一個變數,存放位置的變數稱為「指標」。

在變數前面加上 * ,就成為指標,注意 * 要放在每個變數之前,指標不必在宣告時賦值。

指標有維度的概念,一維指標存放一般變數之位置,二維指標存放一維指標之位置,以此類推。

利用間接運算子 * ,透過指標間接操作變數。

* 的不同功能

下面範例程式碼有兩次出現 *ptr ,但意義不同。

第一次出現是用來宣告 ptr 是(一維)指標。

後面出現的都是透過 ptr 指標操作 a

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
int *a, b; // 只有 a 是指標。

int val = 5;
int *ptr = &val;   // 一維指標 ptr
int **ptr2 = &ptr; // 二維指標 ptr2

// 記憶體為動態配置,每次跑出的答案不盡相同。
// 輸出為一個 16 進位的數字,開頭為 `0x` (代表 16 進位)。
cout << ptr << '\n';

cout << (*ptr) << ' ' << val << '\n';
++(*ptr);
cout << (*ptr) << ' ' << val << '\n';

指標有以下優點:

  • 傳遞參數時,不會複製參數,降低記憶體使用量。
  • 在執行程式時,記憶體是我們所需考量的點之一,任何變數可能會在任何時刻,成為不需要的資訊,成動態記憶體可在程式執行過程添加或刪除任何記憶體,減少記憶體資源。
  • 相較陣列,指標可以簡潔地表示各種圖、樹等非線性資料結構,降低維護成本。

參考 (Reference)

參考代表一個變數的別名,可直接取得變數的位址,並間接透過參考別名來操作物件,作用類似於指標,但不必使用指標語法,也就是不必使用 * 運算子來操作變數。

參考必須在宣告時設初始值。

1
2
3
4
5
int a = 5;
int &r = a;
++r;
cout << r << '\n'; // 5
int &r2;           // Complier error

參考有以下優點:

  • 傳遞參數時,不會複製參數,降低記憶體使用量。
  • 可取代太長的變數(如: a[x][y][z] ),增加可讀性。

函式傳入參數

函式傳入的參數,可以是一般、指標或是參考型態,以下以 Swap 來介紹:

Call by value:傳入的變數為一般型態,會 "複製" 一份到函式,原本的變數不會有任何改變。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
void swap(int x, int y)
{
    cout << x << ' ' << y << '\n'; // 1 2
    int t = x;
    x = y;
    y = t;
    cout << x << ' ' << y << '\n'; // 2 1
}

int main()
{
    int a = 1, b = 2;
    cout << a << ' ' << b << '\n'; // 1 2
    swap(a, b);
    cout << a << ' ' << b << '\n'; // 1 2
}

Call by address (value of pointer):傳入的變數為指標型態,函式內的變數改變,是對記憶體操作,所以原本的數字也會跟著改變。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
void swap(int *x, int *y)
{
    cout << *x << ' ' << *y << '\n'; // 1 2
    int t = *x;
    *x = *y;
    *y = t;
    cout << *x << ' ' << *y << '\n'; // 2 1
}

int main()
{
    int a = 1, b = 2;
    cout << a << ' ' << b << '\n'; // 1 2
    swap(&a, &b);
    cout << a << ' ' << b << '\n'; // 2 1
}

Call by reference:傳入的變數為參考型態,函數內的變數是原本變數的分身,所以函數內變數改變時,原本變數也會跟者改變。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
void swap(int &x, int &y)
{
    cout << x << ' ' << y << '\n'; // 1 2
    int t = x;
    x = y;
    y = t;
    cout << x << ' ' << y << '\n'; // 2 1
}

int main()
{
    int a = 1, b = 2;
    cout << a << ' ' << b << '\n'; // 1 2
    swap(a, b);
    cout << a << ' ' << b << '\n'; // 2 1
}