如何实现从字符串提取Token并同步修改原字符串?
如何实现每次调用返回第一个Token并修改原字符串的功能
你的思路方向是对的,但用strtok的方式有问题——因为strtok第一次调用需要传入目标字符串,后续调用必须传NULL才能继续分割剩余的内容,而你的函数每次都把str传给strtok,导致每次都会从头开始分割,达不到“每次取下一个Token”的效果。
下面给你两种可行的实现方案,分别适合不同场景:
方案1:用静态变量跟踪剩余字符串(单线程场景)
这个方案用静态变量在函数内部记住上次分割后的剩余位置,调用起来比较简洁,但因为静态变量的存在,不适合多线程或者同时分割多个字符串的场景:
#include <stdio.h> #include <string.h> char *tokeniz(char *str) { static char *remaining = NULL; // 如果传入新的字符串,重置剩余位置指针 if (str != NULL) { remaining = str; } // 没有剩余字符了,返回NULL if (remaining == NULL || *remaining == '\0') { return NULL; } // 跳过开头的连续空格(避免返回空Token) while (*remaining == ' ') { remaining++; } // 记录当前Token的起始位置 char *token_start = remaining; // 找到下一个空格的位置 while (*remaining != ' ' && *remaining != '\0') { remaining++; } // 如果不是到字符串末尾,把空格替换成'\0'(截断当前Token),并移动指针到下一个字符 if (*remaining != '\0') { *remaining = '\0'; remaining++; } return token_start; } int main() { // 注意:必须用字符数组,不能用字符串常量(比如char *str = "Hi..."),因为要修改原字符串 char str[] = "Hi my name is"; char *tok; // 第一次调用传入原字符串 tok = tokeniz(str); while (tok != NULL) { printf("当前Token: %s\n", tok); // 后续调用传入NULL,获取下一个Token tok = tokeniz(NULL); } // 此时原字符串已经被修改,可以查看剩余部分 printf("剩余字符串: %s\n", str + strlen(str) + 1); return 0; }
方案2:通过指针参数跟踪剩余位置(线程安全/多场景通用)
这个方案把剩余位置的控制权交给调用者,不用静态变量,更安全灵活,适合多线程或者同时处理多个字符串的情况:
#include <stdio.h> #include <string.h> char *tokeniz(char **remaining) { // 参数合法性检查 if (remaining == NULL || *remaining == NULL || **remaining == '\0') { return NULL; } // 跳过开头的连续空格 while (**remaining == ' ') { (*remaining)++; } char *token_start = *remaining; // 找到下一个空格的位置 while (**remaining != ' ' && **remaining != '\0') { (*remaining)++; } // 截断当前Token并移动剩余指针 if (**remaining != '\0') { **remaining = '\0'; (*remaining)++; } return token_start; } int main() { char str[] = "Hi my name is"; char *remaining = str; char *tok; // 循环获取所有Token while ((tok = tokeniz(&remaining)) != NULL) { printf("当前Token: %s\n", tok); } // 此时remaining指向最后一个Token之后的位置 printf("剩余字符串: %s\n", remaining); return 0; }
重要注意事项
- 不要用字符串常量:比如
char *str = "Hi my name is"这种字符串是只读的,修改它会导致未定义行为,必须用char str[] = "Hi my name is"这种可修改的字符数组。 - 如果想用标准库函数,也可以考虑
strtok_r(POSIX系统)或strtok_s(Windows系统),它们是strtok的可重入版本,原理和方案2类似,需要传递一个指针来保存剩余位置。
内容的提问来源于stack exchange,提问作者fdev
相关产品推荐
相关产品推荐

