scanf使用制表符和换行符缓冲

问题描述:

我对处理空白时scanf的行为感到困惑。scanf使用制表符和换行符缓冲

下面是我使用的代码:

int main() 
{ 
    int val; 
    int c; 

    scanf("%d\t", &val); 

    c = getchar(); 

    if(c == EOF) 
    printf("eof"); 
    else if(c == '\t') 
    printf("tab"); 
    else if(c == '\n') 
    printf("newline"); 
} 

而这里的输入端,我通过它:

1234<tab><newline> 

我希望它可以打印“换行”,因为scanf函数只是寻找制表符,并假设scanf在默认情况下在缓冲区留下空白。相反,它会打印“eof”。 %d\t似乎吞噬换行符。

我错过了关于scanf的工作原理吗?

注意,如果我将其更改为下文中,正确地打印“换行”:

int main() 
{ 
    int val; 
    int c; 

    scanf("%d", &val); 

    getchar(); /* note this extra getchar */ 

    c = getchar(); 

    if(c == EOF) 
    printf("eof"); 
    else if(c == '\t') 
    printf("tab"); 
    else if(c == '\n') 
    printf("newline"); 
} 

任何模式中的空白的量(\t)在输入匹配任何空白的量(\t\n)。

从手册页:

White space (such as blanks, tabs, or newlines) in the format string match any amount of white space, including none, in the input. 

“我感到困惑的scanf处理空白时的行为。”是一个普遍的要求!

如果格式字符串中有任何空白,它将消耗所有空白,所以“\ t”匹配任何空白字符串。

您遇到了一个更为臭名昭着的原因:为什么*scanf should never be used:混淆的空白处理。您的'\t'不仅仅匹配一个标签,它匹配任意数量的任何类型的空白,包括换行符!

做这样的事情的最好方法,假设你有getline,看起来是这样的:

#include <stdio.h> 
#include <stdlib.h> 

int main(void) 
{ 
    char *line = 0; 
    char *p; 
    long val; 

    (void) getline(&line, 0, stdin); 

    val = strtol(line, &p, 10); 
    if (*p == '\0') 
     puts("eof (no tab)"); 
    else { 
     if (*p != '\t') 
      printf("no tab, %c instead\n", *p); 
     p++; 
     if (*p == '\0') 
      puts("eof"); 
     else if (*p == '\t') 
      puts("tab"); 
     else if (*p == '\n') 
      puts("newline"); 
    } 

    free(line); 
    return 0; 
} 

如果没有getline做,fgets往往是不够好。 (警告:不要混淆fgetsgets,gets是危险的,不应该被使用,但是如果你希望你的程序在超长输入行时能够健壮,那么fgets只是不方便。)