如何在循环中使用sscanf?

30
有没有一种好的方法可以使用 sscanf 循环遍历字符串?
假设我有一个看起来像这样的字符串:
char line[] = "100 185 400 11 1000";

我想打印这些数字的总和。我真正想写的是:

int n, sum = 0;
while (1 == sscanf(line, " %d", &n)) {
  sum += n;
  line += <number of bytes consumed by sscanf>
}

但是没有简单的方法从sscanf中获取这些信息。如果它返回了消耗的字节数,那就很有用了。在这种情况下,可以使用strtok,但能够像从stdin中做的那样编写一些类似的内容会更好:

int n, sum = 0;
while (1 == scanf(" %d", &n)) {
  sum += n;
  // stdin is transparently advanced by scanf call
}

我是否忘记了一个简单的解决方案?

1个回答

54

查找sscanf()及其相关函数中的%n转换说明符。它会给你所需的信息。

#include <stdio.h>

int main(void)
{
    char line[] = "100 185 400 11 1000";
    char *data = line;
    int offset;
    int n;
    int sum = 0;

    while (sscanf(data, " %d%n", &n, &offset) == 1)
    {
        sum += n;
        data += offset;
        printf("read: %5d; sum = %5d; offset = %5d\n", n, sum, offset);
    }

    printf("sum = %d\n", sum);
    return 0;
}

将'line'更改为'data',因为您不能增加数组的名称。


2
@Green Code:多年来,我已经阅读、反复阅读和再次阅读了该函数的手册页面,使用了许多台机器,并使用了我的 C 标准副本等。我认为这实际上是我第一次使用 %n 表示法,但它运行良好。请注意:%nprintf() 中也存在,并具有类似的含义。这成为一个风险因素,因为它是一个在主要读取值的函数中的输出值。它也被 TR24731 的安全版本的 printf() 禁止使用。并且 %n 可以被那些管理程序格式字符串攻击的人以毁灭性的效果使用。 - Jonathan Leffler
@JonathanLeffler 在 sscanf 格式字符串中的前导空格是否需要,因为 %d 无论如何都会读取并丢弃任意数量的空格字符? - ajay
你能否解释一下你在谈到 printf 时提到的 TR24731 是什么? - ajay
1
@ajay:不需要前导空格,我是没有考虑就从问题中复制过来的。TR 24731-1 是 ISO JTC1/SC22/WG14 委员会(也称为“标准C”委员会)发布的技术报告,名为“C库扩展第一部分:边界检查接口”,定义了一些函数的“更安全”版本。它们由微软等公司实现(请参见Do you use TR 24731 safe functions)。TR24731-1 是 ISO/IEC 9899:2011 的附录K(可选项),该版本是当前的C标准。 - Jonathan Leffler
@JonathanLeffler 非常感谢您 :) 每天我都感到自己所知甚少,同时也很兴奋地意识到还有很多东西需要学习。 - ajay
显示剩余2条评论

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