###### tags: `MDCPP講義` # 指標(pointer) **Author: 謝侑哲** ---- 在計算機科學中,指標是一個讓電腦運行的核心技術 ---- 指標本身是一段小小的記憶體 裡面**儲存了某個記憶體的位址** ---- 這是我們上次看過的硬碟圖片 ![](https://i.imgur.com/O0AxPx7.png) 可以想像指標就像右邊HDD上面的那根針 ---- 我們可以透過指標來確定我們的變數、陣列... 總之就是所有資料的位址,並利用這個位址取出我們的資料 ---- 先帶一點指標的概念 不過我們在講指標之前,有些重要的東西要先提 --- ## 位元(bit) ---- 位元全名是Binary digit 至於甚麼是位元 ``01`` 這就是位元 ---- 我們常說程式就是010101組成的 事實上也是如此沒錯 ---- 先來看看我們之前教到的變數是怎麼由01組出來的吧 ![](https://i.imgur.com/brhhaZ5.png =500x) ---- 首先看到整數的部分(這張圖有誤,應該不是32而是31) 可以看見int的範圍是$2^{31}+2^{31}=2^{32}$ ![](https://i.imgur.com/tb46mLz.png) 想想如果他有$2^{32}$種可能數字,我們透過01來排列組合 需要用到多少個01才能表達所有數字呢 答案顯然是$log_2(2^{32})=32$ 所以表達一個int所需的空間就是32個bit 這也就是怎麼用bit來表達整數的概念 ---- 不過我們這裡用一個C++裡面的sizeof函式看看 這個函式可以告訴我們一個東西佔的記憶體大小是多少 ```cpp= int a; cout<<"int size= "<<sizeof(a)<<endl; ``` ```bash= int size= 4 ``` 4? 奇怪了不是應該是32嗎 ---- 這邊要帶出另外一個很重要的概念 ---- 位元組(byte) ---- 所謂位元組就是8個一組的bit ---- 在計算機科學上我們更常使用位元組byte 來表示,畢竟如果出現一些單個單個的垃圾bit可能會影響記憶體的存取 也可以讓電腦先預留好一定的位置 當我們遇到把一個變數從8(3bit)改成128(8bit)的時候 就不用重新分配一次記憶體 ---- 所以說 ```cpp= int a; cout<<"int size= "<<sizeof(a)<<endl; ``` ```bash= int size= 4 ``` 這段程式碼所輸出的4其實是4個位元組,也就是32bit ---- ![](https://i.imgur.com/g1vyEI8.png =700x) ---- ![](https://i.imgur.com/aMWmR0s.png =700x) --- ## 記憶體位址 ---- 回到記憶體位址 先來看看記憶體位址長怎樣 ---- ``0x00007fffffffe658`` 這是我隨便抓的一段記憶體位址 我們一步步解析他 ---- ``0x00007fffffffe658`` 先看前面0x的部分 這個0x是一種數學的表示方式 代表後面的數字是16進制(hex) 其他也有像是二進制(binary)的表示 開頭會用0b等等 ---- ``0x00007fffffffe658`` 這邊我們可以看到記憶體的數字總長度是16 前面講過他是16進制,所以她總共可表示的數字就是 $16^{16} = 2^{64}$ 是64bit,也就是8byte 所以我們可以看出指標的大小是8byte ---- 不過這個指標的大小在每台電腦上不一定一樣 回顧一下之前講到的 ![](https://i.imgur.com/85JpzOx.png) 電腦有分32位元跟64位元 剛剛提的指標是64位元電腦的指標,也是最常見的 如果是32位元,則是只有4byte ---- 為了讓某些程式在64位元跟32位元都可以跑 會保留一些兼容的操作 像是乘法的時候,如果原本是4byte的數字當她產生進位到第5byte時 會被丟到另一個區段,而不是塞成一個完整的5byte區段給指標 否則在32位元的電腦會爆掉 ---- 現在了解了位元跟記憶體位址,讓我們進下一步吧 --- ## 指標 ---- 剛剛有講到指標是指向某個記憶體位址 但他只向的是甚麼記憶體位址呢? ---- 指標通常指向的東西為一段記憶體的開頭 ![](https://i.imgur.com/wSDEhz0.png =650x) 像這樣,變數b的那段記憶體被指針指到的地方就是 0x0012FF74 ---- 另外有一個很毒瘤的地方 假設存了3553145145這樣的數字 換成16進位是比較好看 d3c8b139 那他的儲存方式會是這樣 ($16*16=2^8=1 byte$) 0x0012FF74 39 0x0012FF75 b1 0x0012FF76 c8 0x0012FF77 d3 這樣倒著一塊一塊存的 ---- 現在我們要來正式講指標在C++裡面怎麼寫拉 ---- ## C++裡的指標 ---- 先介紹兩個運算子 ---- 取址運算子(&) ---- 我們一般取變數的時候 都是直接取得他的值 ```cpp= int a=1; cout<<a; ``` ```bash= 1 ``` ---- 不過實際上我們取得值的方式是 先抓到他的記憶體位址 在透過變數名稱取得記憶體位址 用記憶體位址拿出他的數值 不過為了方便,程式通常直接讓我們取得值 ---- 所以這裡要帶出變數有三個要素 int b=1; - 位址 0x0012FF74 - 值 1 - 名稱 b 所以實際的流程是 名稱->位址->值 ---- 所謂取址運算子,就是取得變數位址的一個運算子 他的符號是 & ---- 用法是這樣 ``` #include<bits/stdc++.h> using namespace std; signed main(){ int b=1; cout<<"位址 "<<&b<<endl; cout<<"值 "<<b<<endl; } ``` ```bash= 位址 0x61fe1c 值 1 ``` ---- 間接取值運算子(*) ---- 間接取值運算子 就是取址運算址的相反 可以從某個位址取得那個位址的值 符號是 * ---- 用法是這樣 ``` #include<bits/stdc++.h> using namespace std; signed main(){ int b=1; cout<<"位址 "<<&b<<endl; cout<<"值 "<<*&b<<endl; } ``` ```bash= 位址 0x61fe1c 值 1 ``` ---- 另外指標這個東西是也可以宣告成一個變數的 只不過會變成他的值存了一個指標的位址 ---- 看看變數三要素 - 位址 0x0012FF74 - 值 0x0012FF08 - 名稱 b ---- 看起來很奇怪,不過事實上這是完全可行的 因為我們在記憶體中,所存的值都是一堆數字 事實上並不具特別意義 所以0x0012FF08也是可以當成一個int用 重要的是我們透過甚麼方法去取他 ---- 用法是這樣 ``` #include<bits/stdc++.h> using namespace std; signed main(){ int b=1; int* b_pointer=&b; cout<<"位址 "<<b_pointer<<endl; cout<<"值 "<<*b_pointer<<endl; } ``` ```bash= 位址 0x61fe1c 值 1 ```
{"metaMigratedAt":"2023-06-17T02:16:39.175Z","metaMigratedFrom":"Content","title":"指標(pointer)","breaks":true,"contributors":"[{\"id\":\"f547d745-63f3-4bad-986b-1751eeec19d1\",\"add\":3632,\"del\":244}]"}
    523 views
   Owned this note