C语言中不带额外参数的scanf函数

14

在不使用额外参数的情况下,scanf(" ")是否允许用于忽略前导空格?
我正在使用getchar()读取单词的字符,并且我想在单词之前忽略空格(在单词后面使用空格来检查单词的结尾)。
以下是代码,它正确吗?

char *read_word() {
    int size = 2;
    int char_count = 0;
    char *s;
    char ch;

    s = mem_alloc(size);

    scanf(" ");

    while ((ch = getchar()) != EOF) {
        if (char_count >= size) {
            s = mem_realloc(s, size++);
        }

        if (ch == ' ' || ch == '\n') {
            s[char_count] = '\0';
            break;
        }

        s[char_count++] = ch;
    }

    return s;
}

6
当然。 - DevSolar
2
附: mem_realloc(s, size++); --> mem_realloc(s, ++size); - Weather Vane
1
如果出现 EOFs[char_count] = '\0'; 不会执行。 - chux - Reinstate Monica
1
@WeatherVane 我听说过答案无效(在代码审查中),但没有听说过评论无效?如果错误与问题无关,那为什么要在意呢? - Insane
2
@Insane 是的。评论应该用于请求对帖子的澄清;它们经常变得过时(并被标记为过时)。 - Mathieu Guindon
显示剩余5条评论
4个回答

13

scanf() 函数的定义(*)中可以看到:

格式由零个或多个指令组成:一个或多个空格字符,一个普通的多字节字符(既不是 % 也不是空格字符),或者一个转换说明符。

[...]

由空格字符组成的指令通过读取输入直到第一个非空格字符(未读取的字符保持不变)或者无法再读取为止而被执行。

因此,scanf( " " ); 是完全有效的。


(*): ISO/IEC 9899:1999, 7.19.6.2 The fscanf function, section 3 and 5.

其他 *scanf 函数的定义基于此章节。


9
除了其他答案之外,以下所有内容都是有效的:
scanf(" ");      // skip over whitespace
scanf("xyz");    // skip over the longest leading substring of "xyz" if present
                 // i.e. "xyz" or "xy" or "x"
scanf(" %*s ");  // skip over the first string and whitespace around it

2
感谢您在原回答的基础上增加了额外的知识,这非常有帮助。 - Grijesh Chauhan

5
manpage中写道:

格式字符串由指令序列组成。

...

指令可以是以下之一:

• 一系列空格字符(空格、制表符、换行等;请参见 isspace(3))。此指令匹配输入中的任意数量的空格,包括零个。

...

所以,是的,这是 scanf 的合法用法。


如果您追求效率:
int c;
while(isspace(c=getchar()) {;}

这会引导我们走向更高效的道路,因为getchar等函数通常有相应的“_unlocked”版本,而scanf没有。


虽然在这种情况下不是问题,但我会小心依赖manpages。它们通常不能清楚地区分什么是ISO C,什么是POSIX - 这可能会有所不同。因此,如果问题是关于某些东西是否“在C中”合法,标准胜过manpage。(我这么说不仅仅是因为我引用了它,而是因为我有时会在非POSIX平台上工作。) - DevSolar
@DevSolar 我同意。我们几乎同时发布了。如果我先看到你的帖子,我可能不会发我的,但我认为我的帖子仍然有一些价值(=我从中得到了积分:D),所以我会保留它。 - Petr Skocik
请注意,要使您的getchar示例等同于scanf(" "),您必须在结尾处使用ungetc(c, stdin) - Nate Eldredge

4

我建议尝试以下操作:

int skip = -1;
if (scanf(" %n", &skip)>=0 && skip>0)   {
  // you have skipped skip spaces
}

>=0测试检查scanf是否失败(例如由于stdin上的EOF或输入错误)。skip>0测试检查我们已经跳过了至少一个空格字节。 %n转换说明符给出了解析的字节数。


“>=0”测试看起来是不必要的。它有什么作用? - chux - Reinstate Monica
我认为如果标准输入中有EOF或输入错误,skip就不可能改变,因此skip将保留其-1值,然后未通过skip>0测试。无论如何,检查scanf()的返回值是值得鼓励的。 - chux - Reinstate Monica
如果没有跳过任何空格,我的测试就会失败。 - Basile Starynkevitch

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