确定sscanf是否使用%* s读取任何内容

时间:2014-12-08 12:59:28

标签: c scanf dummy-data

说我有字符串:

char* foo = "  blah  blee  bleck  ";

现在说我想阅读并丢掉前两个词:

int bar = 0;

sscanf(foo, "%*s%n", &bar);
foo += bar;

if(bar > 0) sscanf(foo, "%*s%n, &bar);

我的问题是如何判断第二个sscanf是否有任何内容?

我是否需要在每次读取之间输出0 bar以确定是否实际读取了字符串,还是有更好的方法?

修改

检查sscanf返回值无效,因为%* s和%n不会增加sscanf的返回值:

printf("%d ", sscanf(foo, "%*s%n", &bar));
printf("%d ", bar);
printf("%d ", sscanf(foo + bar, "%*s%n", &bar));
printf("%d\n", bar);

将输出:

  

0 6 0 6

5 个答案:

答案 0 :(得分:2)

检查sscanf调用的返回值,因为文档离子声明将返回一个整数值。

int sscanf( const char          *buffer, const char          *format, ... ); (C99)

我在我的机器上试了一小段代码,类似于你的查询,实际上sscanf为不成功的操作返回负值。

测试代码:

#include <stdio.h>

void main(void)
{
char* foo = "  blah  bleee  bleckk  ";
//char* foo = "  blah";
int bar = 0;
int ret = -10;

printf("#m1 foo:%s\n",foo);
printf("#m1 bar:%d\n",bar);
printf("#m1 ret:%d\n\n",ret);

ret = sscanf(foo, "%*s%n", &bar);
foo += bar;
printf("#m2 foo:%s\n",foo);
printf("#m2 bar:%d\n",bar);
printf("#m2 ret:%d\n\n",ret);

if(bar > 0)
{
    ret = -10;
    ret = sscanf(foo, "%*s%n", &bar);
    foo += bar;
}
printf("#m3 foo:%s\n",foo);
printf("#m3 bar:%d\n",bar);
printf("#m3 ret:%d\n",ret);
}

测试两种情况的输出:

./a.out
#m1 foo:  blah  bleee  bleckk
#m1 bar:0
#m1 ret:-10

#m2 foo:  bleee  bleckk
#m2 bar:6
#m2 ret:0

#m3 foo:  bleckk
#m3 bar:7
#m3 ret:0


./a.out
#m1 foo:  blah
#m1 bar:0
#m1 ret:-10

#m2 foo:
#m2 bar:6
#m2 ret:0

#m3 foo:oo:%s

#m3 bar:6
#m3 ret:-1

问题是对于失败的sscanf调用,条形值未设置为零。

答案 1 :(得分:1)

如果忽略空格,正确的方法是在sscanf()返回值中测试EOF。 EOF表示%* s没有读取任何内容。如果你没有忽略空格,解决方案是微不足道的:如果在fscanf之前* foo!= 0,那么sscanf会读取一些内容。

答案 2 :(得分:1)

...阅读并丢掉前两个词:

const char* foo = "  blah  blee  bleck  ";
int bar = 0;
sscanf(foo, "%*s%*s% %n", &bar);
if (bar) {
  printf("Success: string with first two words thrown away:'%s'\n", &foo[bar]);
}

上面在"%n"之前添加了一个空格,以便在&#34; blee&#34;之后扔掉空格。


判断第二个sscanf是否读了什么?我需要0吗?

是的,重置bar = 0;是一种简单的方法。除非前面的"%n"扫描了一些非空格,否则"%*s"不会被采取行动。

char* foo = "  blah  blee  bleck  ";
int bar = 0;
sscanf(foo, "%*s%n", &bar);
foo += bar;

if(bar > 0) {
  puts("first sscanf read something.");
  bar = 0;
  sscanf(foo, "%*s%n", &bar);
  if (bar) puts("second sscanf read something.");
}

答案 3 :(得分:0)

更好的方法可能是使用一些适当的标记化代码,而不是构建在sscanf()上。我可能会写这样的东西:

const char * skip_word(const char *s)
{
  while(isspace(*s))
   ++s;
  while(*s && !isspace(*s))
   ++s;
  return s;
}

这可用于跳过前导空格后跟一个单词,其中一个单词被非常宽松地定义为&#34;非空白字符&#34;。然后你可以通过调用上面的两次来提取第三个单词,当然检查中间返回值是否敏感。这样的事情。

但是,是的,当然,您必须清除bar以获得新的解释。

规范似乎有点混淆了%n是否包含在返回值中,仅此一点告诉我它不是最好的方法。

答案 4 :(得分:-1)

来自sscanf()文档:

  

返回值

     

这些函数返回成功匹配的输入项数   分配,可以少于提供,或者甚至为零   早期匹配失败。

因此,如果sscanf()没有返回您预期的匹配数,那么它可能无法读取您想要的内容。