指標 (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)
參考代表一個變數的別名,可直接取得變數的位址,並間接透過參考別名來操作物件,作用類似於指標,但不必使用指標語法,也就是不必使用 *
運算子來操作變數。
參考必須在宣告時設初始值。
| 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
}
|