---
# System prepended metadata

title: 指標(pointer)
tags: [MDCPP講義]

---

###### 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
```










