嵌套调用strtok分割字符串出现指针异常的原因咨询
为什么子函数调用
strtok会干扰父函数的strtok状态? 你的问题核心在于**strtok函数的全局状态特性**——它内部维护了一个静态/全局指针,用来记录上一次分割的位置,跨函数调用会互相覆盖这个状态,导致父函数的后续strtok调用偏离预期。
问题根源拆解
strtok的工作逻辑是:
- 第一次调用
strtok(str, delim)时,会扫描str直到找到第一个分隔符,将其替换为\0,返回指向当前片段的指针,同时用内部全局变量记录当前分隔符的下一个位置。 - 后续调用
strtok(NULL, delim)时,不会再传入初始字符串,而是直接从之前记录的位置继续扫描分割。
对应到你的代码流程:
f1中第一次调用strtok(src, "&"),处理原字符串a=1&b=2&c=3,将第一个&替换为\0,返回指向a=1的栈内存指针,同时全局状态指针记录到&的下一个位置(即原字符串中b的地址)。- 调用
f2时,你虽然把src(此时是a=1的指针)复制到了堆内存的dest,但调用strtok(dest, "=")时,strtok会覆盖全局状态指针,将其更新为dest中=的下一个位置(即dest+2,对应1的地址)。 - 回到
f1调用strtok(NULL, "&")时,strtok会使用被f2修改后的全局状态指针,从dest+2的位置开始扫描,而非原字符串的b地址,最终返回的token自然指向了dest的内存区域,也就是你看到的异常地址。
解决方法
要避免这种状态干扰,有两种可靠方案:
方案1:使用可重入版本的strtok
POSIX标准提供strtok_r,C11标准提供strtok_s,它们需要手动传递一个状态指针,每个调用链维护独立的状态,不会互相干扰。
修改后的代码示例:
#include <stdio.h> #include <string.h> #include <stdlib.h> void f2(char *src) { char *dest = (char *)calloc(strlen(src) + 1, sizeof(char)); strcpy(dest, src); char *state; char *token = strtok_r(dest, "=", &state); printf("dest addr: %p token addr: %p \n", dest, token); free(dest); // 修复原代码的内存泄漏问题 } void f1(char *src) { char *state; char *token = strtok_r(src, "&", &state); while (token) { printf("src addr: %p ", token); f2(token); token = strtok_r(NULL, "&", &state); } } TEST(CopyPointer, CopyStrTok) { char str[]="a=1&b=2&c=3"; f1(str); }
方案2:避免嵌套调用strtok
先一次性把所有&分割的结果存储到数组中,再逐个处理每个x=y的分割,这样两个分割流程完全分离,不会交叉干扰strtok的状态。
额外注意
原代码中f2用calloc分配的dest没有释放,会导致内存泄漏,记得在函数结束前调用free(dest)。
内容的提问来源于Stack Exchange,提问作者Davood
相关产品推荐
相关产品推荐

