C 語言字符串與字符處理函數速查手冊
string.h 與 ctype.h 提供了豐富的字符串操作與字符分類函數。本文通過帶註釋的測試代碼,系統梳理常用函數的原型、行為差異與典型用法。
字符串查找與比較
| 函數 | 原型 | 說明 | 返回值 |
strstr | char *strstr(const char *haystack, const char *needle) | 查找 needle 在 haystack 中首次出現的位置 | 匹配地址 / NULL |
strcasestr | char *strcasestr(const char *haystack, const char *needle) | 忽略大小寫查找子串(POSIX 擴展,非標準 C) | 匹配地址 / NULL |
strchr | char *strchr(const char *s, int c) | 查找字符 c 在 s 中首次出現位置 | 匹配地址 / NULL |
strrchr | char *strrchr(const char *s, int c) | 查找字符 c 最後一次出現位置 | 匹配地址 / NULL |
strcmp | int strcmp(const char *s1, const char *s2) | 按字典序(ASCII 值)比較兩字符串 | <0 / =0 / >0 |
strcoll | int strcoll(const char *s1, const char *s2) | 按當前 locale 規則比較(如中文拼音序) | <0 / =0 / >0 |
strncmp | int strncmp(const char *s1, const char *s2, size_t n) | 比較前 n 個字符 | <0 / =0 / >0 |
strnstr | char *strnstr(const char *s1, const char *s2, size_t n) | 在 s1 前 n 字符中查找 s2(BSD 擴展) | 匹配地址 / NULL |
字符串複製與拼接
| 函數 | 原型 | 說明 |
strcpy | char *strcpy(char *dest, const char *src) | 複製含結束符的字符串,**需保證 dest 足夠大** |
strncpy | char *strncpy(char *dest, const char *src, size_t n) | 複製前 n 字符,**不保證以 \0 結尾** |
strdup | char *strdup(const char *s) | 分配內存並複製字符串(POSIX),需 free 釋放 |
strcat | char *strcat(char *dest, const char *src) | 拼接字符串到 dest 末尾 |
strncat | char *strncat(char *dest, const char *src, size_t n) | 拼接前 n 字符 |
stpcpy | char *stpcpy(char *dest, const char *src) | 複製並返回 dest 末尾指針(GNU 擴展) |
strlcpy | size_t strlcpy(char *dst, const char *src, size_t dstsize) | 安全複製,保證以 \0 結尾,返回 src 長度(BSD) |
內存塊操作(不限字符串)
| 函數 | 原型 | 說明 |
memcpy | void *memcpy(void *dest, const void *src, size_t n) | 複製 n 字節,**內存區域不可重疊** |
memmove | void *memmove(void *dest, const void *src, size_t n) | 複製 n 字節,**允許重疊**(內部處理方向) |
memcmp | int memcmp(const void *s1, const void *s2, size_t n) | 比較前 n 字節 |
memset | void *memset(void *s, int c, size_t n) | 設置前 n 字節為字符 c |
memchr | void *memchr(const void *s, int c, size_t n) | 在前 n 字節中查找字符 c |
字符分類與轉換
頭文件 ctype.h,參數為 int(需轉換為 unsigned char 或 EOF),返回非零/零:
| 函數 | 判斷條件 |
isalnum(c) | 字母或數字(isalpha || isdigit) |
isalpha(c) | 字母(A-Z, a-z) |
isdigit(c) | 十進制數字(0-9) |
isxdigit(c) | 十六進制數字(0-9, A-F, a-f) |
islower(c) | 小寫字母 |
isupper(c) | 大寫字母 |
isspace(c) | 空白字符:空格、\t、\n、\v、\f、\r |
isblank(c) | 空格或 \t(C99) |
iscntrl(c) | 控制字符(0x00-0x1F, 0x7F DEL) |
isgraph(c) | 可打印非空白字符(isprint && !isspace) |
ispunct(c) | 標點符號(isgraph && !isalnum) |
isprint(c) | 可打印字符(含空格) |
字符大小寫轉換
int tolower(int c)、int toupper(int c):轉換單字符,非字母原樣返回。
int toascii(int c):c & 0x7F,保留 7 位 ASCII。
實戰測試代碼片段
#include
#include
#include
int main() {
printf("strstr: %s\n", strstr("China is good", "is")); // "is good"
printf("strcasestr: %s\n", strcasestr("fFDsafds", "D")); // "Dsafds"
printf("strchr: %s\n", strchr("abcdefghijklmnopqrstuvwxyz", 'c')); // "cdef..."
printf("strcmp: %d\n", strcmp("abc", "abd")); // -1
printf("strcoll: %d\n", strcoll("China", "As")); // locale 相關
printf("strcspn: %zu\n", strcspn("China is good", "in")); // 1 (首字符 'C' 不在 "in" 中)
printf("memcmp: %d\n", memcmp("avc", "dds", 1)); // 'a' - 'd' < 0
printf("isalnum('$'): %d\n", isalnum('$')); // 0
printf("isblank(' '): %d\n", isblank(' ')); // 1
printf("iscntrl('\\n'): %d\n", iscntrl('\n')); // 1
printf("isgraph('$'): %d\n", isgraph('$')); // 1
printf("ispunct('a'): %d\n", ispunct('a')); // 0
printf("isspace('a'): %d\n", isspace('a')); // 0
printf("toascii('a'): %d\n", toascii('a')); // 97
printf("isascii(130): %d\n", isascii(130)); // 0 (超出 0-127)
return 0;
}
避坑指南
- 緩衝區溢出:
strcpy/strcat 不檢查目標大小 → 用 strncpy/strncat 或 strlcpy/snprintf。
strncpy **不自動添加 \0** → 手動設置 dest[n-1] = '\0'。
ctype.h 函數參數**必須轉換**:isalpha((unsigned char)ch),否則負值導致未定義行為。
strcasestr/strnstr/strdup/strlcpy 非標準 C → 跨平台項目需自行實現或用 #ifdef 兼容。
- locale 影響
strcoll/isalpha 等 → 多語言環境需显式 setlocale。
將常用函數原型、返回值、副作用內化為肌肉記憶,是高效編寫安全 C 字符串代碼的關鍵。