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

嵌套调用strtok分割字符串出现指针异常的原因咨询

为什么子函数调用strtok会干扰父函数的strtok状态?

你的问题核心在于**strtok函数的全局状态特性**——它内部维护了一个静态/全局指针,用来记录上一次分割的位置,跨函数调用会互相覆盖这个状态,导致父函数的后续strtok调用偏离预期。

问题根源拆解

strtok的工作逻辑是:

  1. 第一次调用strtok(str, delim)时,会扫描str直到找到第一个分隔符,将其替换为\0,返回指向当前片段的指针,同时用内部全局变量记录当前分隔符的下一个位置。
  2. 后续调用strtok(NULL, delim)时,不会再传入初始字符串,而是直接从之前记录的位置继续扫描分割。

对应到你的代码流程:

  1. f1中第一次调用strtok(src, "&"),处理原字符串a=1&b=2&c=3,将第一个&替换为\0,返回指向a=1的栈内存指针,同时全局状态指针记录到&的下一个位置(即原字符串中b的地址)。
  2. 调用f2时,你虽然把src(此时是a=1的指针)复制到了堆内存的dest,但调用strtok(dest, "=")时,strtok会覆盖全局状态指针,将其更新为dest中=的下一个位置(即dest+2,对应1的地址)。
  3. 回到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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 13:30:55