前言
C/C++ 一個超級重要的觀念就是指標,
沒學會指標基本上就還等於沒有玩出 C++ 的「精隨」,
但指標這個概念真的超複雜又容易搞錯 (這邊是以作者而言,至少我混亂過好多次XD)
這次打算來好好整理一下,以一個初學者到終於搞清楚的角度,
重新整理這部分的內容。
先釐清會常搞亂的根本原因
我到很後來才發現,自己指標學得很差的最主要原因,
就是在「call by reference」加入之後,直接一片混亂,
「call by reference」是 C++ 才有的「更方便」的東西,
但也因為這個「方便」,導致觀念如果不穩,就會像我一樣把這個「方便」的功能,
變成「符號意義大混亂」
因此,如果這三個你現在很混亂,
建議先從「call by value, call by address(pointer)」搞清楚再說!!!
call by value
在 C(C++) 裡面,「所有的東西基本上都是 call by value」,
在這一開始還是很和平,「沒有指標」的世界,
所有東西看起來都是非常好懂。
void foo(int a){
a = 20;
}
int main(){
int a = 10;
cout << a << endl;
foo(a);
cout << a << endl;
return 0;
}
結果
10
10
結果我們卻發現了一個神奇的問題,那就是 a 並沒有被修改到,
如果以同樣的概念,除非我們改成這樣寫。
void foo(){
return 20;
}
int main(){
int a = 10;
cout << a << endl;
a = foo();
cout << a << endl;
return 0;
}
結果
10
20
用「回傳」的方式,去修改 a 的值,a 才會被改到
但其實這限制了所有修改的範圍,僅能侷限在 main() 當中。
仔細觀察就發現,要達到我們的目的,所有的修改都必須要在 main 裡面
但這並不是很實際。 隨著我們程式越寫越大,不可能要所有的東西都在 main() 處理。
圖解一下
在沒有指標的觀念以前,我們不是很在乎這個值「是實際存在哪個記憶體位置」
所以下面的圖,「Address 的部分」,在指標的概念出現前,
我們都是省略不看的。
但實際上,我們會發現在 void function 裡面的 a,
「複製了 10 這個值,並儲存在新的記憶體位置,
並用新的「只在 function 使用的 a」,指向這個記憶體位置。
- function 之內的 a,因為是另外一個記憶體位置的 a 被改過值,
- 所以不在 function 內的 a 就是另外一個 a,沒有被改過。
call by address (pointer)
在原本還是很簡單的只有 call by value 的世界,
自從我們要開始學習「指標 (pointer)」這個章節後,
一切開始複雜了起來。
但其實,掌握「指標 (pointer)」,才是真正開始「能完全掌控系統參數的控制」
上述的例子我們提到了一個問題,所有的修改僅在 main 裡面有效,
那如果要實現真正的跨 function 修改,我們就必須使用 call by address (pointer) 的方式
正如其名,call by address 就是直接呼叫他的記憶體位置進行修改,
因為我們實際儲存值的地方,都是一個又一個的記憶體位置,
我們所宣告的 a,只是暫時替我們指向這個記憶體位置而已。
而之所以也可以叫做 call by pointer,因為我們傳的是記憶體位置,
傳入 function 後,作為「指向記憶體位置的指標」,而非「參考值」,
因此也有 call by pointer 之稱 (不過我個人覺得講 call by address 更好理解。)
圖解一下
call by address,最重要的地方在於「傳了實際的記憶體位置進去function」,
也因此,我們得以進行對應值的修改
(改的是記憶體位置,原 a 也是指向同一個記憶體位置,造成 a 結果就可以從 function 內改變)