前言
許多大學的資料結構課程會使用 C 語言。原因很簡單:C 語言的抽象層較少,程式設計者可以直接操作記憶體與資料配置,因此在實作 stack、queue、linked list 等資料結構時,更容易理解資料結構在系統中的實際運作方式。
在練習資料結構時,除了演算法本身,也需要一個簡單且穩定的開發環境與工作流程。例如:
- 使用什麼平台開發
- 如何組織 C 專案
- 如何自動化編譯
- 如何檢查記憶體問題
本文介紹一個簡單且實用的 C 資料結構實作工作流程,協助讀者建立練習環境。
開發平台
如果課程有上機考試,建議平常就使用相同的平台練習,藉此熟悉該環境。如果沒有特別限制,也可以先使用自己熟悉的平台。
Visual Studio
Visual Studio 是常見的 IDE。
需要注意的是:
- Visual C++ 對 C 語言標準的支援不完整
- 預設專案是為 C++ 設計,而不是 C
因此需要手動調整專案設定。
msys2
另一個常見選擇是 msys2。
msys2 提供:
- GCC toolchain
- 基本 POSIX 環境
- Windows 上的 Unix 工具
對於習慣 Linux 工具鏈的使用者來說,這是一個非常方便的開發環境。
WSL
WSL (Windows Subsystem for Linux) 可以在 Windows 上直接使用 Linux 環境。
目前 WSL 已相當成熟,使用 Linux 工具鏈來練習資料結構也是一個不錯的選擇。
C 專案架構
C 語言本身沒有專案的概念,因此通常需要搭配工具來管理程式碼,例如:
- IDE 內建的專案系統
- Make
- CMake
在練習資料結構時,一個資料結構通常只需要三個檔案:
- 標頭檔:公開介面
- 實作檔:資料結構內部實作
- 測試程式:用來驗證實作
例如佇列 (queue):
- queue.h
- queue.c
- main.c
這種寫法其實是在把資料結構寫成一個小型函式庫,而不是把所有程式碼都寫在 main.c。
這樣的好處是:
- 介面與實作分離
- 測試程式可以獨立
- 程式結構比較清楚
當檔案較少時,可以使用扁平式專案架構。
如果程式碼變多,則常見的做法是:
- src → 原始碼
- include → 標頭檔
使用 Make 自動化編譯流程
在練習資料結構時,通常需要反覆編譯與執行程式。
如果每次都手動輸入編譯指令會比較麻煩,因此建議使用 Make 來自動化流程。
Makefile 的基本形式如下:
task: dependency
command
例如:
compile:
gcc -Wall -g -o file file.c
在終端機輸入:
$ make compile
即可執行 compile 任務。
如果希望編譯完成後自動執行程式:
run: compile
./file
compile:
gcc -Wall -g -o file file.c
輸入:
$ make run
會先編譯程式,再執行程式。
檢查記憶體問題
在實作資料結構時,記憶體管理是非常重要的一部分。即使程式看起來運作正常,也可能存在記憶體洩漏。因此建議使用工具進行檢查。
Valgrind
Valgrind 是 Linux 上非常常見的記憶體檢查工具。
可以用來檢查:
- memory leak
- invalid memory access
- 未初始化記憶體
AddressSanitizer
在 macOS 或 clang 環境中,可以使用 AddressSanitizer。
編譯方式例如:
$ clang -O1 -g -fsanitize=address -fno-omit-frame-pointer -o file file.c
執行:
$ ASAN_OPTIONS=detect_leaks=1 ./file
結語
在使用 C 練習資料結構時,可以建立一個簡單的 workflow:
- 選擇開發平台(VS / msys2 / WSL)
- 建立簡單的 C 專案架構
- 使用 Make 自動化編譯
- 使用 Valgrind 或 AddressSanitizer 檢查記憶體問題
有了這樣的基本環境,就可以開始專心練習各種資料結構,例如:
- linked list
- stack
- queue
- tree
- hash table
附記
筆者另外提供一個簡單的 C 函式庫樣板專案:
https://github.com/opensourcedoc/c-boilerplate-application
此樣板包含基本的專案架構與 Makefile,可作為撰寫小型 C 函式庫或練習資料結構實作的起點。
此專案原先是為撰寫應用程式設計,但其結構同樣適合資料結構練習,因為資料結構通常會以「函式庫 + 測試程式」的方式實作。