統測資電類・資訊科專業科目(二)核心考點

第 7 章:指標

本章統整統測程式設計中「位址與間接存取」的核心工具:& 取址、* 解參考、傳值 vs 傳址呼叫、指標算術與雙重指標(111~115 年共計 3 題考古真題,題數雖少但觀念是後續章節的基礎)。 出題老師最愛把「傳址呼叫的兩處修改」、「指標型態相容性」與「多個指標互相指向的連鎖修改」揉合在一起設計陷阱。 本教學將帶你掌握清晰的位址追蹤技巧,並透過3 題真題 + 5 題模擬題的所有選項深度剖析,徹底掃除所有答題盲點!

📍
6 大核心
指標觀念全解構
🎯
3 題真題
111~115 統測題全收錄
💡
全選項剖析
A/B/C/D 逐項深入拆解
🚀
100% 互動
點擊即答 + 展開詳解

1 指標是什麼:位址(&)與解參考(*)的基本概念

指標變數存放的是「記憶體位址」,可以想成一張寫著門牌號碼的紙條——紙條本身不是房子,而是告訴你房子在哪裡。&x 取得變數x的位址(把門牌號碼抄到紙條上);*p 則是「解參考(dereference)」,拿著紙條去敲門,取得指標p所指向位址中存放的值。

C Code:& 取址、* 解參考、透過指標修改變數
int x = 10;
int *p = &x;              // p存放x的位址(紙條上寫著x的門牌號碼)
printf("%d\n", x);        // 10(變數本身的值)
printf("%d\n", *p);       // 10(透過p解參考,拿到x的值)
*p = 20;                  // 透過p「敲門」,直接修改x的內容
printf("%d\n", x);        // 20(x真的被改了!)
🖥️ 終端機執行輸出結果
10
10
20
符號名稱作用
&x取址運算子取得變數 x 的記憶體位址
int *p指標宣告宣告 p 是一個「存放 int 位址」的指標變數
*p解參考運算子取得(或修改)p 所指向位址中存放的值

2 傳值呼叫 vs 傳址呼叫:函式如何真正修改呼叫端變數

函式參數若用一般型態(如 int)傳遞,函式拿到的只是原始變數的一份複本,函式內對參數的修改不會影響呼叫端的原始變數(傳值呼叫,call by value);若要讓函式能真正修改呼叫端變數,必須改用指標型態當參數(傳址呼叫,call by reference)。

C Code:傳值呼叫 vs 傳址呼叫的效果差異
void inc_by_value(int x)      { x = x + 1; }   // 只改到函式內的複本,main的變數不受影響
void inc_by_reference(int *x) { *x = *x + 1; }  // 透過位址找到原始變數並修改它

int main(void) {
    int a = 10;
    inc_by_value(a);      printf("%d\n", a); // 10(沒變)
    inc_by_reference(&a); printf("%d\n", a); // 11(真的改到了)
}
🖥️ 終端機執行輸出結果
10
11
呼叫方式函式參數宣告呼叫時怎麼傳能否修改原始變數
傳值呼叫void f(int x)f(a)❌ 不能,只改到複本
傳址呼叫void f(int *x)f(&a)✅ 能,透過位址找到原始變數
⚠️ 統測常考題型:把 call by value 改成 call by reference

要讓一個原本用一般型態傳遞的函式,改成能真正修改呼叫端變數,必須同時做兩件事:呼叫時把引數改成 &變數(傳位址),並且函式參數宣告改成指標型態、函式內所有存取都要加上 * 解參考。只改其中一邊、沒改另一邊,都無法達成傳址呼叫的效果。

3 指標的型態相容性:指標必須跟它指向的資料型態一致

指標宣告的型態(例如 int *p)代表它只能合法指向該型態的位址。把不同型態的位址(或直接把一個「值」而非「位址」)指定給指標,會產生型態不相容的編譯警告或錯誤。

