1

假设我有字符串:

char* foo = "  blah  blee  bleck  ";

现在说我要阅读并扔掉前两个单词:

int bar = 0;

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

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

我的问题是如何判断第二个是否sscanf读过任何东西?

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

编辑:

检查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

4

5 回答 5

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 调用,bar 值未设置为零。

于 2014-12-08T13:45:53.643 回答
1

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

于 2014-12-08T13:37:00.657 回答
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"在“blee”之后添加了一个空格以丢弃空格。


判断第二个 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.");
}
于 2014-12-08T14:39:56.330 回答
0

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

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

这可用于跳过前导空格后跟一个单词,其中一个单词被非常松散地定义为“非空白字符”。然后,您可以通过两次调用上述方法来提取第三个单词,当然还要检查中间返回值的敏感性。类似的东西。

但是,是的,当然,您必须清楚bar才能获得新的解释。

该规范似乎对是否%n包含在返回值中有些困惑,仅此一点就告诉我这不是最好的方法。

于 2014-12-08T13:06:39.623 回答
-1

sscanf()文档:

返回值

这些函数返回成功匹配和分配的输入项的数量,该数量可能少于提供的数量,或者在早期匹配失败的情况下甚至为零。

因此,如果sscanf()不返回您期望的匹配数量,它可能没有读取您想要的内容。

于 2014-12-08T13:07:50.360 回答