【问题标题】:does sscanf() delete characters from stdin when %*[^|] delimiter used?使用 %*[^|] 分隔符时,sscanf() 会从标准输入中删除字符吗?
【发布时间】:2015-12-08 15:00:59
【问题描述】:

根据 sscanf() 的手册页,* 字符

可选的 '*' 赋值抑制字符:scanf() 读取输入 按照转换规范的指示,但丢弃输入。

据此,我(对吗?)假设像

sscanf(string,"%*[^|]%*c%[^|]%*c", vars)

将接受输入“text|neededtext|”,忽略第一个“|”之前的所有文本(即从标准输入中删除它?),忽略(并从标准输入中删除)下一个字符,即“|”存储“neededtext”,然后删除最后的“|”字符,让标准输入为空? 如果是,那么是否需要在此 sscanf() 调用之后运行清理函数,以捕获一些奇怪的异常以防万一出现问题,或者上面的代码是否总能保证工作?

我已经运行了一些测试,看起来 sscanf() 确实吃掉了标准输入中的所有字符,但我只是想确定一下。

【问题讨论】:

  • 您的分析大部分是正确的,只是您查看的是从字符串读取的sscanf(),而不是“stdin”!此外,sscanf() 严格来说是非破坏性的;它不会改变其输入字符串。可能还有一个换行符。您应该测试来自sscanf() 的返回值,以确保它获得了数据(如果之前没有管道,则返回 0)。不能直接判断后面的管道是否匹配。
  • 啊,当然,谢谢!是的,当然 sscanf 从字符串中读取,而我使用的 fgets 将从标准输入中读取
  • 确保您遵循@JonathanLeffler 的建议并检查来自sscanf 的回报。 scanfsscanf 的错误处理基于成功匹配和分配的输入项的数量。您使用* 丢弃输入允许在不增加匹配计数的情况下跳过输入。如果您不检查退货,则最初无法知道您是否真的拥有您认为拥有的东西......
  • 谢谢,这正是我正在做的,检查输入并填充以适应格式,然后检查来自 sscanf 的返回值。谢谢你的建议。

标签: c stdin delimiter scanf


【解决方案1】:

并非总是如此。见#2

@Jonathan Leffler 评论说,sscanf() 与字符串一起使用,不会影响 stdin。让我们假设问题是关于 *scanf() 家族的。

*scanf(string,"%*[^|]%*c%[^|]%*c", vars) 的问题

  1. 代码不检查*scanf() 的结果。这会导致微妙的检测问题。最好写一张支票。

    char vars[100];
    if (sscanf(string,"%*[^|]%*c%99[^|]%*c", vars) != 1) Handle_Error();
    
  2. "%*[^|]" 不扫描任何内容,如果前导字符为 '|',则停止整个扫描功能。 "%*[^|]" 扫描 1 个或多个非'|',而不是 0 个或多个。因此,上面的“并非总是”。使用 scanf(),不会消耗任何字符 - 它们保留在 stdin 中。

  3. "%*[^|]" 之后继续扫描的唯一可能字符是'|'。最好编码"%*[^|]%|"而不是"%*[^|]%*c"

  4. sscanf()scanf()fscanf() 的不同之处在于后者可以扫描并保存一个空字符'\0'sscanf() 在到达空字符时停止扫描。 IMO:应避免将"%s""%[^...]fscanf() scanf() 一起使用,以防止黑客利用。 OP 的fgets()+sscanf() 是更好的方法。

  5. %[^|] 缺少宽度。如果没有此限制,则无法防止缓冲区溢出。见#1。

  6. "%*c" 最后可能会或可能不会扫描字符。结果值不反映其成功或失败,因为带有'*' 的扫描指令不会直接影响返回值。如果需要对"%*c" 进行成功的尾随扫描(每个点#3 可能是"|"),建议使用"%n" 来检测扫描是否继续进行。

    char vars[100];
    int n = 0;
    sscanf(string,"%*[^|]|%99[^|]| %n", vars);
    if (n > 0) Success();
    
    // May also want to use
    if (string[n]) Fail_ExtraTextOnLine();
    
  7. 在 C 中,%*[^|]scanf 说明符,而不是分隔符。

【讨论】:

    猜你喜欢
    • 2017-02-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-08-22
    • 1970-01-01
    相关资源
    最近更新 更多