首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> C >> 關於C

C語言字符串操作完全手冊:標準庫函數深度解析與工程避坑指南

     編輯:關於C

字符串本質:以 NUL 結尾的字節序列

C 語言無內置字符串類型,字符串本質是 char* 指向的內存區域,以 '\0'(NUL,ASCII 0)標記結束。所有標準庫字符串函數均依賴此約定,**缺失 NUL 將導致未定義行為(緩衝區溢出、無限循環)**。

核心函數詳解

1. strlen:長度計算(不含 NUL)

size_t strlen(const char *s);
  • 遍歷直到 NUL,時間複雜度 O(n)
  • 頻繁調用時應緩存結果:size_t len = strlen(s);
  • 返回 size_t(無符號),比較時注意類型轉換

2. strcmp/strncmp:字典序比較

int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);
  • 返回 0:相等;< 0:s1 < s2;> 0:s1 > s2
  • 僅比較字節值,非本地化感知(不處理多字節字符、排序規則)
  • 常用模式:if (strcmp(a, b) == 0) 或 if (!strcmp(a, b))
  • strncmp 限制比較前 n 字符,適合前綴匹配

3. strcat/strncat:拼接(極易緩衝區溢出)

char *strcat(char *dest, const char *src);
char *strncat(char *dest, const char *src, size_t n);
  • 不檢查 dest 容量,必須確保 dest 足夠大
  • strncat 追加 src 前 n 字符,保證結果以 NUL 結尾
  • 安全替代:snprintf(dest, size, "%s%s", dest, src) 或手動檢查剩餘空間
  • 返回 dest,支持鏈式調用

4. strchr/strrchr:字符查找

char *strchr(const char *s, int c);     // 首次出現
char *strrchr(const char *s, int c);    // 最後出現
  • 參數 c 為 int 但按 unsigned char 解釋
  • 返回指向字符的指針,未找到返回 NULL
  • 查找所有出現:for (p=strchr(s,c); p; p=strchr(p+1,c))

5. strcpy/strncpy:複製(經典陷阱)

char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);
  • strcpy:複製直到 NUL,**不檢查邊界**
  • strncpy:複製前 n 字符,**若 src 短於 n,補 NUL 到 n;若 src ≥ n,結果不以 NUL 結尾**
  • 安全模式:strncpy(dest, src, n-1); dest[n-1] = '\0';
  • 現代推薦:snprintf(dest, n, "%s", src) 保證 NUL 結尾

6. strspn/strcspn:字符集跨度

size_t strspn(const char *s, const char *accept);   // 首個不在 accept 中的下標
size_t strcspn(const char *s, const char *reject);  // 首個在 reject 中的下標
  • 常用於分詞、驗證、跳過空白:s += strspn(s, " \t\r\n");

7. strstr:子串查找

char *strstr(const char *haystack, const char *needle);
  • 返回 needle 在 haystack 中首次出現位置,未找到返回 NULL
  • 非 KMP 算法,極端情況 O(mn),長文本建議用 Boyer-Moore 或標準庫 memmem (GNU 擴展)

8. strtok:分詞器(有狀態、破壞原串、非線程安全)

char *strtok(char *str, const char *delim);
  • 首次調用傳 str,後續傳 NULL 繼續分割
  • 修改原字符串(將分隔符替換為 NUL)
  • 標準模式:
    char *token;
    if ((token = strtok(str, " ,.!?")) != NULL) {
        do {
            printf("Token: %s\n", token);
        } while ((token = strtok(NULL, " ,.!?")) != NULL);
    }
  • 線程安全替代:strtok_r (POSIX) / strtok_s (C11 Annex K)

工程級避坑清單

陷阱後果對策
目標緩衝區過小緩衝區溢出、安全漏洞使用 snprintf、strlcpy/strlcat (BSD)、檢查長度
字符串無 NUL 結尾讀越界、無限循環初始化置零、strncpy 後手動加 NUL、靜態分析工具
strncpy 不補 NUL後續函數誤讀垃圾數據dest[n-1] = '\0' 或改用 snprintf
strtok 破壞原串原數據不可用、多線程衝突傳入副本 strdup(s),或用 strtok_r
字符串字面量修改段錯誤(只讀段)char s[] = "lit" 而非 char *s = "lit"
有符號/無符號比較邏輯錯誤(如 strlen(s) > -1 恆真)統一用 size_t,編譯器警告 -Wsign-compare

現代替代方案

  1. C11 Annex K (Bounds-checking interfaces):strcpy_s、strcat_s、strtok_s 等,需定義 __STDC_WANT_LIB_EXT1__
  2. BSD strlcpy/strlcat:保證 NUL 結尾,返回源長度,廣泛可用
  3. 動態字符串庫:sds (Redis)、bstring、CString (Glib) —— 管理長度、容量、自動擴容
  4. C++ std::string:混合編程時優先選擇

性能優化提示

  • 編譯器內建函數:__builtin_strlen 等,常優化為 SIMD 指令
  • 對齊訪問:確保緩衝區對齊,利用向量化指令
  • 避免重複掃描:len = strlen(s); 緩存,而非循環中反覆調用
  • 大規模文本處理:考慮 mmap + memchr/memmem 避免拷貝

字符串操作是 C 語言安全漏洞的高發區。內化「NUL 終結、長度檢查、副本隔離」三大原則,善用現代安全 API,才能在享受 C 效率的同時守住底線。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved