C語言雖然規模精簡,但它是現代許多程式語言(如 Java、C#、Python)的基石。無論你是否有其他語言經驗,系統性地複習 C 的核心要素都能幫你建立扎實的系統程式設計能力。本文將帶你從最基本的 Hello World 開始,逐步涵蓋基本型別、運算式、函式、流程控制、字串操作、指標、動態記憶體、結構體與函式指標等關鍵主題。
C 語言的基本型別很少,常用的只有 char、int、float、double 等。其他如 short、long、signed/unsigned 只是修飾詞。建議:常用的記住,用不到的查文件即可。
算術、關係、邏輯、位元、逗號運算子與 Java/C# 大同小異。重點在於理解運算子優先順序與副作用(如 i++ vs ++i),以及運算式最終都有「型別」與「值」。
所有非內建操作都應封裝成函式。若函式僅在本檔案使用,加上 static 限制連結範圍,避免命名衝突。
static void hello_world() {
printf("hello, world\n");
}
printf 常用格式:%d(int)、%c(char)、%s(字串)、%p(指標)。記得換行符 \n 會刷新輸出緩衝區。
C89 標準要求變數宣告必須在區塊開頭。for 迴圈極其靈活,善用逗號運算子可在單行完成多變數更新。
static void n_hello_world(int n) {
int i = 0;
for (i = 0; i < n; i++) {
printf("hello, world\n");
}
}
C 沒有字串型別,字串是以 '\0' 結尾的字元陣列。標準庫 strlen 可計算長度,自己寫一個練習指標操作:
static int w_strlen(const char* str) {
int i;
for (i = 0; *str != '\0'; str++, i++) ;
return i;
}
const 修飾參數防止意外修改。str++ 會移動到下一個字元(位元組)。char* s1 = "hello"; // 指向唯讀常數區,修改會崩潰
char s2[10] = "hello"; // 在堆疊分配,可修改內容
*s2 = 'p'; // 正常運作,輸出 "pello"
雙指標法:一個從頭、一個從尾,交換字元直到相遇。
static char* reverse(char* str) {
char* ret = str;
char* p = str + w_strlen(str) - 1;
char c;
for (; p > str; --p, ++str) {
c = *p; *p = *str; *str = c;
}
return ret;
}
*p 取值,*p = *str 相當於 p[i] = str[i]。char* 移動 1 byte)。C 沒有 GC,必須手動配對 malloc 與 free,否則會記憶體洩漏。兩大原則:
範例:動態串接兩字串
static void concat_test() {
char* a = "hello";
char* b = "world";
int len = w_strlen(a) + w_strlen(b) + 1;
char* p = (char*)malloc(sizeof(char) * len);
if (p != NULL) {
char* result = p; // 保存起始位址供 free 使用
while (*a != '\0') *p++ = *a++;
while (*b != '\0') *p++ = *b++;
*p = '\0';
printf("concat_test: %s\n", result);
free(result); // 從起始位址釋放
} else {
printf("malloc error");
}
}
C 沒有類別,用 struct 組合異質資料。存取成員:變數用 .,指標用 ->。動態分配結構體陣列時注意指標邊界,若成員含動態記憶體也要逐一釋放。
struct customer { char* name; int age; };
static void customer_manager() {
struct customer wawa;
struct customer* p_wawa = &wawa;
p_wawa->age = 31; // 透過指標修改
struct customer* p_customers = (struct customer*)malloc(sizeof(struct customer) * 2);
if (p_customers) {
p_customers->name = "wawa"; p_customers->age = 10;
p_customers++;
p_customers->name = "tiancai"; p_customers->age = 30;
p_customers++; // 移至陣列尾端
int n = 2;
while (n-- > 0) {
p_customers--;
printf("%s is %d years old\n", p_customers->name, p_customers->age);
}
free(p_customers); // 歸還起始位址
}
}
函式指標語法較繁瑣,建議用 typedef 簡化。經典應用:冒泡排序傳入比較函式,實現升序/降序切換。
typedef int (*cmp_func)(int, int);
static int cmp_default(int a, int b) { return a - b; }
static int cmp_reverse(int a, int b) { return b - a; }
static void sort(int* arr, int n, cmp_func cmp) {
int i, j, t;
for (i = 0; i < n; i++) {
for (j = i; j < n; j++) {
if (cmp(arr[i], arr[j]) > 0) {
t = arr[i]; arr[i] = arr[j]; arr[j] = t;
}
}
}
}
static void sort_test() {
int arr[] = {4, 5, 3, 1, 2};
sort(arr, 5, cmp_default); // 升序
sort(arr, 5, cmp_reverse); // 降序
}
C 語言核心不大,但「指標」與「記憶體管理」是精髓所在。多動手寫練習(如自己實作 strlen、strcpy、鏈結串列、簡易分配器),才能真正掌握。建議搭配《C 和指標》或《C 程式設計語言》經典教材深入研讀。