C Code:只有型態完全相符才能安全賦值給指標
int *p;
char MyName[] = {'A'};
int MyAge;
double MyWeight;

p = &MyAge;     // ✅ &MyAge 型態是 int*,跟 p 完全相符
// p = MyName;     // ❌ MyName 退化成 char*,跟 int* 不符
// p = &MyName[0]; // ❌ 同樣是 char*,跟 int* 不符
// p = MyWeight;   // ❌ MyWeight 是 double「值」,不是位址,型態錯誤更明顯
💡 檢查指標賦值是否合法的兩個步驟

1. 右邊是不是一個「位址」?(有沒有 &,或本身就是陣列名稱/指標變數)——如果右邊是一般變數的「值」,型態一定不符。
2. 這個位址指向的資料型態,跟指標宣告的型態是否完全一致?(int* 只能指向 int,char* 只能指向 char,以此類推)

4 指標算術(pointer arithmetic)與陣列名稱的關係

陣列名稱在大部分情況下會自動退化成「指向第一個元素的指標」。p+1 不是位址加1個byte,而是加「1個該型態大小」——編譯器會自動依指標宣告的型態換算要跳過幾個bytes。

C Code:指標 +1 會依型態大小自動換算跳過的位元組數
int arr[3] = {100, 200, 300};
int *p = arr;              // 陣列名稱會自動退化成指向第一個元素的指標
printf("%d\n", *p);        // 100
printf("%d\n", *(p + 1));  // 200,指標+1會依型態大小跳過一個int(通常4 bytes)
printf("%d\n", p[2]);      // 300,p[i]其實就是*(p+i)的另一種寫法
🖥️ 終端機執行輸出結果
100
200
300
🧠 指標起點若不是陣列開頭,位移量要以「指標當下指向的位置」為基準

如果指標一開始就指向陣列中間某個位置(例如 int *p2 = &Data[2]),那麼 *(p2+3) 指向的其實是 Data[2+3]=Data[5]——位移量是從指標當下指向的位置往後算,不是從陣列的索引0開始算。

5 雙重指標(指標的指標)

指標本身也是一個變數,也會佔用一塊記憶體、也有自己的位址——所以「指向指標的指標」(int **pp)也是合法的。**pp 要先解一次參考拿到 p,再解一次參考才拿到最原始的 x。

C Code:透過雙重指標一路改到最原始的變數
int x = 5;
int *p = &x;
int **pp = &p;   // pp存放的是「p這個指標變數」的位址
**pp = 99;       // 透過雙重解參考,一路改到最原始的x
printf("%d\n", x); // 99
🖥️ 終端機執行輸出結果
99
💡 白話比喻:兩層紙條

pp 是一張寫著「p這張紙條放在哪裡」的紙條;*pp 先照第一張紙條找到 p,**pp 再照 p 上寫的門牌號碼繼續找下去,最終找到 x。雙重指標常用在函式需要「修改一個指標本身所指向的位置」的情境(例如讓函式能改變呼叫端某個指標要指向哪裡)。

6 指標互相指向時的連鎖修改追蹤(統測最愛的複合陷阱)

當兩個指標分別指向兩個不同的變數,並依序透過解參考賦值時,後面那一行讀到的一定是「前一行執行完之後」的最新值,不是變數最原始的初始值。這是統測指標題最容易失分的地方。

C Code:兩個指標互指,逐行依序更新(統測115年Q46示範)
int  i1 = 1, i2 = 2;
int  *p1 = &i2, *p2 = &i1;   // p1指向i2,p2指向i1
*p1 = i1 + 1;                // 把 i1+1 寫進 i2(此時i1還是原始值1)
*p2 = i2 + 2;                // 把 i2+2 寫進 i1(此時i2已經是上一行更新後的值!)
⚠️ 逐行追蹤:一定要先確認「這一行修改的是哪個變數」,再往下一行走

1. *p1 = i1 + 1;:p1指向i2,所以這行是在修改i2。等號右邊的 i1 此時還是初始值1,所以i2被設為 1+1=2(跟原本的值剛好相同,容易誤以為「沒有變化」)。
2. *p2 = i2 + 2;:p2指向i1,所以這行是在修改i1。等號右邊的 i2,用的是上一行執行完之後的最新值2,不是最初的2(雖然數字剛好一樣,但推導邏輯不同),所以i1被設為 2+2=4。
最終 i1=4,i2=2。

🧠 記憶口訣

「先看指標指向誰,再看等號用舊值還新值」——每一行賦值前,先確認左邊 *p 實際上是在修改哪個變數;等號右邊出現的變數,一律用「執行到這一行為止」最新的值,不是程式一開始的初始值。

7 111~115 歷屆統測真題全選項深度剖析(共 3 題)

以下收錄統測專業科目(二)近年全部 3 題指標真題。每題均提供高解析度原始考題掃描圖、互動選項按鈕與所有選項逐項深入解析:

112 統測專二 Q41 📌 概念:傳址呼叫(call by reference)的正確修改方式
試題來源:技專校院入學測驗中心
想要讓 main() 中的 x 隨著 inc() 中 xin 的值更新,下列修改方式何者正確?
題幹程式碼
int sum=1, x=10;
int inc(int xin){
    int sum=2;
    sum = sum + xin;
    xin++;
    return (sum);
}
int main(){
    int sum = 3;
    sum=inc(x);
    printf("%d, %d", sum, x);
    return 0;
}
112 統測專二 Q41 題目截圖
本題標準答案: (A) 呼叫時x改為&x,並將inc()中所有xin改為*xin

🔍 四個選項逐項深度剖析

正確答案完整推導(★ 本題標準答案)
要讓 main() 中的 x 能被 inc() 內的運算真正更動,必須改成傳址呼叫:呼叫時傳入 x 的位址 &x,inc() 的參數宣告改成指標型態 int *xin 接收這個位址,並在函式內用解參考 *xin 存取/修改實際指向的值(所有原本用 xin 的地方都改用 *xin),這樣函式內的修改才會真正反映到 main() 的 x 身上,選 (A)。
選項 B 錯誤解析
呼叫時寫 *x 是錯誤的:x 本身已經是一個 int 變數的「值」,不是指標,對它取 *(解參考)沒有意義且無法通過編譯;而 inc() 裡把 xin 改成 &xin 也是方向錯誤——這個修改方式把「呼叫端該做的事」跟「函式內部該做的事」對調了,&(取址)與 *(解參考)分別該用在哪一邊完全弄反。
選項 C 錯誤解析
呼叫時 &x 是正確的(要傳位址),但 inc() 內把 xin 改成 &xin 卻是錯的:函式參數要宣告成指標型態(int *xin)才能接收位址,並且要用 *xin(解參考)才能存取、修改指標所指向的值;&xin 是在對參數本身取址,語意跟「透過位址修改原始變數」完全不同,無法達成傳址呼叫。
選項 D 錯誤解析
呼叫時 *x 與 inc() 內的 *xin 同樣方向錯誤:呼叫端要傳的是位址(&x),不是對一個普通 int 變數解參考(*x 不合語法);即使函式內部正確使用了 *xin,呼叫端沒有真的傳入位址,函式收到的仍然只是一個值的複本,無法修改到 main() 中的原始 x。
112 統測專二 Q48 📌 概念:指標型態相容性/位址運算子 &
試題來源:技專校院入學測驗中心
p宣告為int*,在【1】的位置加入哪一行程式碼,編譯時不會產生任何錯誤或警告訊息?
題幹程式碼
int *p;
char MyName[] = {'A'};
int MyAge;
double MyWeight;
【1】
112 統測專二 Q48 題目截圖
本題標準答案: (D) p = &MyAge;

🔍 四個選項逐項深度剖析

