c - strtok_r 保存状态行为
问题描述
正确的使用strtok_r
方法如下:
char* str = strdup(string);
char* save;
char* ptr = strtok_r(str, delim, &save);
while(ptr) {
puts(ptr);
ptr = strtok_r(NULL, delim, &save);
}
当试图检查实际存储的内容时save
,我发现它只是未解析字符串的其余部分。所以我试图让第二个调用看起来像第一个,并编写了一个包装器,如下所示。
char* as_tokens(char** str, const char* const delim) {
return strtok_r(NULL, delim, str);
}
这可以像下面这样使用,它不那么冗长。我们不必区分第一次呼叫和休息。
char* str = strdup(string);
char* ptr;
while(ptr = as_tokens(&str, delim))
puts(ptr);
这种方法有什么缺点吗?我是否导致任何未定义的行为?我尝试了一些极端情况,两种方法的工作方式相似。
在线编译器:https ://wandbox.org/permlink/rkGiwXOUTzqrbMpP
PS 为简洁起见忽略内存泄漏。
更新
已经存在一个与我的as_tokens
: strsep几乎相似的函数。在有连续分隔符的情况下有所不同。strsep
返回一个空字符串,而as_tokens
(即 strtok_r)将它们视为一个。
解决方案
这种方法有什么缺点吗?
是的,它失去了 的原始值str
,使得(在这种情况下)无法释放它。因此,您有内存泄漏。这可以通过保留指针的单独副本来解决,但这归结为与您的第一个代码几乎相同的事情。
此外,正如评论中所观察到的,它不符合规范,即使用第一个参数strtok_r
调用的行为仅在先前调用的上下文中定义,该调用提供了第三个参数指向的值。strtok_r
NULL
strtok_r
此外,它偏离了惯用的、易于理解的 . 用法strtok_r
,甚至将其隐藏在不同的函数中。正常的成语不繁琐,人尽皆知。聪明一点会让你的代码更难维护。
我是否导致任何未定义的行为?
是的,在“未定义的行为”的意义上,与明确称为未定义的行为相反。但相关标准赋予这些替代品同样的意义。看上面。
推荐阅读
- grails - Json 文件解析 - Groovy
- sql - SQL 查询从当前日期每周显示日期
- javascript - 因此返回一个 JSX 必然会使函数成为一个组件?
- typescript - NPM 仅安装后依赖项
- javascript - 污染的画布 - 但仅在一台 Windows 10 Chrome PC 上
- python - 我需要一个类似于 pygtrie.PrefixSet 在 python 中的 PrefixMap
- java - KafkaConsumer.commitSync/commitAsync 是否可以提交未分配分区的偏移量
- docker - Docker 通过 ssh 连接到远程守护进程 - 权限被拒绝(公钥)
- prometheus - 两个具有相同数据存储库的 Prometheus
- javascript - 垃圾收集内联事件