最近開始重新摸一下C++語言,畢竟打好根基是很重要的。
我個人是比較喜歡看書,所以我推介大家去讀這本《C++ Primer》來學C++ (我個人是用5th Edition)。
今天來談一下Pointer,這個所有Programmer都討厭的東西。
為什麼?因為Pointer通常難以理解,即使是有經驗的Programmer也常常因為調試Pointer引發的Error而備受折磨。


既然說到 Pointer, 就不得不先談一下 Reference(引用)。

Reference(引用)

Reference是為對象起另外一個名字,引用類型引用(refers to)另外一種類型。
每個引用的Variable名字都必須以 & 開頭。

來看一個小例子:

1
2
3
4
int ival = 1024;
int &refVal = ival; //refVal point to ival

refVal = 10; //現在 ival 也變成10了!

這和我們平時宣告Variable有何不同?

宣告Variable時,初始值會Copy到新建對象。

1
2
3
4
int val1 = 69;
int val2 = val1; // Copy val1 to val2

val1 = 70; // 現在val1的數值是70,但val2的數值仍然是69

宣告Reference時,引用會和它的初始值綁到一起(bind),而不是Copy。

1
2
3
4
int val1 = 69;
int &val2 = val1; // Bind val1 to &val2

val1 = 70; // 現在val1的數值是70,val2的數值也是70

TL:DR

Reference gave another name of an existed object.
They are still the same object.

注意 :引用必須要被初始化!

錯誤示範:

1
2
3
int &refVal2; //Error : 引用必須要被初始化。

int &refVal1 = 10; //Error : 引用的類型必須要是一個對象。

注意 :引用的類型必須要和對象的類型一樣!

用剛才的例子改一下:

1
2
double ival = 1024;
int &refVal = ival; // Error:引用的類型和對象的類型不一樣

來個簡潔的程序示範

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <iostream>
#include <string>

int main()
{
int i;
int &ri = i;
i = 5;
ri = 10;
std::cout << i << " " << ri << std::endl;
}

//結果
//10 10
//因為ri 和 i 綁定在一起,所以當 ri = 10 時,引用的 i 也同樣變成10。

Pointer(指針)

Pointer(指計)是程式語言中的一類資料類型及其物件或變數,用來表示或儲存一個記憶體位址,這個位址的值直接指向(points to)存在該位址的物件的值。
每個的Variable名字都必須以 * 開頭。

來看一個小例子:

1
2
int *ip1, ip2; //ip1 是 指向 int 型對象的 Pointer, ip2 是個 int 型對象。
double dp1, *dp2; // dp1 是個 double型對象, dp2是 指向 double 型對象的 Pointer。

Pointer需要用到new嗎?
為什麼人們用Pointer會用到new?

Address(地址)

Pointer存放在某個對象的Address(地址)。要想獲取對應的Address,需要使用到取地址符(和Reference(引用)一樣用 &)

1
2
int ival = 42;
int *p = &ival; //pointer p is pointing to variable ival 或者說 p存放了ival的address。

注意 :指針的類型必須要和對象的類型一樣!

1
2
3
4
5
6
double dval;
double *pd = &dval; // Correct : pointer pd is pointing to variable dval
double *pd2 = pd; // Correct : pointer pd2 is pointing to pointer pd

int *pi = pd; //Error:兩邊指針類型不一樣
pi = &dval; //Error:地址和指針類型不一樣 double unmatch with int type

指針的其他操作

Pointer是可以用 == 和 != 來做比較的。

1
2
3
4
5
6
7
int ival = 1024;
int *pi = 0;
int *pi2 = &ival //Link pointer pi2 to address ival
if(pi) //pi is 0, false
// ...
if(pi2) //pi2 is not 0, true
// ...

void* 指針

void*指針可用於存放住意對象的地址,但我們不知道地址中是什麼類型的對象。
通常用於pointer間的比較,function input and output。

1
2
3
4
double obj = 3.14, *pd = &obj;

void *pv = &obj; //obj can be any type of object
pv = pd; //pv can be any type of pointer

指向指針的指針

1
2
3
int ival = 1024;
int *pi = &ival; //pi point to ival
int **ppi = &pi; //ppi point to pi

ppi->pi->ival

引用和Const

先參考一下const的用法)

1
2
3
4
const int ci = 1024;
const int &r1 = ci; // 引用和對應的對象都要是const
r1 = 42; // Error : 引用的類型和對象的類型不一樣
int &r2 = ci; // Error : 引用的類型和對象的類型不一樣

對const引用

1
2
3
4
5
int i = 42;
const int &r1 = i; //允許把const int& 綁定到一個普通int對象上
const int &r2 = 42; // Const引用
const int &r3 = r1*2;// Const引用
int &r4 = r1 * 2; // Error: r4 不是 Const引用

想一想下面的例子,會不會有Error?

1
2
double dval = 3.14;
const int &ri = dval;

是沒有Error的。
留意ri是引用了一個int的數,而這裹dval是double。
為了確保ri綁定一個整數,Compiler會把上面的code變成這樣:

1
2
const int temp = dval; //轉double去int
const int &ri = temp; //綁定

ri綁定了一個temporary的對象。所以最後ri的值是3。

1
2
3
4
5
int i = 42; 
int &r1 = i; // r1綁定了i
const int &r2 = i; // r2綁定了i,但不能通過r2修改i的值
r1 = 0; // r1 不是const,所以 i 變成了0
r2 = 0; //Error : r2是const

指針和Const

指向Const的指針 (Pointer to Const)

和引用大致一樣。指向Const的Pointer是不能用於改變其所指對象的值。

指針的類型一定要和所指的對象一致。

Pointer type must match with the pointed object.

1
2
3
4
5
6
7
8
const double pi = 3.14; 
double *ptr = &pi; // Error: *ptr 不是一個 Const指針
const double *cptr = &pi; // Correct
*cptr = 42; // Error: *cptr 的值不能改變

//例外情況
double dval = 3.14;
cptr = &dval; // Correct, 但是不能通過cptr去改變dval的值 (why?)

指向Const的Pointer只要求我們不可以用Pointer去改變對象的值,

但沒有說過那個對象的值不能通過其他方式去改變。

Const指針 (Const Pointer)

Const pointer 一定要initialize, 而且initialize後存放在pointer中的address就不能再改變了。

把*放在const前面用以說明Pointer是個const,即不變的是Pointer的值而不是指向的那個值。

1
2
3
4
5
int errNumb = 0;
int *const curErr = &errNumb; // curErr 會一直指向errNumb
const double pi = 3.14159;
const double *const pip = &pi; // pip是一個指向const對象的const pointer
*pip = 2.72; //Error : pip 是一個指向Const的指針

順便分享一下Lynn姐的淺顯易懂C語言指標教學