在 C 語言中處理字串分割一直是初學者的痛點。標準庫提供的 strtok 雖然功能強大,但存在修改原字串、非執行緒安全等特性,使用時需格外小心。本文將詳細解析其原型、行為、原始碼邏輯,並提供測試範例與現代替代方案 strsep。
char *strtok(char *strToken, const char *strDelimit);
| 參數 | 說明 |
|---|---|
strToken | 待分割的字串。首次呼叫傳入字串指標,後續呼叫必須傳入 NULL。 |
strDelimit | 分隔符字元集合。字串中任一字元皆視為分隔點。 |
回傳值: 指向下一個 token 的指標;若無更多 token 則回傳 NULL。
NULL。'\0',導致原字串被切斷。___strtok 保存狀態,多執行緒環境下會相互干擾。核心流程如下:
char * ___strtok 指向下次搜尋起始位置。strToken != NULL,重置搜尋起點為該字串;否則沿用 ___strtok。'\0',更新 ___strtok 指向下一字元,回傳 token 起始位址。___strtok 設為 NULL。這也解釋了為何連續分隔符會被視為單一分隔(空 token 被跳過)。
#include <string.h>
#include <stdio.h>
#include <Windows.h>
char string[] = "A string\tof ,,tokens\nand some more tokens";
char seps[] = " ,\t\n";
char chinese[] = "中國,吃飯";
char *token;
int main(void) {
printf("英文測試:\n");
token = strtok(string, seps);
while (token != NULL) {
printf(" %s\n", token);
token = strtok(NULL, seps);
}
printf("原字串: %s\n", string); // 輸出 "A",證明原字串已改變
printf("\n中文測試:\n");
token = strtok(chinese, ",");
while (token != NULL) {
printf("%s\n", token);
token = strtok(NULL, ",");
}
system("pause");
return 0;
}
輸出結果:
英文測試:
A
string
of
tokens
and
some
more
tokens
原字串: A
中文測試:
中國
吃飯
測試證明:
','。string 僅剩首字元 "A",其餘被 '\0' 截斷。警告:
strtok is deprecated, use strsep instead.—— Linux 2.6.29+ 已棄用strtok。
| 特性 | strtok | strsep |
|---|---|---|
| 連續分隔符處理 | 合併視為一個(跳過空 token) | 保留空 token(回傳空字串) |
| 執行緒安全 | 否(靜態變數) | 是(狀態由呼叫者傳遞) |
| 修改原字串 | 是 | 是 |
| Windows 支援 | 有 | 無(需自行實作) |
若在 Visual Studio 等 Windows 環境開發,可參考開源實作(如 BSD 原始碼)自行加入 strsep,或使用 strtok_s(C11 標準,Microsoft 實作為 strtok_s)作為較安全的替代。
strtok 仍可用但需加註解警示。strsep(Linux)或 strtok_s(跨平台/C11)。libcsv、cJSON 等)。std::stringstream + std::getline 或 Boost.Tokenizer。strtok 是 C 語言早期的字串分割利器,理解其「破壞性、狀態保持、非執行緒安全」三大特性至關重要。現代開發應逐步遷移至 strsep 或更安全的替代方案,並在跨平台專案中妥善處理相容性問題。