選項 A 錯誤解析
MyName 是 char 陣列名稱,會退化成 char* 型態的指標,跟 p 宣告的 int* 型態不符——把 char* 指定給 int*,型態不相容,編譯器會產生警告(甚至在較嚴謹的設定下報錯),並不是「不會產生任何錯誤或警告」。
選項 B 錯誤解析
&MyName[0] 是對 char 陣列的第一個元素取址,型態同樣是 char*,跟 p 的 int* 不符,理由跟選項A相同——只是換了一種寫法表達同一個 char 位址,型態不相容的問題並沒有解決。
選項 C 錯誤解析
MyWeight 本身是一個 double 型態的「值」,不是位址,把一個 double 值直接指定給指標變數 p,型態錯誤的程度比選項A、B更明顯(連「位址」都不是),一定會產生編譯錯誤。
正確答案完整推導(★ 本題標準答案)
&MyAge 是對 int 型態變數取址,得到的型態是 int*,跟 p 宣告的 int* 完全相符,型態相容,可以合法賦值,編譯時不會產生任何錯誤或警告訊息,選 (D)。
115 統測專二 Q46 📌 概念:指標互相指向的連鎖修改追蹤
試題來源:技專校院入學測驗中心
下列 C 語言程式片段執行後變數或指標所指的內容,何者正確?
題幹程式碼
int  i1 = 1, i2 = 2;
int  *p1 = &i2, *p2 = &i1;
*p1 = i1 + 1; *p2 = i2 + 2;
115 統測專二 Q46 題目截圖
本題標準答案: (A) i1 = 4

🔍 四個選項逐項深度剖析

正確答案完整推導(★ 本題標準答案)
p1 指向 i2,p2 指向 i1。先執行 *p1 = i1+1,即把 i2 設為 1+1=2(i1此時還沒被修改,仍是1;巧合的是 i2 原本也是2,看起來像沒變化)。接著執行 *p2 = i2+2,此時 i2 已經被上一行更新成2,故把 i1 設為 2+2=4。最終 i1=4,選 (A)。
選項 B 錯誤解析
*p1 指的是 p1 所指向的內容,也就是 i2,而 i2 最終的值是2(不是4,詳見正確答案的推導),這個選項把答案(i1=4)誤套到了錯誤的變數身上——*p1 其實是 i2,不是 i1。
選項 C 錯誤解析
i2 最終的值是2(第一行執行完後 i2 變成 i1+1=2,之後就沒有任何敘述再修改過 i2),這個選項把 i1 的最終值(4)誤植到了 i2 身上,兩個變數的答案對調了。
選項 D 錯誤解析
p2 是一個指標「變數」,它存放的內容是 i1 的「位址」,並不是一個像4這樣的一般數值。這個選項把「p2所指向的值變成4」(也就是 *p2,等同於 i1=4)跟「p2這個指標變數本身的值變成4」搞混了——指標變數存放的是位址,不會因為 *p2=4 這樣的賦值而讓 p2 本身的內容變成數字4。

8 高職段考與模擬精選實戰題(5 題全選項解析)

透過以下 5 題精選模擬試題,全面檢驗你對取址/解參考、傳值傳址、型態相容性與雙重指標的掌握度:

模擬實戰第 1 題 📌 概念:& 取址與 * 解參考的基本追蹤
已知下列 C 語言程式碼片段,執行後印出的內容為何?
C Code
int a = 5, b = 8;
int *pa = &a, *pb = &b;
*pa = *pb + 1;
printf("%d %d", a, b);
本題標準答案: (A) 9 8

🔍 四個選項逐項深度剖析

