You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何实现从字符串提取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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.26 11:14:07