--- GA: G-RZYLL0RZGV --- ###### tags: `大一程設-下` `東華大學` `東華大學資管系` `基本程式概念` `資管經驗分享` 指標 pointer 基礎認識(一) === [TOC] ## 前言 指標可以說是 C++ 的超級大魔王,指標變數怎麼指、到底指到誰身上、記憶體位置到底存誰的,概念是有點難理解的,到了大四我仍沒辦法完全搞懂他,但我一定會盡全力把該學到的講給你們聽,同時去看 reference 多參考網路上多位大神的解釋會更好。 <span style="color:red">**參考資料二非常建議閱讀!!**</span> ## 講解影片(還沒錄) {%youtube youtubeid %} ## 基本觀念釐清: 何為變數、何為變數值、何為指標、如何取址 > <span style="color:red">**甚麼樣的資料型態(變數型態)存什麼樣的資料,這個大前提請千萬不要忘記**</span> ### 變數 變數由四個最重要的東西所組成,分別是變數型態、變數值、變數名稱、變數位址,請看以下表格與說明。 | 變數型態 | 變數位址 | 變數值 | 變數名稱 | | -------- | -------- | -------- | -------- | | int | 0x6ffe08 | 9 | a1 | | string | 0x6ffe00 | Orange | s1 | | double | 0x6ffdf8 | 7.3 | d1 | | float | 0x6ffdf4 | 6.5f | f1 | ![](https://i.imgur.com/UacJFXL.png) * 變數位址 * 在你程式執行後,變數儲存在記憶體的位置 * 變數值 * 該變數儲存的值,int 存整數,string 存字串 * 變數名稱 * 使用者對變數做一個自定義名字的動作 而根據你的型態不同,所需的記憶體用量也不同,以整數為例,一個整數就是佔 4 bytes 的空間。 ### 指標 變數位址負責讓你找到你的這個變數在電腦的哪裡,而**變數位址就是變數的指標**!簡單的說,變數的位址就是「**指向該變數的指標**」。<span style="color:red">**這句話很重要!!**</span> **而這邊說的是指標,而不是指標變數,請不要把兩者混為一談哦!!!** ### 取址與參考變數大不同!! 那既然我們這麼大費周章地跟你說了變數位址,自然就是可以被拿來用的東西,未來我們可以親自的來操控記憶體,那既然要操控,我們就要取得他。 要做到取得記憶體位址,需要利用取址運算子「`&`」,透過在變數前面加上這個符號以取得變數的記憶體位址。 * <span style="color:red">**要取得位置,取址運算子請一定是與宣告分開的哦!**</span> ```cpp= int a = 5; cout << &a; //印出 a 的記憶體位址 ``` * <span style="color:red">**請注意,請千萬不要像下面這樣寫!!!**</span> ```cpp= int &a = 5; // 程式會報錯,Error ``` 還記得我們有教過如何宣告參考變數 (reference variable),你可以為變數取一個別 名,所以你在變數宣告的時候這樣寫,是告訴程式說你宣告一個參考變數,並不是取 得一個變數所在的記憶體位置哦! 然而上面這樣寫也不是正確的參考變數宣告,參考變數是為「一個變數」取別名,然而你指派常數給他,是錯誤的,參考變數的宣告一定要接受「變數」,像這樣。 ```cpp= int a = 5; int &a_new = a; ``` ## 何為指標變數(pointer variable)? 上面都可以的話接下來來真的談談指標變數吧! 前面已經強調,指標(pointer)就是某個變數的記憶體位址,而指標變數(pointer variable),則是「用來存放指標的變數」。 有點文字遊戲對吧,所以我們先從前面來。 ``` 整數變數儲存整數 浮點數變數儲存浮點數 字串變數儲存字串 字元變數儲存字元 ``` > 那指標變數儲存甚麼? > 儲存指標!!! > [name=Orange] ### 如何宣告、初始化、設值給指標變數 如果對於指標變數儲存的東西到底是甚麼你已經理解了,接下來來看看如何宣告他。 * 全新符號 `*` ,其有兩種意義 * **指標** * 在**變數宣告**時出現,是**為了宣告指標** * 告訴程式此變數是一個「指標變數」 * 其內容存的是一個記憶體位址 * **取值運算子(Dereference operator)** * 在**宣告以外**的場合出現,是**為了取出指標所指向的位址的值** * 依照變數所存的記憶體位址,去那個位址把資料取出來 ```cpp= int a = 5; // 假設位於 0x6ffe0c int *p1; // 宣告不給值,之後才給值 p1 = &a; // 把 a 變數的位址 0x6ffe0c 存到 p1 內 **-----------我是分隔線------------** int *p1 = &a; // 宣告即給值,把 a 變數的位址 0x6ffe0c 存到 p1 內 ``` 指標變數的宣告方式呢,是在變數型態跟名稱中間加上一個 `*` 號,這樣就是宣告指標變數,而因為他必須接受一個記憶體位址,所以你只能要傳位址給他。 透過上文我們已經知道指標變數儲存指標,而指標又是指一個變數的記憶體位址,所以對於 p1 這個指標變數,就是存變數 a 的記憶體位址。示意圖如下: ![](https://i.imgur.com/PngbRsx.png) 而今天一個變數如果他被宣告,他會需要記憶體去儲存他,所以指標變數本身需要一個記憶體,而他裡面儲存的是一個指標(記憶體位址)。 > 學這邊真的在玩繞口令... > [name=Orange] ## 如何取值? 取出誰的值? 針對一般的整數變數、字串變數,要取值時我們都只要打他的名字即可,指標變數也同理,如果要取出他儲存的變數值,也是打他的名字。 ```cpp= int a = 5; cout << "[整數]變數 a 所儲存的[整數]: " << a << endl; //印出 a 就是一種取值了哦! cout << "[整數]變數 a 所處的記憶體位址(也就是指標): " << &a << endl; int *p1 = &a; cout << "[指標]變數 p1 所儲存的[指標](指標變數存記憶體位址): " << p1 << endl; cout << "[指標]變數本身所屬的記憶體位址: " << &p1 << endl; cout << "[指標]變數 p1 所儲存的[指標]指向的值: " << *p1 << endl; ``` ![](https://i.imgur.com/DlAwq3n.png) 相信看到這裡你已經知道我們說的指標變數取值是取出誰的值了!**就是指標變數所儲存的指標指向的值!!!** 用一張圖可以這樣解釋(紅筆對紅筆,藍筆對藍筆)。 ![](https://i.imgur.com/IfNgleN.png) 最後一個最重要的提醒,<span style="color:red">**指標**</span>跟<span style="color:red">**指標變數**</span>是兩個<span style="color:red">**完全不一樣**</span>的東西,請你一定要搞清楚,不然進入雙重指標就再見了哦! > 指標是_________? > 指標變數是__________? > 大家自己填空想想看吧,忘了麻煩一定要往上回去看! > [name=Orange] ## 小總結整理 * 指標的宣告 * type *name; * type *name = address; * type *name1, *name2, *name3; * 指標的取值 1. 指標變數如同一般的變數,取值就是打名字(取出這個指標變數儲存的位址(指標)) * name 2. 存取指標變數儲存的位址所指向的記憶體空間所儲存的值,<span style="color:red">**在前面加上米字號,切記與宣告不同!**</span> * *name * 如何取址 * 在任何的變數面前加上 `&` * 切記不能在宣告的時候加 * 可以把一個指標變數儲存的指標給另一個指標變數 * `name1 = name2` * 把 name2 指標變數儲存的記憶體位址也給 name1 所以現在兩個指標變數內都存相同的記憶體位址 ## Reference 由淺入深 <span style="color:green">**越上面越簡單**</span> [參考 - 1](https://openhome.cc/Gossip/CppGossip/Pointer.html) [參考 - 2 雖然是用 C 語言(不是 C++),但概念一模一樣,可專注在內文](https://kopu.chat/c%e8%aa%9e%e8%a8%80-%e8%b6%85%e5%a5%bd%e6%87%82%e7%9a%84%e6%8c%87%e6%a8%99%ef%bc%8c%e5%88%9d%e5%ad%b8%e8%80%85%e8%ab%8b%e9%80%b2%ef%bd%9e/) [參考 - 3](https://vinesmsuic.github.io/2019/08/14/c++-pointer/#const%E6%8C%87%E9%87%9D-const-pointer) 比較難的參考資料 [丁培毅老師](http://squall.cs.ntou.edu.tw/cprog/materials/Pointers2.html)