Joseph Chen
大學修 C 語言時,指標讓我痛苦了整整一個學期。後來才理解:指標只是一個儲存記憶體地址的變數。搞懂這句話,C 語言就開竅了一半。
C 語言特色
C 語言是最接近硬體的高階語言,1972 年誕生,至今仍是作業系統、嵌入式系統、驅動程式的核心語言。了解 C 語言,等於了解電腦底層如何運作。
| 特性 | C 語言 | Python(對照) |
|---|---|---|
| 型別系統 | 靜態型別,需宣告型別 | 動態型別,自動推斷 |
| 記憶體管理 | 手動 malloc/free | 自動垃圾回收(GC) |
| 執行方式 | 編譯成機器碼(快) | 直譯執行(慢 10–100x) |
| 硬體存取 | 可直接操作記憶體地址 | 高度抽象,不直接存取 |
| 適合場景 | 作業系統、韌體、驅動程式 | 腳本、資料科學、Web |
| 學習難度 | 高(指標、手動記憶體) | 低(語法簡潔直觀) |
指標(Pointer)基礎
指標是 C 語言最難也最重要的概念。一句話理解:指標是一個儲存記憶體地址的變數。它「指向」另一個變數在記憶體中的位置。
記憶體視覺化
地址: 0x1000
42
int x
地址: 0x2000
0x1000
int *p
p 存的是 x 的地址,不是 x 的值。*p 才是「透過地址去讀取值」。
Stack vs Heap 記憶體
C 語言的記憶體分為兩大區域,搞懂它們是理解 C 語言記憶體管理的基礎:
Stack(堆疊)
- •自動分配、自動釋放
- •函數內宣告的 local 變數
- •大小有限(通常 1–8 MB)
- •速度極快(只是移動 stack pointer)
- •函數返回後記憶體自動收回
Heap(堆積)
- •手動 malloc() 分配
- •手動 free() 釋放(忘記 = 記憶體洩漏)
- •大小彈性,可動態調整
- •速度較慢(OS 介入管理)
- •生命週期跨越函數範圍
記憶體洩漏(Memory Leak)
malloc 分配的記憶體若不 free,即使變數超出 scope,記憶體也不會自動回收。在長時間運行的系統(如嵌入式設備、伺服器)裡,累積的洩漏最終會讓系統崩潰。工具:valgrind 可以自動偵測洩漏。
struct(結構體)
struct 是 C 語言的自訂複合型別,把相關的資料打包在一起。C++ 的 class、Python 的 dataclass 概念都源自這裡。
常用字串函數速查
C 語言的字串是 char 陣列,以 \0(null terminator)結尾。所有字串函數都在 <string.h>。
| 函數 | 用途 | 注意事項 |
|---|---|---|
| strlen(s) | 取得字串長度(不含 \0) | 返回 size_t,非 int |
| strcpy(dst, src) | 複製字串 | dst 空間必須足夠,危險!建議用 strncpy |
| strcat(dst, src) | 字串串接 | 同上,注意緩衝區溢位 |
| strcmp(s1, s2) | 比較字串 | 相等返回 0,s1 < s2 返回負數 |
| sprintf(buf, fmt, ...) | 格式化寫入字串 | 類似 printf,但寫到 buffer |
| strtok(s, delim) | 切割字串 | 會修改原字串,多執行緒不安全 |
C vs C++ vs Python 比較
| 面向 | C | C++ | Python |
|---|---|---|---|
| OOP | 不支援 | 完整支援(class) | 完整支援(class) |
| 記憶體管理 | 手動 malloc/free | 手動 + RAII (智能指標) | 自動 GC |
| 執行速度 | 最快 | 接近 C | 最慢 |
| 標準函式庫 | 精簡 | 龐大(STL) | 龐大(豐富生態系) |
| 適合場景 | OS/韌體/驅動 | 遊戲引擎/系統軟體 | 腳本/AI/Web |
面試常考題
Q1. int *p 和 int p 的差異?
int p 是普通整數變數,儲存一個整數值。int *p 是指標變數,儲存一個記憶體地址(該地址存放 int)。*p 解參考後才能讀取或修改那個地址的值。
Q2. malloc 和 calloc 的差異?
malloc(n) 分配 n bytes,內容不初始化(是垃圾值)。calloc(count, size) 分配 count*size bytes,並將所有 bytes 初始化為 0。calloc 稍慢,但更安全,能避免讀到未初始化值的 bug。
Q3. free 之後還能使用那個指標嗎?
不行。free 後那塊記憶體被歸還給 OS,繼續使用是「懸空指標(Dangling Pointer)」,屬於未定義行為,可能導致程式崩潰或資料被覆寫。習慣:free 之後立刻 ptr = NULL,使用前先檢查 NULL。
Q4. Stack overflow 在什麼情況會發生?
Stack 大小有限(通常 1–8 MB)。最常見原因是無終止條件的遞迴(infinite recursion),每次遞迴都在 Stack 上分配新的 stack frame,最終耗盡 Stack 空間,作業系統發出 SIGSEGV 信號終止程式。
Q5. 如何用 C 實作 swap 函數?
必須用指標。void swap(int *a, int *b) { int tmp = *a; *a = *b; *b = tmp; }。若傳值(int a, int b),函數內交換的是副本,呼叫端的值不會改變。這是指標在函數參數的最典型應用。
Q6. const int *p 和 int * const p 的差異?
const int *p(pointer to const int):p 本身可以改變(指向不同地址),但不能透過 p 修改所指的值。int * const p(const pointer to int):p 本身不可改變(固定指向某地址),但可以透過 p 修改所指的值。
上一篇
這是系列第一篇
下一篇
EP.02 — C#
ASP.NET 面試題