正確答案完整推導(★ 本題標準答案)
*pa = *pb + 1; 把 pb 所指向的值(也就是 b=8)加1,指定給 pa 所指向的變數(也就是 a)。所以 a 變成 8+1=9,b 全程沒有被任何敘述修改,維持8。輸出 "9 8",選 (A)。
選項 B(5 8)錯誤解析
此答案誤以為 *pa = *pb + 1; 這行賦值沒有真的生效,以為 a 維持原值5。但這行敘述明確透過 pa 指標把 a 的內容改成了 *pb+1=9。
選項 C(9 9)錯誤解析
此答案誤以為賦值也影響到了 b,把 a 的新值同步套用到了 b 身上,但這行敘述只透過 pa 修改了 pa 所指向的 a,完全沒有動到 b 或 pb 指向的內容,b 應該維持原值8。
選項 D(6 8)錯誤解析
此答案把 *pb+1 誤算成了 *pa+1(把 pa 原本指向的 a 值5加1得到6),搞混了到底該用哪一個指標所指向的值來計算——程式碼明確寫的是 *pb(也就是 b 的值8),不是 *pa。
模擬實戰第 2 題 📌 概念:傳值呼叫(call by value)不會修改原始變數
已知下列 C 語言程式碼片段,執行後印出的內容為何?
C Code
void modify(int n) {
    n = n * 10;
}
int main(void) {
    int x = 3;
    modify(x);
    printf("%d", x);
    return 0;
}
本題標準答案: (A) 3

🔍 四個選項逐項深度剖析

正確答案完整推導(★ 本題標準答案)
modify() 的參數 n 是一般 int 型態,屬於傳值呼叫(call by value),呼叫時只是把 x 的值3複製一份給 n,函式內對 n 的任何修改都只發生在這個複本上,不會影響 main() 裡的原始變數 x,故 x 維持3,選 (A)。
選項 B(30)錯誤解析
此答案誤以為函式內對參數 n 的修改會直接反映回呼叫端的 x,這只有在「傳址呼叫」(參數宣告為指標型態並用 &x 呼叫)時才會發生。本題的 modify() 使用的是一般 int 參數,屬於傳值呼叫,x 不會被改變。
選項 C(0)錯誤解析
此答案誤以為呼叫函式後,原本的 x 會被「清空」或重置,但傳值呼叫只是複製一份值給函式使用,並不會對呼叫端的原始變數做任何清空或重置的動作,x 應該維持呼叫前的值3。
選項 D 錯誤解析
此答案誤以為函式參數與呼叫端變數用不同名字(n跟x)會造成型態或語法錯誤,但這是完全合法且常見的寫法——函式參數名稱本來就可以自由命名,跟呼叫端傳入的變數名稱無關,不會有編譯錯誤。
模擬實戰第 3 題 📌 概念:指標型態相容性判斷
已知 int *p;、float f = 3.14;、int n = 5;,下列哪一行程式碼放入空格處,編譯時不會產生型態不相容的警告?
C Code
int *p;
float f = 3.14;
int n = 5;
/* 這裡要放一行程式碼 */
本題標準答案: (C) p = &n;

🔍 四個選項逐項深度剖析

選項 A 錯誤解析
&f 是對 float 型態變數取址,得到的型態是 float*,跟 p 宣告的 int* 不相容,型態不匹配。
選項 B 錯誤解析
f 本身是一個 float 型態的「值」,不是位址,把浮點數值直接指定給指標變數,型態完全不符,問題比選項A更明顯——連「位址」都不是。
正確答案完整推導(★ 本題標準答案)
&n 是對 int 型態變數取址,得到的型態是 int*,跟 p 宣告的 int* 完全相符,型態相容,不會有任何警告,選 (C)。
選項 D 錯誤解析
n 本身是一個 int 型態的「值」,不是位址,即使 n 剛好是 int 型態、跟 p 「看起來」有點關聯,但沒有取址符號 &,把一個整數值直接指定給指標變數仍然是型態錯誤——指標要存放的是位址,不是數值本身。
模擬實戰第 4 題 📌 概念:指標算術與陣列元素存取
已知下列 C 語言程式碼片段,執行後印出的內容為何?
C Code
double d[3] = {1.5, 2.5, 3.5};
double *p = d;
printf("%.1f %.1f", *(p+2), *p);
本題標準答案: (A) 3.5 1.5

