前言
C/C++ 標準庫提供豐富的字串與字符處理函數,分散於 <ctype.h>、<stdio.h>、<stdlib.h>、<string.h> 四大標頭檔。本文系統整理各分類核心函數、原型、用途與常見陷阱,供開發時快速查閱。
一、<ctype.h> 字符分類與轉換
所有函數原型:int func(int c),參數為 unsigned char 或 EOF 轉換後的 int。注意:傳入 `char` 可能為負值導致未定義行為,正確用法:func((unsigned char)ch)。
| 函數 | 功能 | 返回值(非零=真) |
isalnum(c) | 字母或數字 | 字母/數字 |
isalpha(c) | 字母 | A-Z, a-z |
iscntrl(c) | 控制字符 | \\n, \\t, \\r 等 |
isdigit(c) | 十進制數字 | 0-9 |
isgraph(c) | 可見字符(非空白) | !~ 等 |
islower(c) | 小寫字母 | a-z |
isprint(c) | 可列印字符(含空格) | 空格 + isgraph |
ispunct(c) | 標點符號 | 非字母數字、非空白 |
isspace(c) | 空白字符 | \\n, \\t, \\v, \\f, \\r, 空格 |
isupper(c) | 大寫字母 | A-Z |
isxdigit(c) | 十六進制數字 | 0-9, A-F, a-f |
tolower(c) | 轉小寫 | 轉換後字符 |
toupper(c) | 轉大寫 | 轉換後字符 |
二、<stdio.h> 字符/字串輸入輸出
| 函數 | 原型 | 說明 |
getchar | int getchar(void) | 讀取單字符,返回 int(含 EOF) |
gets | char *gets(char *s) | 已棄用/移除(C11),緩衝區溢位風險,改用 fgets |
putchar | int putchar(int c) | 輸出單字符 |
puts | int puts(const char *s) | 輸出字串並自動換行 |
sprintf | int sprintf(char *s, const char *fmt, ...) | 格式化寫入字串緩衝區(注意緩衝區大小) |
sscanf | int sscanf(const char *s, const char *fmt, ...) | 從字串按格式讀取 |
snprintf | int snprintf(char *s, size_t n, const char *fmt, ...) | 安全版 sprintf,指定最大寫入長度 |
三、<stdlib.h> 字串轉數值
| 函數 | 原型 | 說明 | 備註 |
atoi | int atoi(const char *nptr) | 字串→int | 無錯誤檢測,錯誤返回 0 |
atol | long atol(const char *nptr) | 字串→long | 同 atoi |
atof | double atof(const char *nptr) | 字串→double | 支援科學記號 |
strtol | long strtol(const char *nptr, char **endptr, int base) | 字串→long,支援 2-36 進制 | 推薦,可檢測錯誤 |
strtoul | unsigned long strtoul(...) | 字串→unsigned long | 同上 |
strtod | double strtod(const char *nptr, char **endptr) | 字串→double | 可檢測錯誤 |
strtol 關鍵行為
base=0:自動偵測前綴(0x→16 進制,0→8 進制,否則 10 進制)。
endptr:若非 NULL,指向第一個無效字符,便於檢查是否完整轉換。
- 溢位時返回
LONG_MAX/LONG_MIN 並設 errno=ERANGE。
四、<string.h> 字串與記憶體操作
1. 複製/連接
| 函數 | 原型 | 關鍵差異 |
strcpy | char *strcpy(char *dest, const char *src) | 複製含 \\0,dest 需足夠大 |
strncpy | char *strncpy(char *dest, const char *src, size_t n) | 複製 n 字符,**不保證以 \\0 結尾** |
strcat | char *strcat(char *dest, const char *src) | 接在 dest 尾部,需空間足夠 |
strncat | char *strncat(char *dest, const char *src, size_t n) | 最多接 n 字符,**保證以 \\0 結尾** |
2. 比較
strcmp(s1,s2):逐字符比較,返回 <0, =0, >0。
strncmp(s1,s2,n):比較前 n 字符。
3. 查找
| 函數 | 功能 | 返回值 |
strchr(s,c) | 尋找字符 c 首次出現 | 指針或 NULL |
strrchr(s,c) | 尋找字符 c 最後出現 | 指針或 NULL |
strstr(s1,s2) | 尋找子串 s2 首次出現 | 指針或 NULL |
strspn(s1,s2) | s1 開頭連續屬於 s2 的長度 | size_t |
strcspn(s1,s2) | s1 開頭連續**不**屬於 s2 的長度 | size_t |
strpbrk(s1,s2) | 尋找 s1 中首個屬於 s2 的字符 | 指針或 NULL |
strtok(s1,s2) | 以 s2 字符集分割 s1,**會修改 s1** | 下次呼叫傳 NULL 續切 |
4. 記憶體操作(針對任意二進制區塊)
| 函數 | 原型 | 關鍵點 |
memcpy | void *memcpy(void *dest, const void *src, size_t n) | src/dest **不可重疊** |
memmove | void *memmove(void *dest, const void *src, size_t n) | **可重疊** 安全複製 |
memcmp | int memcmp(const void *s1, const void *s2, size_t n) | 比較前 n 位元組 |
memchr | void *memchr(const void *s, int c, size_t n) | 前 n 位元組找字符 c |
memset | void *memset(void *s, int c, size_t n) | 填充位元組值,**僅適用字符/0 初始化** |
5. 其他
strlen(s):返回字符數(不含 \\0),size_t。
strerror(errnum):返回錯誤碼對應訊息字串。
常見坑總結
- gets 已移除,嚴禁使用,改用
fgets(buf, sizeof(buf), stdin)。
- strncpy 不補 \\0,複製後手動
dest[n-1] = '\\0'。
- atoi 族無錯誤回報,轉換失敗靜默返回 0,改用
strtol/strtod 檢查 endptr。
- ctype 函數參數必須轉 unsigned char,否則負值字符導致 UB。
- strtok 非執行緒安全且修改原字串,多執行緒用
strtok_r (POSIX) 或 C++ stringstream/std::string::find。
- memset 僅按位元組填充,不可用於初始化 int 陣列為非 0/-1 值(位元組模式重複)。