字符串是C語言中使用最頻繁、也是Bug高發區的數據類型。本文系統梳理字符串的內存模型、初始化方式、標準庫操作、函數傳遞返回、命令行參數處理、函數指針應用,助你構建清晰的字符串編程心智模型。
\0(NUL,ASCII 0)結尾的字符序列。char*指向首字符,長度不含\0,分配空間需+1。char*、寬字符wchar_t*(16/32位,支持國際化)。"hello",存儲在只讀字面量池,多次使用同一文面量通常共享一份副本。不可修改,修改導致未定義行為。char str[] = "hello"; 或 char str[10] = "hi";。存儲在棧(局部)或全局/靜態區,可修改,大小固定。char *p = "hello"; 指向字面量池(只讀);char *p = malloc(...); strcpy(p, "hello"); 指向堆,可修改、可擴展、需手動free。sizeof(arr)返回數組總字節數(含\0);sizeof(ptr)返回指針大小(4/8字節);strlen(str)返回邏輯長度(不含\0)。<string.h>)| 函數 | 原型 | 關鍵點 |
|---|---|---|
| 比較 | int strcmp(const char*, const char*) | 返回0相等,<0 s1ptr1 == ptr2 比較內容。 |
| 複製 | char* strcpy(char* dest, const char* src) | 含\0整體複製。dest必須有足夠空間。安全版strncpy不保證以\0結尾。 |
| 拼接 | char* strcat(char* dest, const char* src) | 將src接到dest末尾(覆蓋dest的\0)。dest需預留足夠空間。常見錯誤:strcat(str1, str2)未分配新空間導致溢出。 |
| 長度 | size_t strlen(const char*) | 掃描至\0,O(n)。 |
// 讀取任意長度行,動態擴容
char* readLine() {
size_t cap = 16, len = 0;
char *buf = malloc(cap), *p = buf;
int ch;
while ((ch = getchar()) != '\n' && ch != EOF) {
if (len + 1 >= cap) { // +1 for \0
cap *= 2;
char *nb = realloc(buf, cap);
if (!nb) { free(buf); return NULL; }
p = nb + (p - buf); // 維持相對偏移
buf = nb;
}
*p++ = ch; len++;
}
*p = '\0';
return buf; // 調用者負責 free
}
void func(const char* s)(只讀)或 void func(char* buf, size_t n)(輸出緩衝區)。數組名退化為指針傳遞。const char* getMsg() { return "static"; } 線程不安全,多次調用覆蓋。char* dup(const char* s) { char* p=malloc(strlen(s)+1); strcpy(p,s); return p; } 調用者必須 free,文檔需明確說明。void format(char* out, size_t n, ...) 最安全,無所有權轉移。main(int argc, char** argv)argc:參數個數(含程序名)。argv:指針數組,argv[0]為程序路徑,argv[1..argc-1]為實際參數。./prog "hello world" 42 → argv[1]="hello world"。// 比較器類型
typedef int (*CmpFunc)(const char*, const char*);
// 忽略大小寫比較
int cmpIgnoreCase(const char* a, const char* b) {
char *la = strToLower(a), *lb = strToLower(b);
int r = strcmp(la, lb);
free(la); free(lb);
return r;
}
// 通用排序
void sortStrings(char* arr[], int n, CmpFunc cmp) {
for (int i=0; i 0) {
char* t = arr[j]; arr[j] = arr[j+1]; arr[j+1] = t;
}
}
// 使用
char* names[] = {"Jack","rose","TITANIC"};
sortStrings(names, 3, strcmp); // 區分大小寫
sortStrings(names, 3, cmpIgnoreCase); // 忽略大小寫
函數指針使算法與比較策略解耦,是C語言實現多態、回調、插件架構的核心機制。
const char*用於只讀參數。malloc(strlen(s)+1)。strncpy/strncat/snprintf或手動檢查,防緩衝區溢出。掌握字符串的內存語義、生命週期、所有權轉移,是寫出健壯C代碼的分水嶺。