--- tags: books, note --- # Pointer ## Intro 指標(Pointer)其實也是"**變數**" 只不過比較特殊 指標變數不像其他學過的變數一樣(int / float...) 存取的資料很直觀 ```cpp int a = 48763; cout << a; //output : 48763 ``` 而是比較抽象的"**記憶體位址(address)**" > 紫大 9-2 > --- > 在我們宣告一個變數的時候 > 編譯器便會配置一塊足夠儲存這個變數的記憶體給它 > 每個記憶體空間都有獨一無二的編號 > 這些編號稱為記憶體的位址(address) --- Example : ```cpp int *ptr = &a; cout << &a; // output : 0x61fe14 cout << *ptr; // output : 48763 cout << ptr; // output : 0x61fe14 cout << &ptr; // output : 0x61fe08 ``` ![](https://i.imgur.com/G4EiYfa.png) --- 你可能會想說指標感覺很無用處 但是在之後**實作資料結構時是相當重要的基礎** 而且也更能了解程式的運作 還可以寫出比較彈性的Code ## 宣告指標變數 > 紫大 9-6 ``` 資料型態 *指標變數 ``` Example : ```cpp int *ptr; int* ptr2; //這樣也可以 而且比較清楚是 int* 型態 ``` 但是 ```cpp int* ptr, ptr2; ``` ptr會是 `int*` 型態沒錯 ptr2卻只會是 `int` 型態 因此 ```cpp int* ptr; //適合用在只宣告一個指標變數 int *left, *right; //適合用在宣告多個 ``` ## 位址運算子「&」, 依址取值運算子「*」 知道如何宣告指標變數後 現在要做的就是存取變數的位址 用以下範例來解釋 ```cpp int a = 48763; int *ptr = &a; // 宣告一個ptr指標變數 並使他指向變數a的位址 cout << &a; // output : 0x61fe14 變數a的位址 cout << *ptr; // output : 48763 依指標變數所存取的位址來取值 也就是a cout << ptr; // output : 0x61fe14 指標變數ptr所存的位址 也就是 &a cout << &ptr; // output : 0x61fe08 指標變數ptr的位址 ``` ![](https://i.imgur.com/G4EiYfa.png) ## 動態記憶體配置 new, delete 前面已經提到說指標是拿來指向記憶體位置 那假如你未設立他初始指向的位址 ```cpp int *ptr; ``` 他有可能就會亂指向其他記憶體位址 如果這時你再對ptr進行操作 ```cpp *ptr = 48763; ``` 就會出現不可預期之錯誤 ~~(電腦應該是不會這樣就爛了啦)~~ --- 所以為了保險起見 一般我們在宣告指標時都會像這樣 ```cpp int *ptr = NULL; int *ptr = 0; int *ptr = nullptr; // C++11 ``` 在還沒要使用到指標的時候 把他指向空指標 這樣就不會爛了 --- 而指標最常用到的地方 就是進行記憶體的配置 因為平時在打Code的時候 資料不一定會是固定的數量 這時就需要動態的來配置記憶體 方便進行操作 像是在使用陣列時 ```cpp int arr[MAXN]; ``` 如果沒告訴你MAXN的範圍 你要存多少資料你也不會知道 這時動態記憶體配置就派上用場了 最基本的語法是像這樣 new : ```cpp 資料型態 指標名稱 = nullptr; 指標名稱 = new 資料型態(建構元); // 資料型態要一樣 ``` [建構元](https://hackmd.io/@konchin/book/%2FXToC9yD-R6Oxo7-G8nMy6Q#Constructor)的解釋 delete: ```cpp delete 指標名稱; ``` 大概懂這個概念後 可以繼續搭配[類別](https://hackmd.io/@konchin/book/%2FXToC9yD-R6Oxo7-G8nMy6Q#Class)來開始實作一些簡單的資料結構 方便熟悉用法 ## 小結 以上就是指標的初步認識 實際上真的沒有那麼困難 只不過平時打Code用不到 所以覺得有點玄而已 接下來要介紹參照(Reference) # Reference ## Intro 平常會用到參照的時機 大部分都是在寫函數的時候 我們一開始學函數的時候 應該都知道 ```cpp void change_value(int a) { a = 10; return; } int main() { int value = 20; change_value(value); cout << value; //output : 20 } ``` 這是因為我們所傳遞引數的方式是「傳值呼叫」(call by value) 編譯器會將欲傳入函數的引數值另外複製一份 供函數使用 所以不管怎麼在函數改變值 都不會影響原先變數的值 --- > 紫大 7-4 > --- > 「參照」(reference)就像是變數的暱稱或別名 > 他可以代替某個變數 > 也就是說 當一個變數有了他的參照之後 > 在程式中使用參照的名稱 即可直接存取這個變數 --- 所以如果我們是傳遞參照(pass by reference)的話 就可以直接修改原變數的值 ```cpp void change_value(int &a) { a = 10; return; } int main() { int value = 20; change_value(value); cout << value; //output : 10 } ``` 你可能會有點搞混說 阿e04 前面Pointer不是說`&`是取位址嗎 現在開始解釋了喔喔喔 ## 宣告參照 ``` 資料型態 變數名稱; 資料型態 &參照名稱 = 變數名稱; // 資料型態& 參照名稱 = 變數名稱; 亦可 ``` 注意到了嗎 這跟指標大大不同 ``` 指標的型態是 資料型態* 參照的型態是 資料型態& ``` Example : ```cpp int a = 10; int* ptr = &a; int& ref = a; ref = 48763; cout << a; // output : 48763 cout << *ptr; //output : 48763 ``` ## 小結 參照就這樣子而已了 # Others ## 再用指標指向指標? 你可能會想說 阿那 指標能不能再指向指標 參照是不是還可以參照(verb)參照 是可以沒錯 前者比較有意義 後者因為都一樣 所以那麼多參照是要幹啥呢 ```cpp int a = 48763; int *ptr = &a; // int *ptr = &ptr; // wrong 因為你要指向一個指標 所以型態應該要是 int** int **ptr2 = &ptr; // right ``` ## 陣列 你一定試過 ```cpp int arr[5] = {4, 8, 7, 6, 3}; cout << arr; // output : 0x61fe00 ``` 為甚麼不是輸出 4 8 7 6 3 呢 詳情請看 **紫大 9-30** > [name=9th教學顧問][time=Sat, May 20, 2020 1:37 PM]