目次
1. 前言|C語 文法學習的意義與好處
C語自1970年代問世以來,一直在系統開發、嵌入式程式設計等廣泛領域持續使用,是一門具有歷史的程式語言。現代雖然 Python 與 JavaScript 等高階語言相當受歡迎,但 C語提供了許多語言的基礎語法,是系統性理解程式設計不可或缺的存在。 C語的語法學習的最大意義在於其通用性與廣泛的應用範圍。C語中使用的控制結構(if、for、while 等)以及函式定義方式,與許多程式語言共通,一旦掌握,其他語言的學習速度會大幅提升。此外,透過編譯器可直接理解低階運作,因而可應用於硬體導向的程式設計與效能調校。 另一方面,C語的語法雖然簡潔卻具高度彈性,因而若寫法出錯,容易導致預期之外的行為。記憶體管理與指標操作等在其他高階語言中被抽象化的部分,需要直接處理,因此對語法的精確理解對於安全且高效的程式開發是不可或缺的。 本篇文章將從基礎系統性說明 C語 的語法,涵蓋以 BNF(Backus–Naur Form)表示的形式化描述以及依據 C 標準規範的結構。也會探討初學者容易卡關的重點與實務上有用的語法知識學習方法,讓學習者到現場工程師皆能廣泛運用。2. C語言 語法的基本結構
C語言的語法是為了構成程式整體圖像的規則集合。大致可分為「敘述(statement)」「表達式(expression)」「宣告(declaration)」「函式定義(function definition)」「外部宣告(external declaration)」等要素。這些要素相互關聯,最終形成編譯器能理解的指令列。2.1 敘述(statement)與表達式(expression)的關係
敘述是程式中執行某種動作的指令單位,在 C 語言中必須以分號(;)結束。表達式是進行計算或評估的要素,其特點是會回傳值。 例如以下程式碼中,a = b + 5;
這個敘述中包含了 b + 5
這個表達式。表達式常作為敘述的一部份使用,也有表達式單獨作為敘述的情況。int a, b;
b = 3;
a = b + 5; // 此行是「敘述」,其中的 b + 5 是「表達式」
2.2 函式定義與宣告的基本形
在 C 語言中,所有的處理都在函式內執行。函式定義由回傳值型別、函式名稱、參數列表、處理內容(區塊)構成。 最著名的例子是main
函式,它是 C 程式執行的起始點。int main(void) {
printf("Hello, World!n");
return 0;
}
在函式定義之前放置「宣告」即可讓編譯器知道函式的存在與型別。這是常在標頭檔中使用的方法。int add(int x, int y); // 函式宣告(原型宣告)
2.3 外部宣告與內部宣告的差異
- 外部宣告(external declaration):宣告在整個檔案或多個檔案之間使用的變數或函式。通常,全域變數與函式定義屬於外部宣告。
- 內部宣告(local declaration):宣告僅在函式或區塊內有效的變數。像在函式內
int count = 0;
這樣定義的變數即屬於此類。
int globalValue = 10; // 外部宣告(全域變數)
void func() {
int localValue = 5; // 內部宣告(局部變數)
}
如此一來,C 語言的語法結構即使看起來簡單,了解各要素之間的關係仍然非常重要。3. C 語言 文法術語彙(給初學者的解說)
C 語言的文法在理解時,必不可少的是構成程式的最小單位「token(標記)」。token 是編譯器能辨識的有意義字串,依種類其角色不同。這裡為了讓初學者也能容易理解,整理了主要的術語。3.1 關鍵字(keyword)
關鍵字是 C 語言中事先保留的單詞,不能用作變數名或函式名。它在語言規範中表示特定的功能或語法。 常見的關鍵字範例:int, return, if, else, for, while, void, char, struct
例如 if
是用於條件分支的語法關鍵字,而 int
是表示整數型別的型別指定關鍵字。3.2 識別子(identifier)
識別子是程式設計師可以自由命名的名稱,包含變數名、函式名、結構體名等。 識別子的命名規則:- 以英文字母或底線(_)開頭
- 第二個字元之後可以使用數字
- 不能使用與關鍵字相同的名稱
int score;
float average_value;
3.3 字面值(literal)
字面值是指直接寫在原始碼中的常數。它表示值本身,亦可不經賦值而單獨使用。 常見的類型:- 整數字面值:
42
,-5
- 浮點數字面值:
3.14
,-0.5
- 字元字面值:
'A'
,'n'
- 字串字面值:
"哈囉"
,"C 語言"
3.4 運算子(operator)
運算子是對值進行計算或處理的符號。 分類範例:- 算術運算子:
+
,-
,*
,/
,%
- 比較運算子:
==
,!=
,<
,>
,<=
,>=
- 邏輯運算子:
&&
,||
,!
- 賦值運算子:
=
,+=
,-=
a = b + 5;
if (x >= 10 && x <= 20) { ... }
3.5 分隔符號(punctuator)
分隔符號用於明確程式的結構。 主要範例:- 分號
;
(語句結尾) - 大括弧
{}
(區塊範圍) - 小括弧
()
(函式呼叫或優先順序指定) - 方括弧
[]
(陣列存取)
4. 以BNF記法理解C語言 語法
BNF(Backus–Naur Form)是一種用於形式化描述程式語言語法的記號方法。C語言的規範文件與編譯器設計資料等也廣泛使用,對於客觀理解語法結構很有幫助。4.1 什麼是BNF
BNF以**非終端符號(結構的名稱)與終端符號(具體的符號或關鍵字)**的組合來表示語言的構文規則。- 非終端符號會以
<...>
這樣的角括號包住。 - 終端符號是實際在程式碼中使用的關鍵字或符號。
::=
表示「〜由〜構成」。
<if文>
以BNF表示如下。<if-statement> ::= "if" "(" <expression> ")" <statement> [ "else" <statement> ]
此規則說明「在 if
後接寫上用括號包住的表達式,接著寫敘述,且可選擇性地以 else
加上敘述」的含意。4.2 以BNF表示C語言的基本結構
作為C語言最簡單的結構範例,main
函式以BNF表示如下。<program> ::= <function-definition>
<function-definition> ::= <type-specifier> <identifier> "(" <parameter-list-opt> ")" <compound-statement>
<type-specifier> ::= "int" | "void" | "char" | "float" | "double"
<parameter-list-opt> ::= <parameter-list> | ε
<compound-statement> ::= "{" <statement-list-opt> "}"
<statement-list-opt> ::= <statement-list> | ε
4.3 BNF與實際程式碼的對應範例
將以BNF寫成的規則與實際的C語言程式碼作比較。 BNF:<function-definition> ::= "int" "main" "(" ")" "{" <statement-list> "}"
<statement-list> ::= <statement> | <statement-list> <statement>
程式範例:int main() {
printf("哈囉,世界!n");
return 0;
}
對應要點:"int"
→ 回傳值的型別指定子"main"
→ 函式名稱(識別子)"("
“)” → 表示無參數"{" ... "}"
→ 複合敘述(函式的處理區塊)<statement-list>
→ 函式內敘述的排列(printf
敘述、return
敘述等)
4.4 學習BNF的好處
- 能夠以結構化方式理解語言規格
- 較容易想像編譯器與解析器的運作
- 可應用於其他語言的語法比較與設計
5. 基於 C 標準規範(C11)的語法全貌
C 語言的語法已由 ISO 標準化。作為最新的主要規範之一的 C11(ISO/IEC 9899:2011),明確分類語言的整體結構,確保所有程式在一定規則下撰寫。此處整理其大致的全貌。5.1 語法的大分類
C11 的語法大致分為以下類別。- 翻譯單位(translation unit)
- 構成程式的最小編譯單位,等同於一個來源檔案。
- 也包含標頭檔的內容以及巨集展開後的程式碼。
- 外部宣告(external declaration)
- 全域變數或函式定義等,可在檔案範圍內使用的元素。
- 外部變數宣告、函式原型宣告、函式定義等。
- 函式定義(function definition)
- 由返回值型別、函式名稱、參數、處理區塊構成。
main
函式包括在內,所有可執行的處理皆以函式定義。
- 宣告(declaration)
- 告訴編譯器變數、型別、函式的存在。
- 本地變數宣告、typedef 宣告、結構體與共用體的宣告等。
- 敘述(statement)
- 執行實際處理的單位。
- 表達式敘述(expression statement)、複合敘述(compound statement)、選擇敘述(if/switch)、迴圈敘述(for/while/do-while)、跳躍敘述(return/break/continue/goto)等。
- 運算式(expression)
- 結合值、變數、運算子以進行計算或評估的構成要素。
- 單項式、二項式、賦值式、函式呼叫式等。
5.2 語法結構的階層圖(概念圖)
翻譯單位 (Translation Unit)
├─ 外部宣告 (External Declaration)
│ ├─ 函式定義 (Function Definition)
│ └─ 宣告 (Declaration)
└─ 宣告 (Declaration)
└─ 型指定子、初始化子等
敘述 (Statement)
├─ 表達式敘述 (Expression Statement)
├─ 複合敘述 (Compound Statement)
├─ 選擇敘述 (If / Switch)
├─ 迴圈敘述 (For / While / Do-While)
└─ 跳躍敘述 (Return / Break / Continue / Goto)
運算式 (Expression)
├─ 單項式
├─ 二項式
├─ 函式呼叫式
└─ 賦值式

