統測資電類・資訊科專業科目(二)精選核心章節

第 1 章:前處理器與編譯基礎

歡迎來到 C 語言程式設計自學講堂!本章專為技高(高職)學生量身打造,將繁瑣的編譯流程與前處理指令轉化為直觀易懂的觀念、生動比喻、圖表對照與豐富範例。 搭配 111~115 歷屆統測全部 6 題真題以及 5 題模擬題,每題皆提供互動點選測驗與所有選項逐項深入解析,幫你徹底打通觀念任督二脈,穩拿統測滿分!

📚
8 大核心
觀念圖解與白話剖析
🎯
6 題真題
111~115 年統測題全收錄
💡
全選項剖析
A/B/C/D 逐項分析不漏接
⚡
100% 互動
點擊即答 + 展開詳解

1 C 程式的四階段生命週期(從原始碼到執行檔)

當我們在電腦上寫好一段 C 語言原始碼(如 main.c)並按下「執行」或「編譯」按鈕時,電腦底層並不是直接看懂英文程式碼,而是必須經過嚴謹的四個轉換步驟:

Stage 1
前處理 (Preprocess)
.c → .i

前處理器負責處理所有以 # 開頭的指令(如展開 #include 標頭檔、進行 #define 純文字替換、過濾條件編譯 #ifdef,並刪除所有註解)。

Stage 2
編譯 (Compile)
.i → .s

編譯器檢查 C 語言的文法(語法分析),若有拼錯字或少分號會在此時報出 Syntax Error;若完全正確,則轉為「組合語言(Assembly)」。

Stage 3
組譯 (Assemble)
.s → .o / .obj

組譯器將組合語言翻譯為 CPU 能理解的機器二進位指令碼,產生目的檔(Object File)。

Stage 4
連結 (Link)
.o + lib → .exe

連結器把多個目的檔與 C 語言標準函式庫(如 printf、scanf)綁定結合在一起,最終產出可在作業系統執行的 .exe 執行檔。

💡 技高生活動比喻法

