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

如何实现不修改原字符串、返回新token的自定义strtok函数

不修改原字符串的strtok实现方案

现有代码问题

  • 直接在原字符串的分隔符位置写入\0截断字符串,必然修改原输入内容
  • 仅通过静态变量存储原字符串指针和扫描位置,没有对原串做备份,无法避免修改原串的问题

实现思路

要满足无需上层拷贝缓冲区、不修改原串、返回独立token的要求,调整逻辑如下:

  1. 首次调用(传入非空s2)时,内部先拷贝完整的原字符串到动态申请的内存中,完全隔离对原串的修改
  2. 扫描到分隔符时,不再修改原串,而是根据当前扫描的起始位置到分隔符前的长度,单独申请内存存储子串作为返回的token
  3. 扫描结束后自动释放内部存储的原串拷贝,避免常驻内存泄漏

修改后的完整代码

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

char *my_strtok(char *s2, char *delimit);

int main()
{
    char arr1[50] = {"abc-efgh-ijkl-mnopq"}; 
    // 上层不再需要手动拷贝缓冲区
    char *split  = my_strtok(arr1, "-");
   
    while(split != NULL)
    {
        printf("%s\t", split);
        free(split); // 注意:返回的token是动态申请的,用完需要释放避免内存泄漏
        split = my_strtok(NULL, "-");
    }
   
    // 可验证原字符串完全未被修改
    printf("\n原字符串保留为:%s\n", arr1);
    return 0;
}

char *my_strtok(char *s2, char *delimit)
{
    static int curr; // 记录当前扫描位置
    static char *s = NULL; // 内部存储原串的拷贝
    int start = curr;
    int token_len = 0;

    // 首次调用,初始化内部拷贝
    if(s2 != NULL)
    {
        // 释放之前可能存在的旧拷贝,避免内存泄漏
        if(s != NULL)
        {
            free(s);
            s = NULL;
        }
        curr = 0;
        start = 0;
        // 拷贝原串到内部申请的内存,完全不触碰原串
        s = (char*)malloc(strlen(s2) + 1);
        strcpy(s, s2);
    }

    // 没有可扫描的内容直接返回NULL
    if(s == NULL || s[curr] == '\0')
    {
        return NULL;
    }

    while(s[curr] != '\0')
    {
        int j = 0;
        int is_delimiter = 0;
        // 判断当前字符是否是分隔符
        while(delimit[j] != '\0')
        {
            if(s[curr] == delimit[j])
            {
                is_delimiter = 1;
                break;
            }
            j++;
        }

        if(is_delimiter)
        {
            token_len = curr - start;
            curr++;
            // 跳过连续的分隔符
            if(token_len == 0)
            {
                start = curr;
                continue;
            }
            // 申请独立内存存储token
            char *token = (char*)malloc(token_len + 1);
            strncpy(token, s + start, token_len);
            token[token_len] = '\0';
            start = curr;
            return token;
        }
        curr++;
    }

    // 处理最后一个token
    token_len = curr - start;
    if(token_len <= 0)
    {
        free(s);
        s = NULL;
        return NULL;
    }
    char *token = (char*)malloc(token_len + 1);
    strncpy(token, s + start, token_len);
    token[token_len] = '\0';
    // 扫描结束,释放内部缓冲区
    free(s);
    s = NULL;
    return token;
}

注意事项

  • 该实现返回的每个token都是独立申请的堆内存,上层使用完后必须调用free()释放,否则会出现内存泄漏
  • 静态变量的使用会导致函数不可重入,如果需要多线程安全的实现,可以把内部状态(当前扫描位置、内部串拷贝)封装到结构体中,由上层传入状态指针使用

内容的提问来源于stack exchange,提问作者sanchi gupta

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.01 13:24:06