为什么应该弃用strtok()函数?

16

我听说很多程序员表示,将来可能会弃用使用strtok。有些人说目前仍然可用,为什么它不是一个好的选择呢? strtok()在对给定字符串进行标记化方面表现出色。这是否与时间和空间复杂度有关? 我在互联网上找到的最好链接是这个。但这似乎并不能解决我的好奇心。如果可能的话,请提供任何替代方法。


4
我的观点是,这种方式会误导性地破坏原有的内容。在进行标记化时,通常不希望修改源字符串。请注意,这只是我的个人观点。 - Vality
2
对我来说,一旦我熟悉了使用regcomp和regexec,我发现使用regex(3)更加有用和强大。 - Deathgrip
2
可能是为什么strtok()被认为是不安全的?的重复问题。 - phuclv
2个回答

22
为什么strtok是一个不好的选择?
通过编程解决问题的基本技术是构建抽象,这些抽象可被可靠地用于解决子问题,然后将这些子问题的解决方案组合成更大问题的解决方案。strtok的行为在多种方式上直接违反了这些目标;它是一个糟糕的抽象,不可靠,因为它组合得很差。
分词的根本问题是:给定字符串中的某个位置,找到该位置开始的标记结束的位置。如果strtok只做到这一点,那就太好了。它将拥有清晰的抽象,不依赖隐藏的全局状态,不会修改其输入。
要了解strtok的局限性,请想象尝试对一个希望按空格分隔标记的语言进行分词,除非标记被包含在引号 " " "中,否则我们希望对引号内的内容应用不同的分词规则,然后再按空格分隔规则处理。strtok与自身组合效果非常差,因此仅适用于最简单的分词任务。
与时间和空间复杂度有关吗?
没有。
如果可能的话,请提供任何替代方案。
编写词法分析器并不难,只需编写一个即可!
如果编写一个“不可变词法分析器”,则可以获得额外的加分。不可变词法分析器是一个小结构,其中包含对正在分析的字符串的引用,分析器的当前位置以及分析器所需的任何状态。要提取标记,请调用“下一个标记”方法,传递词法分析器,您将获得标记和一个新的词法分析器。新的词法分析器可以用于解析下一个标记,如果愿意,可以舍弃上一个词法分析器。

不可变的词法分析器技术比修改状态的词法分析器更易于理解。而且你可以通过将已弃用的词法分析器保存在列表中来调试它们,现在你可以一次性地检查所有令牌化操作的完整历史记录。


1
我从未以这种方式看过词法分析器。感谢您提出这个问题。 - Pushan Gupta
1
“它不会修改其输入”在某些常见情况下实际上是无效的;例如,strtok("hello world", " ")对于经验丰富的C程序员来说显然是错误的,但对于初学者来说似乎很好!尽管如此,这对于两者都是一个容易犯的错误。 - autistic
1
虽然这个答案描述了strtok与适当的词法分析器相比的局限性,但我认为它并没有直接解释为什么应该将其弃用(除了简要提到“strtok与自身组合非常差”,而没有解释为什么组合不好)。此外,通常从标准库中弃用的东西都会被替换为其他东西(在strtok的情况下可能是像strtok_rstrtok_s这样的东西)。 - jamesdlin
@jamesdlin 或者使用 strsep,或者使用 strcspn 和 memcpy 作为构建块的某些逻辑。 - Random832
3
@jamesdlin:我鼓励你写一篇更好的答案,这样我们都能从你的见解中受益。 - Eric Lippert

16

strtok(char *str, const char *delim) 的限制在于它无法同时处理多个字符串,因为它维护一个静态指针来存储已解析的索引(因此仅在一次操作一个字符串时使用足够)。更好、更安全的方法是使用 strtok_r(char *str, const char *delim, char **saveptr),它显式地使用第三个指针来保存已解析的索引。


3
换句话说,它本质上修改的不仅是全局状态,还包括隐藏的全局状态! - MooseBoys
4
换句话说,它不是可重入的。 - user207421
6
换句话说,它有很多糟糕的方面 :) - ThingyWotsit

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接