想像你要參加一場廚藝競賽:
1. 前處理:助手先把食譜(原始碼)裡的縮寫代號替換成完整食材清單,並撕掉便條紙註記(展開 #include、替換 #define、移除註解)。
2. 編譯:主廚檢查食譜步驟是否合乎料理文法與邏輯(檢查 Syntax Error),並轉化成切菜下鍋的標準動作指令(組合語言)。
3. 組譯:把動作指令變成廚師肌肉記憶的自動化動作(機器碼目的檔 .obj)。
4. 連結:將外叫的現成醬汁包(標準函式庫 stdio.h)與你的料理裝盤打包,產出完整的一道菜(.exe 執行檔)!

C Source Code (示範完整生命週期)
#include <stdio.h>      // 前處理:把 stdio.h 內容整份貼到這裡
#define MSG "Hello TVE" // 前處理:將所有 MSG 文字替換為 "Hello TVE"

int main(void) {
    // 這是單行註解,前處理階段會被乾淨移除
    printf("%s\n", MSG); // 展開後等同於 printf("%s\n", "Hello TVE");
    return 0;
}
🖥️ 終端機執行輸出結果
Hello TVE

2 前處理器(Preprocessor)核心機制與三大鐵律

前處理器不是編譯器,它只是一個「非常聽話但完全不懂 C 語言語法的文字替換小幫手」。牢記以下三大鐵律,統測前處理器相關考題就能秒殺:

三大鐵律 正確示範與原理 高職生最常踩雷的錯誤寫法
鐵律一:
必以 # 開頭
#include <stdio.h>
#define MAX 100
前處理器只認井字號開頭的指令。
❌ define MAX 100
少了 #,編譯器會以為是變數宣告而直接報錯!
鐵律二:
結尾「不可加分號」
#define PI 3.14
#include <math.h>
前處理指令不是 C 敘述句,結尾不加分號。
❌ #define PI 3.14;
若加分號,展開時會連分號一起貼上,導致 2 * PI * r 變成 2 * 3.14; * r 造成編譯崩潰!
鐵律三:
不用等號 =
#define RATE 0.05
巨集名稱與替換值之間以「空白鍵」隔開即可。
❌ #define RATE = 0.05
若加了等號,展開時會把 = 0.05 整個貼過去,引發語法錯誤!
⚠️ 統測魔鬼細節:加了分號會發生什麼恐怖事?

請仔細看以下這段震撼示範程式碼:

C Code (分號地雷大解剖)
#include <stdio.h>
#define PI_BAD 3.14;  // ❌ 致命錯誤:結尾多打了分號

int main(void) {
    double area = 10 * 10 * PI_BAD; 
    // 經過前處理器文字替換後,編譯器看到的真實程式碼居然是:
    // double area = 10 * 10 * 3.14; ;
    // 看似沒事?但如果是以下情況:
    
    // double radius = 2 * PI_BAD * 5;
    // 展開後變成:double radius = 2 * 3.14; * 5; 
    // 💥 編譯器看到第二個星號「* 5」前面居然被分號截斷,當場噴出 Syntax Error!
    return 0;
}

3 #include 標頭檔引入與防重複引用機制

#include 指令的作用極為單純:「把我指定的檔案內容,完完整整、一字不漏地複製貼上到本檔案中」。

📌 尖括號 < > vs 雙引號 " " 的決定性差異

標頭檔語法 搜尋路徑順序 典型適用時機
#include <stdio.h>
(尖括號)
直接前往系統標準函式庫目錄(System Include Paths)搜尋。 使用 C 語言內建的標準函式庫(如 stdio.h, stdlib.h, math.h, string.h)。
#include "my_math.h"
(雙引號)
先從當前專案所在的原始碼目錄(Current Directory)開始找;若找不到,再去系統標準目錄搜尋。 引入你自己或專案組員寫的自訂標頭檔(Custom Header Files)。

🛡️ 標頭檔防重複引用(Include Guard)

在大型專案中,如果多個 .c 檔都引用了同一個 .h 檔,可能會造成變數或結構體重複定義(Redefinition Error)。標準解決方法是使用條件編譯防護罩:

my_header.h (標準 Include Guard 寫法)
#ifndef MY_HEADER_H   // 如果還沒定義過 MY_HEADER_H
#define MY_HEADER_H   // 那麼現在立即定義它

// 這裡放置函式原型宣告、結構體定義等
void sayHello(void);

#endif // MY_HEADER_H // 結束防護區塊

// 現代編譯器也可以在標頭檔第一行寫:
// #pragma once (非標準但被各大主流編譯器普遍支援)

4 #define 巨集常數與常考三大陷阱

#define 建立的不是變數,而是「文字替換巨集(Macro)」。在進入編譯階段前,前處理器會像文書軟體的「全部取代」功能一樣,把所有巨集名稱換成對應的值。

⚠️ 統測超級必考陷阱 1:巨集常數不能被賦值(沒有左值 Lvalue)

變數在記憶體中有一個專屬的「門牌號碼(記憶體位址)」,所以可以被賦值(如 x = 20;)。
但巨集常數只是純數字字面常數(Literal Constant),沒有記憶體位址!

C Code (統測 115 年考題精華改編)
#include <stdio.h>
#define PI 3.14  // 定義巨集常數 PI

int main(void) {
    printf("PI is %f\n", PI); // 展開成 printf("PI is %f\n", 3.14);
    
    PI = 3.14159; // ❌ 致命編譯錯誤!
    // 經過前處理器文字替換後,這行程式碼會變成:
    // 3.14 = 3.14159;
    // 請問:你能把 3.14159 存進數字 3.14 裡面嗎?當然不行!
    // 編譯器會噴出:error: lvalue required as left operand of assignment
    return 0;
}

5 帶參數巨集(Macro Function)與括號安全防護原則

巨集也可以接收參數,外表長得很像函式,但本質依然是「純文字代入」,絕對不會先幫你計算參數的值!

C Code (巨集括號陷阱 vs 安全寫法)
#include <stdio.h>

// ❌ 危險巨集:參數與整體都沒有括號保護
#define SQUARE_BAD(x) x * x

// ✅ 安全巨集:每個參數與整個運算式都用小括號保護
#define SQUARE_SAFE(x) ((x) * (x))

int main(void) {
    int a = 3;

    // 我們希望計算 (3 + 1)^2 = 16
    int res1 = SQUARE_BAD(a + 1);
    // 文字替換展開過程:
    // a + 1 * a + 1
    // = 3 + 1 * 3 + 1
    // = 3 + 3 + 1 = 7 (💥 天差地遠!先乘除後加減導致嚴重邏輯錯誤!)

    int res2 = SQUARE_SAFE(a + 1);
    // 文字替換展開過程:
    // ((a + 1) * (a + 1))
    // = ((3 + 1) * (3 + 1))
    // = 4 * 4 = 16 (✅ 完全符合預期!)

    printf("BAD: %d, SAFE: %d\n", res1, res2);
    return 0;
}
🖥️ 終端機執行輸出結果
BAD: 7, SAFE: 16
🚨 巨集括號黃金守則(統測必背口訣)

「參數加括號,整體加括號;少一個括號,分數全跑掉!」
例如:#define MULTIPLY(a, b) ((a) * (b)),所有出現參數的地方都要包緊!

6 const 唯讀變數 vs #define 巨集大比拼

在 C 語言中要建立「不能修改的常數」,有兩種常見方式:#define 與 const。高職統測非常喜歡考兩者的區別與修復編譯錯誤:

比較項目 #define PI 3.14 (前處理器巨集) const double PI = 3.14; (唯讀常數)
處理階段 前處理階段(編譯前完成文字置換)。 編譯階段(由編譯器進行型態分析與記憶體配置)。
型態安全檢查 無型態檢查(純文字,容易引發隱晦錯誤)。 具有嚴格的資料型態檢查(如 int, double)。
記憶體配置 不佔用記憶體(只存在程式碼的即值常數中)。 佔用記憶體空間(擁有實體記憶體位址)。
作用域 (Scope) 全域有效(從定義處開始直到檔尾或 #undef)。 遵循變數作用域規則(如在函式內部宣告則只在該區塊有效)。
能否被修改? 絕對不能被當作變數賦值(無左值)。 被宣告為唯讀,若嘗試賦值(PI = 3.0;)會引發編譯錯誤。
C Code (const 賦值錯誤示範)
#include <stdio.h>

int main(void) {
    const int MAX_SCORE = 100; // 宣告為唯讀常數
    
    // MAX_SCORE = 90; 
    // ❌ 編譯錯誤!error: assignment of read-only variable 'MAX_SCORE'
    
    // 解法一:若數值需要變動,請刪除 const,改為一般變數 int MAX_SCORE = 100;
    // 解法二:在宣告時就給定正確初始值。
    
    printf("Max score: %d\n", MAX_SCORE);
    return 0;
}

7 條件式編譯(Conditional Compilation)

條件式編譯允許我們在前處理階段,依據巨集是否被定義,決定「哪些程式碼要送給編譯器編譯,哪些程式碼要直接當作垃圾丟掉(不編譯)」。

C Code (實戰除錯模式切換)
#include <stdio.h>
#define DEBUG_MODE 1  // 設定 1 開啟除錯訊息,設定 0 關閉

int main(void) {
    int x = 50, y = 100;

#if DEBUG_MODE == 1
    printf("[除錯日誌] 變數 x 初始化為 %d, y 初始化為 %d\n", x, y);
#endif

    int sum = x + y;
    
#ifdef DEBUG_MODE
    printf("[除錯日誌] 正在執行加法運算...\n");
#else
    // 若 DEBUG_MODE 未定義時編譯這段
#endif

    printf("計算總和為: %d\n", sum);
    return 0;
}
🖥️ 終端機執行輸出結果
[除錯日誌] 變數 x 初始化為 50, y 初始化為 100
[除錯日誌] 正在執行加法運算...
計算總和為: 150

8 程式除錯四大錯誤型態全解構(統測每屆必考!)

寫程式發生錯誤很常見,但在統測中,題目非常喜歡考你:「這個錯誤到底是在哪一個階段被抓出來的?」請務必釐清以下四大分類:

錯誤類型名稱 發生時間點 經典代表案例 能否產生執行檔?
語法錯誤
(Syntax Error /
Compile-Time Error)
編譯階段(由編譯器檢查語法時發現)。 • 敘述結尾漏打分號 ;
• 大小括號不對稱 { ... )
• 拼錯關鍵字(如寫成 prntf、intt)
• 嘗試對常數賦值(如 3.14 = x;)
❌ 否,編譯失敗中斷
連結錯誤
(Link-Time Error)
連結階段(由連結器找不到實體定義時發現)。 • 找不到 main() 進入點函式
• 呼叫了某個函式卻沒有提供其實作本體
• 同一個變數或函式名稱在不同檔案重複定義
❌ 否,無法產出 .exe
執行期錯誤
(Run-Time Error)
執行階段(程式能成功編譯並執行,但跑一跑當機崩潰)。 • 除以 0(Division by zero)
• 指標未初始化就存取(野指標存取)
• 陣列索引超出界線(Array out of bounds)
• 記憶體不足(Out of memory / Stack Overflow)
✅ 能產出執行檔,但執行時崩潰當機
邏輯錯誤
(Logic Error /
Bug)
執行完畢後(程式順利執行結束,但算出來的答案是錯的!)。 • 計算圓面積公式誤寫成 2 * PI * r
• 迴圈終止條件寫錯(如 <= 10 誤寫成 < 10)
• 巨集沒加括號導致運算優先順序錯誤
✅ 能正常執行,但結果不正確

9 111~115 歷屆統測真題全選項深度剖析

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

111 統測專二 Q36 📌 概念:C 語言基本觀念/前處理器/編譯連結
試題來源:技專校院入學測驗中心
以 C 語言開發程式的敘述,下列何者錯誤?
111 統測專二 Q36 題目掃描圖
本題標準答案: (B)

🔍 四個選項逐項深度剖析(為什麼對?為什麼錯?)

選項 A 敘述正確(非本題所選) 程式需要經過編譯及連結產生可執行檔,才能夠執行
C 語言是標準的編譯式語言(Compiled Language)。寫好的 .c 原始程式碼必須先經由編譯器轉譯為目的檔(.obj 或 .o),再由連結器(Linker)將目的檔與標準函式庫結合產生可執行檔(如 Windows 下的 .exe),作業系統才能載入執行。因此本敘述完全正確。
選項 B 敘述錯誤(★ 本題正確答案) 使用#include前置處理命令時,命令結尾需要加上分號
前置處理指令(如 #include、#define)是在編譯前由前處理器執行文字替換與檔案引入,它不是 C 語言的敘述句(Statement),結尾「絕對不需要(也不可以)」加上分號。如果寫成 #include <stdio.h>;,前處理器會將分號遺留在原始碼中,引發非預期的語法錯誤(Syntax Error)。因此本選項敘述錯誤,符合題意所求。
選項 C 敘述正確(非本題所選) main()是一個函式,程式執行時從main()函式開始執行
main() 是所有標準 C 語言程式的程式進入點(Entry Point)。作業系統啟動程式時,必定最先呼叫並執行 main() 函式中的第一行敘述,直到 main() 執行完畢或遇到 return 為止。因此本敘述完全正確。
選項 D 敘述正確(非本題所選) 單行註解可用2個斜線(//)開頭
C 語言支援兩種註解格式:以雙斜線 // 開頭代表單行註解,編譯器會自動忽略該行後續所有內容;多行註解則使用 /* ... */ 包夾。因此本敘述完全正確。
111 統測專二 Q37 📌 概念:前處理器/巨集定義 (#define 語法規範)
試題來源:技專校院入學測驗中心
關於 C 程式語言中,使用 define 建立常數的方式,下列何者正確?
111 統測專二 Q37 題目掃描圖
本題標準答案: (D)

🔍 四個選項逐項深度剖析

選項 A 錯誤(三處重大語法錯誤) define PI=3.14;
本選項犯了三種常見錯誤:① 缺少前處理指令開頭必備的井字號 #;② 誤用等號 =(巨集是以空白隔開名稱與置換內容);③ 結尾誤加分號 ;。
選項 B 錯誤(缺少井字號且多加分號) define PI 3.14;
本選項缺少了開頭的 # 字號,且結尾多加了分號 ;。若無 #,編譯器會把 define 當作未宣告的變數或型態而報錯。
選項 C 錯誤(誤用等號 =) #define PI=3.14
本選項雖然有 # 且沒加分號,但誤用了等號 =!若這樣定義,前處理器會把程式碼中所有的 PI 置換為 =3.14,例如 double r = PI; 會被展開成 double r = =3.14;,在編譯時造成嚴重的語法錯誤。
選項 D 正確(★ 本題標準答案) #define PI 3.14
完全符合標準前處理指令規範:開頭有 #、常數名稱 PI 與替換值 3.14 之間以空白隔開、不使用等號 =、結尾不加分號 ;。
112 統測專二 Q37 📌 概念:編譯原理/語法錯誤 (Syntax error) vs 執行期錯誤 (Run-time error)
試題來源:技專校院入學測驗中心
關於 C 語言中語法錯誤 (Syntax error) 以及程式執行過程的錯誤 (Run-time error) 的敘述,下列何者正確?
112 統測專二 Q37 題目掃描圖
本題標準答案: (A)

🔍 四個選項逐項深度剖析

選項 A 正確(★ 本題標準答案) 語法錯誤在編譯過程中就會被編譯器發現
語法錯誤(Syntax error)是指程式碼違反了 C 語言的文法規則(如關鍵字拼錯、括號未閉合、缺少分號)。編譯器在執行詞法分析與語法分析階段(Compile-time)就能直接檢查出來,並輸出錯誤訊息中斷編譯,無法產出目的檔與執行檔。故 (A) 正確。
選項 B 錯誤(除以 0 屬於執行期錯誤) 除以0屬於一種語法錯誤
int a = 10 / b;(當執行時變數 b 為 0)在語法結構上完全符合「變數 = 運算式」的規則,能順利通過編譯;但在程式「執行時」,CPU 遇到除數為 0 會觸發硬體例外(Floating-point exception)導致當機,因此「除以 0」屬於典型的執行期錯誤(Run-time error),而非語法錯誤。
選項 C 錯誤(指標未初始化存取屬於執行期錯誤) 指標未經初始化就指定其內容時可能會發生語法錯誤
宣告 int *ptr; 後立即寫 *ptr = 100;,程式在文法上完全合法,編譯器能夠編譯通過;但執行時由於 ptr 指向隨機未知的記憶體區段,寫入會引發 Segmentation Fault(記憶體區段錯誤)導致程式強制終止,這是執行期錯誤(Run-time error),非語法錯誤。
選項 D 錯誤(缺少分號屬於編譯期的語法錯誤) 在敘述(Statement)結束時,沒有分號是一種程式執行過程的錯誤
C 語言每句敘述結尾必須有分號 ;。若漏打分號,編譯器在編譯期間進行語法剖析時就會直接判定語法違規報錯(Syntax error),根本無法產出可執行檔,因此是編譯期的語法錯誤,而非執行期錯誤。
112 統測專二 Q38 📌 概念:前處理器(#define巨集)/const常數/賦值運算與編譯錯誤修正
試題來源:技專校院入學測驗中心
(閱讀下文,回答第 38-39 題)小芳在一個原本可以編譯成功的程式中,加入行號 1 至行號 6 的程式碼後發生編譯錯誤。刪除行號 1 至行號 5 中的哪一個部分,可以讓程式編譯成功?
112 統測專二 Q38 題目掃描圖
題幹原始程式碼 (行號 1 ~ 6)
1: #define  Value1  100
2: #define  Value2  (Value1 - 1)
3: const  int  Value3;
4: int  CheckValue = 0;
5: Value3 = Value2;
6: CheckValue = Value1 + Value3;
本題標準答案: (C)

🔍 四個選項逐項深度剖析

選項 A 錯誤(造成語法不完整) 刪除 (Value1 - 1)
若只刪除 (Value1 - 1),行號 2 會變成 #define Value2(空巨集),導致行號 5 展開為 Value3 = ;,反而引發更嚴重的語法錯誤。
選項 B 錯誤(破壞程式邏輯且非最佳解) 刪除 Value3 = Value2;
若刪除行號 5,雖然表面上不再對 Value3 賦值,但 Value3 將維持未初始化的垃圾值,導致行號 6 的加法計算失去意義(邏輯錯誤);而且題目的核心是考 const 關鍵字的唯讀特性。
選項 C 正確(★ 本題標準答案) 刪除 const
行號 3 使用了 const 修飾詞將 Value3 宣告為唯讀常數。在 C 語言中,const 變數一旦宣告即不可再被賦值,行號 5 嘗試執行 Value3 = Value2; 必然引發編譯錯誤。只要刪除 const,Value3 就變回一般的 int 變數,行號 5 的賦值動作完全合法,整段程式即可順利編譯通過!
選項 D 錯誤(造成未宣告識別字錯誤) 刪除 #define Value2 (Value1 - 1)
若刪除整個行號 2,後續行號 5 中的 Value2 會變成未宣告的識別字(undeclared identifier),編譯器同樣會報錯。
112 統測專二 Q39 📌 概念:前處理器巨集展開/運算式求值與變數追蹤
試題來源:技專校院入學測驗中心
(承上題)程式修正後(移除行號 3 的 const),執行完行號 6 時,CheckValue 的值為何?
112 統測專二 Q39 題目掃描圖
本題標準答案: (B)

🔍 程式碼逐步追蹤(Trace)計算過程

行號與敘述 前處理器文字替換與執行說明 各變數數值狀態
1: #define Value1 100 定義巨集 Value1 為 100。 Value1 = 100
2: #define Value2 (Value1 - 1) 定義巨集 Value2,展開為 (100 - 1) = 99。 Value2 = 99
3: int Value3; 移除 const 後宣告整數變數 Value3。 Value3 = 未知
4: int CheckValue = 0; 宣告並初始化 CheckValue 為 0。 CheckValue = 0
5: Value3 = Value2; 文字展開為 Value3 = (100 - 1);,計算後存入 99。 Value3 = 99
6: CheckValue = Value1 + Value3; 文字展開為 CheckValue = 100 + 99;,計算結果為 199。 CheckValue = 199

🔍 四個選項誘答力分析

選項 A 錯誤(200)
誤以為 Value2 等於 Value1(即 100 + 100 = 200)而忽略了減 1。
選項 B 正確(199 ★ 本題標準答案)
計算完全正確:100 + 99 = 199。
選項 C 錯誤(198)
誤以為減了兩次 1(即 100 + 98 = 198)。
選項 D 錯誤(100)
誤以為 Value3 沒加上去,只拿到 Value1 的值。
115 統測專二 Q36 📌 概念:前處理器(巨集常數 #define)/左值(lvalue)與編譯錯誤行號判定
試題來源:技專校院入學測驗中心
某生撰寫程式時將圓周率 PI 定義為常數,並在其中兩次使用不同精度的 PI 計算圓面積。程式編譯時在行號幾會發生錯誤?
115 統測專二 Q36 題目掃描圖
題幹原始程式碼 (行號 1 ~ 8)
1: #include <stdio.h>
2: #define PI 3.14
3: void main(void){
4:   double area1, area2;
5:   printf("圓面積area1為 %lf 平方公分.\n", 100*100*PI);
6:   PI = 3.14159265358979323846;
7:   printf("圓面積area2為 %lf 平方公分.\n", 100*100*PI);
8: }
本題標準答案: (C) 行號6

🔍 四個選項逐項深度剖析

選項 A 無誤(行號 2 語法完全合法) 行號 2: #define PI 3.14
#define PI 3.14 符合前處理指令標準語法(有 #、有空白隔開、無等號、無分號),前處理器會順利記錄巨集符號,此行不會出錯。
選項 B 無誤(行號 4 宣告完全合法) 行號 4: double area1, area2;
宣告兩個倍精確度浮點數變數 area1 與 area2,語法完全正確。
選項 C 發生編譯錯誤(★ 本題標準答案) 行號 6: PI = 3.14159265358979323846;
關鍵觀念:#define PI 3.14 是文字替換巨集,在前處理階段,程式碼中所有的 PI 都會被原封不動置換為數值字面常數 3.14。
因此行號 6 在前處理完後,實際上送進編譯器的程式碼是:
3.14 = 3.14159265358979323846;
在 C 語言中,賦值運算子 = 的左邊必須是「具有記憶體位址的可修改左值(Modifiable lvalue)」(例如變數)。純數字 3.14 是右值(Rvalue),不能被賦值!編譯器在編譯行號 6 時會立刻噴出錯誤:error: lvalue required as left operand of assignment,故行號 6 發生錯誤。
選項 D 無誤(行號 7 語法正確) 行號 7: printf("圓面積area2為 %lf 平方公分.\n", 100*100*PI);
若行號 6 未出錯,行號 7 展開後為 100*100*3.14,屬於合法的算術運算與輸出,語法本身毫無錯誤。

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

透過以下 5 題高擬真度題型自我檢測,看看自己是否已經完全掌握本章的所有常考陷阱:

模擬實戰第 1 題 📌 帶參數巨集與運算子優先順序
已知 C 程式中定義了巨集 #define CUBE(x) x*x*x,若在 main() 函式中執行 int ans = CUBE(1 + 2);,則 ans 的值為何?
本題標準答案: (C) 7

🔍 四個選項逐項深度剖析

選項 A 錯誤(27)
誤以為是函式呼叫先算 1+2=3 再做 3*3*3=27。巨集是「純文字代入」,不會先計算!
選項 B 錯誤(9)
誤算為 3 * 3 = 9。
選項 C 正確(7 ★ 本題標準答案)
前處理展開為純文字:1 + 2 * 1 + 2 * 1 + 2
依據「先乘除後加減」優先順序:
= 1 + (2 * 1) + (2 * 1) + 2
= 1 + 2 + 2 + 2 = 7!
選項 D 錯誤(1)
計算過程完全偏離。
模擬實戰第 2 題 📌 前處理指令與 Include Guard
在 C 語言標頭檔中,常使用 #ifndef 與 #define 搭配,其主要目的為何?
本題標準答案: (B)

🔍 四個選項逐項深度剖析

選項 A 錯誤
前處理指令是在編譯前處理,對執行時的 CPU 運算速度沒有直接加速效果。
選項 B 正確(★ 本題標準答案)
此結構稱為 Include Guard(標頭檔防衛式宣告),能確保即便有多個原始碼檔引入同一個標頭檔,其內容也只會被編譯器載入一次,避免重複定義(Redefinition error)。
選項 C 錯誤
前處理器不提供加密功能。
選項 D 錯誤
動態記憶體配置由 malloc/free 等函式負責,與前處理指令無關。
模擬實戰第 3 題 📌 錯誤類型精準辨析
下列哪一種情況會產生「連結錯誤(Link-Time Error)」?
本題標準答案: (D)

🔍 四個選項逐項深度剖析

選項 A 錯誤(語法錯誤 Syntax Error)
拼錯型態關鍵字會在編譯期被檢查出來,屬於語法錯誤。
選項 B 錯誤(執行期錯誤 Run-Time Error)
陣列越界在執行時才會導致記憶體非法存取或崩潰,屬於執行期錯誤。
選項 C 錯誤(語法錯誤 Syntax Error)
漏寫分號會在編譯期被抓出,屬於語法錯誤。
選項 D 正確(★ 本題標準答案)
編譯器可以單獨編譯通過語法檢查,但在最後「連結階段(Linking)」連結器找不到函式實體或找不到程式進入點 main(Undefined reference),會產生 Link-Time Error。
模擬實戰第 4 題 📌 條件式編譯輸出追蹤
閱讀以下 C 語言程式碼,執行後螢幕輸出的結果為何?
C Code (條件編譯追蹤題)
#include <stdio.h>
#define LEVEL 2

int main(void) {
    int score = 100;
#if LEVEL == 1
    score += 10;
#elif LEVEL == 2
    score += 20;
#else
    score += 30;
#endif
    printf("%d\n", score);
    return 0;
}
本題標準答案: (B) 120

🔍 追蹤說明

前處理器檢查 LEVEL == 2 成立,因此只會將 score += 20; 這行程式碼保留給編譯器,其他分支程式碼全部在前處理階段被剔除。
故 score = 100 + 20 = 120。
模擬實戰第 5 題 📌 const 常數與指標唯讀特性
關於 C 語言中的 const int x = 10; 與 #define x 10,下列敘述何者正確?
本題標準答案: (A)

🔍 四個選項逐項深度剖析

選項 A 正確(★ 本題標準答案)
const 是編譯器處理的唯讀變數,具型態安全性與記憶體位址;#define 則是前處理器的文字置換,無型態檢查。
選項 B 錯誤
兩者都不能被賦值(const 變數唯讀;#define 沒有左值)。
選項 C 錯誤
#define 在前處理階段執行,不做型態檢查。
選項 D 錯誤
const 由編譯器處理,不會在前處理階段被替換。

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

✅
前處理指令鐵律
以 # 開頭、不用等號 =、結尾不加分號 ;。
✅
巨集本質
巨集只是純文字代入,不是變數,沒有記憶體位址,不能被賦值(無左值)。
✅
巨集括號守則
#define SQR(x) ((x)*(x)),參數加括號、整體加括號!
✅
四階段轉換順序
前處理 (.c→.i) → 編譯 (.i→.s) → 組譯 (.s→.obj) → 連結 (.obj→.exe)。
✅
語法錯誤 vs 執行期錯誤
漏分號/拼錯字 = 語法錯誤(編譯期);除以 0 / 未初始化指標 = 執行期錯誤。
✅
#include 引用差異
<stdio.h> 找系統庫;"my.h" 先找當前專案目錄。