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

C语言strtok函数工作原理及常见使用问题答疑

问题1:为什么将line-id(01)处代码改为printf("%s",*p)会触发段错误?p是指针,不是应该用*p获取指向的值吗?

printf的%s格式符要求传入的参数是char类型指针,指向待打印字符串的首地址,printf会从这个地址开始逐字符读取,直到遇到\0停止。
p本身就是char*类型,值就是字符串首地址,直接传p才符合%s的要求。而*p是对指针解引用,拿到的是p指向的第一个字符(比如第一次调用后*p就是字符h,对应的ASCII码值是十进制104),把这个数值当成内存地址传给%s时,printf会尝试访问0x68(即十进制104)这个低地址空间,该空间属于操作系统保护区域,用户进程无访问权限,因此触发段错误。
如果要打印单个字符,应该用%c格式符,此时才需要传*p。

问题2:为什么取消line-id(00)处注释执行printf("%s",a)时仅输出hey?

strtok是原地修改输入字符串的函数:第一次调用strtok(a,"-")时,会从数组a的首地址开始查找第一个分隔符-,找到后会把该位置的-替换为字符串结束符\0。
printf用%s输出数组a时,会从首地址开始读,遇到第一个\0就终止输出,因此只会输出\0之前的内容,也就是第一个切分结果hey(根据原字符串定义可能附带后面的空格)。

问题3:strtok函数中指针p的作用,以及strtok的完整工作机制

指针p的作用

strtok每次调用的返回值是当前切分出的子串(token)的首地址,如果没有更多可切分的子串则返回NULL。指针p的作用就是接收这个返回值,用来遍历所有切分得到的子串。

strtok完整工作机制

strtok内部维护了一个静态全局指针,用来记录上次切分后剩余字符串的起始位置,工作流程分为两类调用场景:

  1. 首次调用:第一个参数传入待切分字符串的首地址,第二个参数传入分隔符集合。
    • 从传入的字符串首地址开始,先跳过所有属于分隔符集合的字符,找到第一个非分隔符的位置作为当前token的首地址
    • 继续向后查找,直到找到第一个属于分隔符集合的字符,将该字符替换为\0
    • 把内部静态指针更新为该分隔符后面的第一个字符的地址
    • 返回当前token的首地址
  2. 后续调用:第一个参数传入NULL,第二个参数可以和之前相同或者更换分隔符集合。
    • 直接从内部静态指针记录的位置开始,重复上面的查找、替换、更新静态指针的逻辑,返回当前token的首地址
    • 如果查找至字符串末尾\0仍未找到可切分的token,则返回NULL

补充说明:

  • strtok会修改原字符串,因此不能传入只读的字符串常量作为切分对象,否则会触发段错误
  • 内部静态指针的存在导致strtok不可重入,不能同时对多个字符串进行切分操作,多线程环境下也存在线程安全问题,这种场景建议使用可重入版本strtok_r
    你提供的代码中第二次切分输出不符合预期,就是因为第一次切分已经把原字符串的第一个-替换成了\0,第二次调用strtok(a,"*")时,扫描到这个\0也没找到*,只能返回第一个tokenhey ,后续没有更多有效内容就返回NULL结束循环。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.04 20:39:03