指標
一個裝著「地址」的變數。 · ⏱ 約 40 分鐘
你會學到三件事
& 拿地址、* 去那個地址取東西
- 為什麼
scanf 非要那個 & 不可
- 指標不是難,是多了一層
開始之前
到目前為止,一個變數裝的是值。
這一課的變數裝的是「另一個變數在哪裡」。
🟢 先把編輯器打開,跟著下面一起做:跟著做
一、兩個符號
這兩個符號長得像,做的事不一樣:
1int n = 42;2int *p = &n;
|
唸作 |
意思 |
&n |
address of n |
n 在哪裡(一個地址) |
int *p |
p 是一個指向 int 的指標 |
p 裝的是地址 |
*p |
去 p 指的地方 |
那個地址上的東西(也就是 n) |
⚠️ * 出現在兩個地方,意思不一樣:
1int *p = &n; // 宣告時的 * =「p 是指標」2*p = 100; // 使用時的 * =「去那裡」
這是初學者最容易糊掉的一點。記法:
宣告時的星號在講型別,使用時的星號在做動作。
積木盤上那三顆分別寫著「建立 … 指標變數 … 初始值 …」、
「取得 … 指向的值」與「把 … 存到 … 指向的位置」
——⚠️ 積木上沒有星號,它把那個符號翻譯成了話。
二、一張圖
畫成圖是這樣:
n p
┌──────┐ ┌──────┐
│ 42 │ ◄────────── │ 0x7f │
└──────┘ └──────┘
位址 0x7f 裝著 n 的位址
1printf("%d\n", *p); // 42 ——去 0x7f 看,是 422*p = 100; // 去 0x7f,把它改成 1003printf("%d\n", n); // 100 ← 🔴 n 也變了
n 和 *p 是同一個東西的兩個名字。
三、🔴 所以 scanf 需要 &
第 1 課那個沒解釋的 &,現在可以解釋了。
所以 scanf 要的是「位址」:
🔎 這一段是試一下——打了看結果就好,不要留在程式裡。
1scanf("%d", &n);
scanf 要改變 n,而 C 傳參數的時候是傳值:
傳 n 進去的話,函式拿到的是一份複本,改它不會影響外面。
所以要傳「n 在哪裡」,函式才改得到本體。
& 不是 scanf 的怪癖,是 C 唯一能「改到外面」的方式。
⚠️ 這也是為什麼 scanf("%s", s) 不用 &:
s 是陣列,而陣列名本身就已經是位址了。
四、空指標
NULL 表示「這個指標現在不指向任何東西」:
🔎 這一段是試一下——打了看結果就好,不要留在程式裡。
1int *p = NULL; // 指向「什麼都沒有」
⚠️ 對 NULL 用 * 會讓程式當場當掉(segmentation fault)。
而那其實是好消息:一個指到亂七八糟地方的指標會安靜地毀掉別的東西,
而 NULL 至少會立刻停下來。
用之前先問:
1if (p != NULL) {2 printf("%d\n", *p);3}
完成的樣子
這一課的參考做法——程式碼每一行的號碼,就印在對應的那塊積木上。
1#include <cstdio>2using namespace std;3int main() {4 int n = 42;5 int *p = &n;6 printf("%d\n", *p);7 *p = 100;8 printf("%d\n", n);9 return 0;10}
換你了
寫一個函式 void swap(int *a, int *b),把兩個變數的值對調。
⚠️ 呼叫的時候要寫 swap(&x, &y)。不加 & 的話它交換的是複本,
而外面兩個變數紋風不動,程式不會報錯。
(這是 C 的經典練習,而它就是「為什麼需要指標」的答案。)
到編輯器做這一題:練習:寫一個 swap(int *a, int *b)
做一個
寫一個 void divmod(int a, int b, int *q, int *r),把商和餘數分別寫回去。
用 divmod(47, 5, &q, &r) 叫它,印出 q 和 r。
🔴 一個函式只能 return 一個值,而這一題要兩個。指標就是那個出口。
⚠️ 把 *q = ... 寫成 q = ... 會編得過而什麼都沒發生,試一次看看。
到編輯器做這一題:做一個:一次回傳兩個答案
這一課你做了什麼
- 你用
& 拿到了一個變數的地址
- 你用
* 透過地址改到了原本的變數
- 你知道
scanf 的 & 是什麼、為什麼不能省
如果卡住了
| 你看到 |
多半是因為 |
| 程式當掉(segfault) |
對 NULL 或沒初始化的指標用了 * |
swap 沒有效果 |
呼叫時忘了 &,或函式參數沒寫 * |
scanf 之後值沒變 |
忘了 & |
| 印出一個很長的數字 |
印的是位址不是值。要 *p |
宣告時的 * 到底屬於誰 |
int *p 和 int* p 完全一樣。⚠️ 而 int* a, b; 裡 b 不是指標 |
在編輯器打開這一課 →