<string.h> 提供的字符串函數是 C 程序員的基本功。本文整理 8 大核心函數的原型、語義、參數要求、返回值與典型陷阱,附帶安全替代建議。
| 函數 | 原型 | 功能 | 關鍵注意點 |
|---|---|---|---|
puts | int puts(const char *s) | 輸出字符串並自動換行 | 僅能輸出單個字符串,末尾自動加 \n |
gets | char *gets(char *s) | 從 stdin 讀取一行(含空格) | 極其危險,C11 已移除,無緩衝區長度檢查,**絕對禁用** |
strcat | char *strcat(char *dest, const char *src) | 拼接字符串 | dest 必須有足夠空間容納結果+\0,不檢查長度 |
strcpy | char *strcpy(char *dest, const char *src) | 複製字符串(含 \0) | 同 strcat,**極易溢出** |
strncpy | char *strncpy(char *dest, const char *src, size_t n) | 最多複製 n 字符 | 若 src 長度 ≥ n,**不自動添加 \0**,需手動 dest[n-1]='\0' |
strcmp | int strcmp(const char *s1, const char *s2) | 字典序比較 | 返回 <0, =0, >0;區分大小寫;strcasecmp 忽略大小寫(POSIX) |
strlen | size_t strlen(const char *s) | 計算字符串長度(不含 \0) | 若無 \0 導致越界讀取,O(n) 時間 |
strlwr | char *strlwr(char *s) | 轉小寫(原地修改) | 非標準(Microsoft 擴展),跨平台請用 tolower 循環 |
strupr | char *strupr(char *s) | 轉大寫(原地修改) | 同 strlwr,非標準 |
| 不安全函數 | 推薦替代 | 來源 |
|---|---|---|
gets | fgets(buf, sizeof(buf), stdin) | C 標準 |
strcpy | strcpy_s / strlcpy (BSD) / snprintf | C11 / BSD / 常用 |
strcat | strcat_s / strlcat / snprintf | C11 / BSD / 常用 |
sprintf | snprintf / sprintf_s | C99 / C11 |
strlwr/strupr | 手寫循環 for(p=s;*p;p++) *p=tolower(*p) | 標準 C |
// ❌ 錯誤:直接賦值字符串字面量給數組
char s[10] = "hello"; // 只能在定義時初始化
s = "world"; // 編譯錯誤:數組不可賦值
// ✅ 正確:用 strcpy/strncpy
strcpy(s, "world");
// ❌ 錯誤:strncpy 不保證以 \0 結尾
char d[5]; strncpy(d, "abcdef", 5); // d = {'a','b','c','d','e'} 無 \0
// ✅ 正確:
strncpy(d, "abcdef", 4); d[4] = '\0';
snprintf、strncpy+手動終止、strncat);strlwr/strupr/strdup 等);sds、bstring)替代手工管理。熟練掌握這些函數的「邊界行為」,是從「能跑通」進入「寫得穩」的關鍵一步。