如何实现不修改原字符串、返回新token的自定义strtok函数
不修改原字符串的strtok实现方案
现有代码问题
- 直接在原字符串的分隔符位置写入
\0截断字符串,必然修改原输入内容 - 仅通过静态变量存储原字符串指针和扫描位置,没有对原串做备份,无法避免修改原串的问题
实现思路
要满足无需上层拷贝缓冲区、不修改原串、返回独立token的要求,调整逻辑如下:
- 首次调用(传入非空
s2)时,内部先拷贝完整的原字符串到动态申请的内存中,完全隔离对原串的修改 - 扫描到分隔符时,不再修改原串,而是根据当前扫描的起始位置到分隔符前的长度,单独申请内存存储子串作为返回的token
- 扫描结束后自动释放内部存储的原串拷贝,避免常驻内存泄漏
修改后的完整代码
#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
相关产品推荐
相关产品推荐

