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

C語言字符串分割完全指南:strtok 用法、陷阱與自定義實現對比

     編輯:關於C語言

標準庫 strtok 快速上手

char *strtok(char *str, const char *delim);
  • 首次調用:傳入待分割字符串 str,函數內部靜態記錄位置。
  • 後續調用:str 傳 NULL,繼續從上次位置分割。
  • 分隔符:delim 中任意字符均視為分隔符,連續分隔符被視為一個,不產生空串。
  • 返回值:下一個 token 指針(指向原字符串內部),無則返回 NULL。

標準用法示例

char s[] = "abc,def;ghi";  // 必須可修改數組,不可用字面量
char *d = ",;";
char *t = strtok(s, d);
while (t) {
    puts(t);
    t = strtok(NULL, d);  // 關鍵:傳 NULL 繼續分割
}
// 輸出:abc / def / ghi

⚠️ 三大核心陷阱

  1. 破壞原字符串:strtok 會在分隔符處寫入 \0,原字符串被切碎。需分割副本:char *copy = strdup(s);。
  2. 非線程安全:內部靜態狀態,多線程調用會互相干擾。C11 提供 strtok_s,POSIX 有 strtok_r(需 _GNU_SOURCE)。
  3. 分隔符語義差異:delim="##" 視為 '#' 和 '#' 兩個單字符分隔符,而非子串 "##"。若需按子串分割,strtok 無能為力。

自定義分割函數:支援多字符分隔符

作者原版實現(按完整匹配分隔符串分割):

void strsplit(const char *str, const char *delim,
              void (*visitor)(const char *, int start, int end)) {
    int s_len = strlen(str), d_len = strlen(delim);
    int k_s = 0, k_e = 0;
    while (k_e < s_len) {
        if (k_e + d_len <= s_len && strncmp(str + k_e, delim, d_len) == 0) {
            if (k_e > k_s) visitor(str, k_s, k_e);  // 回調處理 token
            k_s = k_e = k_e + d_len;                // 跳過整個分隔符串
        } else {
            k_e++;
        }
    }
    if (k_e > k_s) visitor(str, k_s, k_e);  // 尾部 token
}

關鍵差異:strtok("a##b", "#") → "a", "b";自定義 strsplit("a##b", "##") → "a", "b";但 strsplit("a#b", "##") → "a#b" (無分割),而 strtok 會分割。

改造為類 strtok 行為(單字符分隔符集合)

只需將跳過邏輯改為 k_e++; k_s = k_e; 即可實現「任意分隔符字符單獨切分」語義。

總結選型建議

場景推薦方案
單線程、簡單分隔符、可修改原串strtok 最簡潔
多線程 / 需保留原串strtok_r / strtok_s 或手寫
多字符分隔符串(如 "::" "--")手寫 strsplit 或 strstr 循環
高性能解析(如 CSV、日志)手寫狀態機,避免函數調用開銷
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved