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
往往是不够好。 (警告:不要混淆fgets
和gets
,gets
是危险的,不应该被使用,但是如果你希望你的程序在超长输入行时能够健壮,那么fgets
只是不方便。)