5.3 基於官方規範的優點
- 能夠撰寫沒有歧義的程式碼
- 可正確預測編譯器與分析工具的行為
- 更容易理解他人撰寫的程式碼結構
6. 初學者容易卡住的語法要點
C 語言的語法看似簡單,但初學者在實際寫程式時,常會被意想不到的錯誤或未預期的行為所困擾。這裡將針對特別容易讓初學者卡住的代表性語法要點,說明其原因與解決方案。6.1 忘記加分號
在 C 語言中,語句(statement)結尾必須加上分號(;
)。若遺漏會導致編譯錯誤。 範例(錯誤範例):int a = 10 // 缺少分號
修正版:int a = 10;
要點:在控制結構的if
或for
語句之後,有時不會加分號,這會讓人容易混淆,直到習慣為止。6.2 大括號 {}
的範圍錯誤
在將多行處理合併時,若大括號的開閉位置錯誤,會導致非預期的處理範圍。 範例(非預期的動作):if (x > 0)
printf("Positiven");
printf("Always printedn"); // 不屬於 if
修正版:if (x > 0) {
printf("Positiven");
printf("Only when positiven");
}
要點:控制結構可以省略大括號,但省略會降低可讀性,且容易成為錯誤的根源。6.3 型別宣告的順序錯誤
在使用變數或函式之前,若未以正確的型別宣告,會產生編譯錯誤或警告。 範例(錯誤範例):x = 5; // 未宣告就使用
int x;
修正版:int x;
x = 5;
要點:特別是在函式呼叫時,將原型宣告寫在函式之前,或統一放在標頭檔中,會更安全。6.4 賦值與比較的混淆
=
是賦值運算子,==
是比較運算子。若混淆會導致非預期的結果。 範例(錯誤原因):if (a = 5) { ... } // 將 5 賦給 a,並以其值作判斷
修正版:if (a == 5) { ... } // 比較 a 是否等於 5
要點:部分開發者為了安全,會將常數寫在左側,例如 (5 == a)
。6.5 增量/減量運算子的放置位置
++
與 --
放在變數前後會改變其行為。++i
(前置)先將值增加後再回傳i++
(後置)先回傳值再增加
int i = 0;
printf("%dn", i++); // 輸出 0
printf("%dn", ++i); // 輸出 2
這些要點不僅是初學者,連有經驗者也可能不小心犯錯,因此利用程式碼審查與編譯器警告來防止是很重要的。7. C語言 文法有效學習方法
C語言的文法不僅僅是死記硬背,重要的是在實際撰寫程式碼的過程中體驗其用法。以下將介紹有效掌握文法的具體步驟與工具。7.1 從實際程式碼學習
在語法書或參考書確認規則後,立即撰寫範例程式碼並執行。舉例來說,學習「if敘述」時,從簡單的條件分支開始,逐步嘗試複雜的巢狀結構與 else‑if 語法,能加深理解。 範例:#include <stdio.h>
int main(void) {
int score = 75;
if (score >= 80) {
printf("Excellent!n");
} else if (score >= 60) {
printf("Good!n");
} else {
printf("Needs improvement.n");
}
return 0;
}
重點:透過實際輸入、編譯、執行,不僅能確認語法正確性,也能理解其運作。7.2 善用語法檢查工具與編譯器警告
編譯時出現的警告,可協助及早發現語法錯誤與潛在的程式錯誤。- gcc與clang可使用
-Wall
選項將警告顯示到最大程度 - 語法錯誤務必查明原因並修正
- VS Code、CLion 等 IDE 能即時顯示語法錯誤
gcc -Wall sample.c -o sample
7.3 參考官方規範與參考文件
ISO C 標準規範與高可信度的參考網站,對於正確掌握語法是不可或缺的。- ISO/IEC 9899:2011 (C11) 規範文件
- cppreference.com(C 語言章節)
- 大學與專科學校的公開資料
7.4 利用程式練習平台
善用可於線上環境練習 C 語言的網站,可提升學習效率。- paiza.IO(可於瀏覽器上執行)
- AtCoder 與 Aizu Online Judge(競賽程式設計環境)
- LeetCode(演算法練習)
7.5 學習步驟範例
- 學習基本語法(變數、運算子、控制結構)
- 自行製作小規模程式(計算機或簡易遊戲等)
- 掌握函式切分與標頭檔的使用方式
- 進入結構體、指標等進階語法
- 挑戰實務性的小規模專案
8. 總結|語法理解帶來的長期效益
C 語言的語法不僅僅是規則的集合,而是讓程式安全且高效執行的基礎。從基礎系統化學習,短期內能寫出正確的程式碼,長期則能提升整體開發技能。8.1 加速其他語言的學習
在 C 語言中掌握的語法知識,直接對 Java、C++、C#、Go 等多種語言共通的語法理解有所幫助。 特別是控制結構與函式定義方式幾乎相同,學習新語言的門檻會降低。8.2 設計低錯誤的程式碼
正確理解語法,可預防意外行為與編譯錯誤的發生。- 避免型別不匹配
- 適當設定變數作用域
- 徹底安全的記憶體操作
8.3 效能最佳化的基礎
C 語言能夠在接近硬體層級進行控制,深入理解語法後,可進行注重執行速度與記憶體效率的程式設計。 這在嵌入式開發、遊戲引擎、系統工具等需要高效能的領域特別有利。8.4 擴大專案全局視野
若能結構性地理解語法,程式碼閱讀能力會提升。能快速掌握他人撰寫的複雜程式碼,亦更容易進行重構與改進建議。8.5 持續的技能成長
一旦掌握 C 語言的語法,可以此為基礎延伸至以下新領域的學習。- 資料結構與演算法
- 網路程式設計
- 作業系統與編譯器的運作原理
9. FAQ|C 語言 文法相關的常見問題
Q1:C 語言的文法要學到什麼程度才算足夠? A:只要掌握基本的控制結構(if、for、while)、函式的定義與呼叫、型別與變數的宣告、陣列與指標的使用,就能順利撰寫基礎程式。但在實務或應用開發中,若能了解結構體、檔案輸入輸出、記憶體管理等,也會更有把握。 Q2:應該先學 BNF 還是實際程式碼? A:首先先執行實際的程式碼以掌握語法感覺,之後再以 BNF 進行系統化整理,能加深理解。可將 BNF 視為補強理論理解的工具。 Q3:為什麼理解語法會讓學習其他語言變得更容易? A:因為許多程式語言的語法結構都是以 C 語言為基礎設計的。例如 Java、C++、C#、Go 等,都具有類似 C 語言的語法規則。對控制結構與函式定義的理解,直接可套用到其他語言。 Q4:為什麼語法錯誤不容易被發現? A:在 C 語言中,語法上正確但與預期不同的程式碼仍可能寫出(例如=
與 ==
混淆)。此外,錯誤訊息對初學者而言往往難以理解,因此啟用警告選項(如 -Wall
等)進行開發,可較容易發現問題。 Q5:有推薦的語法檢查工具嗎? A:以下工具與環境值得推薦。- gcc/clang:使用
-Wall
選項可詳細顯示警告 - Visual Studio Code:透過擴充功能進行即時語法檢查
- clang-tidy:自動偵測程式碼品質與語法風格
- 線上執行環境(paiza.IO、JDoodle 等):可進行簡易語法檢查與執行結果確認