🔍 四個選項逐項深度剖析

正確答案完整推導(★ 本題標準答案)
*(p+2) 等同於 d[2]=3.5;*p 等同於 d[0]=1.5(p 目前指向的第一個元素,沒有額外位移)。依 printf 引數順序輸出 "3.5 1.5",選 (A)。
選項 B(1.5 2.5)錯誤解析
把兩個運算式的順序搞反了,且第二個值也算錯了——誤把 *p 當成 d[1]=2.5,而不是 p 當下直接指向的 d[0]=1.5。
選項 C(3.5 2.5)錯誤解析
第一個值算對了,但 *p 誤算成了 d[1]=2.5,而不是 p 目前指向位置的值 d[0]=1.5——*p 就是解一次參考,沒有額外的位移動作。
選項 D(7.0 1.5)錯誤解析
把 *(p+2) 誤算成了某種「重複套用型態大小換算」後放大的數值(3.5的兩倍剛好是7.0)。但指標算術的 +2 已經自動依型態大小換算好要跳過的位元組數,直接對應到 d[2] 的值3.5,不需要再手動乘上型態大小做二次換算。
模擬實戰第 5 題 📌 概念:雙重指標(指標的指標)追蹤
已知下列 C 語言程式碼片段,執行後印出的內容為何?
C Code
int x = 1, y = 2;
int *p = &x;
int **pp = &p;
*p = y;
**pp = **pp + 5;
printf("%d %d", x, y);
本題標準答案: (A) 7 2

🔍 四個選項逐項深度剖析

正確答案完整推導(★ 本題標準答案)
*p = y; 把 y 的值2指定給 p 所指向的 x,x 變成2。**pp 是雙重解參考:pp 存放 p 的位址,*pp 拿到 p(也就是 &x),再解一次參考 **pp 就是 x。所以 **pp = **pp + 5; 等同於 x = x + 5 = 2+5 = 7。y 全程沒有被任何敘述修改,維持2。最終輸出 "7 2",選 (A)。
選項 B(1 2)錯誤解析
此答案誤以為 *p = y; 這行賦值沒有真的生效,以為 x 維持原始值1,忽略了這行明確透過 p 把 x 的內容改成了 y 的值2。
選項 C(2 2)錯誤解析
此答案正確算出了 *p=y 讓 x 變成2,但誤以為 **pp = **pp + 5; 這行沒有真的執行加5的動作,忽略了 **pp 就是 x 的另一種寫法,這行確實會讓 x 再加5,變成7。
選項 D(7 7)錯誤解析
此答案誤以為 **pp 這種雙重解參考的寫法會同時影響到 x 和 y 兩個變數,但 pp 從頭到尾只指向 p、而 p 從頭到尾只指向 x,兩層解參考最終只會動到 x 一個變數,y 不會受到任何影響,應維持原值2。

9 考前衝刺 10 秒速記口訣 & 核心知識檢核清單

✅
& 與 * 是相反動作
& 從變數取得位址(做紙條);* 從位址取得(或修改)內容(照紙條找東西)。
✅
傳址呼叫兩件事缺一不可
呼叫時傳 &變數,函式參數宣告成指標型態並用*存取——兩邊都要改,只改一邊無效。
✅
指標型態要完全相符
int* 只能指向 int 的位址;把值(非位址)或不同型態的位址指定給指標都會型態不符。
✅
指標算術自動換算型態大小
p+1 不是加1個byte,是加「1個該型態的大小」,不需要手動乘型態大小做二次換算。
✅
雙重指標兩層解參考
**pp 要先解一次拿到p,再解一次拿到x,兩層各自對應一次跳轉,不會同時影響其他變數。
✅
指標互指時務必逐行追蹤
每行先確認*p改的是哪個變數,等號右邊一律用「執行到當下」的最新值,不是最初的初始值。