scanf()将新行字符保留在缓冲区中

scanf()将新行字符保留在缓冲区中,c,scanf,C,Scanf,我有以下计划: int main(int argc, char *argv[]) { int a, b; char c1, c2; printf("Enter something: "); scanf("%d",&a); // line 1 printf("Enter other something: "); scanf("%d", &b); // line 2 printf("Enter a char: "); scanf("%c",&

我有以下计划:

int main(int argc, char *argv[])
{
  int a, b;
  char c1, c2;
  printf("Enter something: ");
  scanf("%d",&a); // line 1
  printf("Enter other something: ");
  scanf("%d", &b); // line 2

  printf("Enter a char: ");
  scanf("%c",&c1); // line 3
  printf("Enter another char: ");
  scanf("%c", &c2); // line 4

  printf("Done"); // line 5

  system("PAUSE");

  return 0;
}
正如我在C语言书中读到的,作者说,
scanf()
在缓冲区中留下了一个新行字符,因此,程序不会停在第4行让用户输入数据,而是将新行字符存储在c2中,并移到第5行

是这样吗

但是,这是否只发生在
char
数据类型中?因为我在第1、2、3行中没有看到
int
数据类型的问题。是否正确?

在尝试解析字符以外的转换之前,函数会自动跳过前导空格。字符格式(主要是
%c
;也包括扫描集
%[…]
-和
%n
)是例外;它们不会跳过空白

使用带前导空格的
“%c”
跳过可选空格。请勿在
scanf()
格式字符串中使用尾随空格

请注意,这仍然不会消耗输入流中留下的任何尾随空格,甚至不会消耗到行尾,因此如果同时使用或在同一输入流上使用,请注意这一点。我们只是让scanf在转换之前跳过空白,就像它在
%d
和其他非字符转换中一样


请注意,非空白的“指令”(要使用)不是转换,例如
scanf中的文本(“order=%d”,&order)也不会跳过空白。文本
顺序
必须与要读取的下一个字符匹配

因此,如果要跳过前一行的换行,但仍需要固定字符串上的文字匹配,则可能需要
“order=%d”

使用
scanf(“%c”和&c2)。这将解决您的问题。

在调用第二个
scanf()之前使用
getchar()

scanf("%c", &c1);
getchar();  // <== remove newline
scanf("%c", &c2);
scanf(“%c”和&c1);
getchar();// 另一个选项(我从中得到)是使用赋值抑制选项读取并丢弃换行符。为此,我们只需设置一种格式来读取一个星号介于
%
c
之间的字符:

scanf("%d%*c",&a); // line 1
scanf("%c%*c",&c1); // line 3
scanf
随后将读取下一个字符(即换行符),但不会将其分配给任何指针

然而,最后,我要说的是:

或者,根据您的需求,您也可以忘记scanf()/getchar(),使用fgets()从用户那里获取一行文本并自己解析


为了回应我的帖子:我建议扔掉
scanf()
,不要使用它,而是使用
fgets()
sscanf()
(*)

原因是,至少在类似Unix的系统中,默认情况下,CLI程序运行的终端会在程序看到用户输入之前对其进行一些处理。它缓冲输入,直到输入换行符,并允许一些基本的行编辑,如使退格工作

所以,你不可能一次只得到一个字符,或者几个字符,只是一整行。但这不是例如scanf(“%d”)
所处理的,相反,它只处理数字,然后停在那里,剩下的缓冲在C库中,供将来的
stdio
函数使用。如果你的程序有,例如

printf("Enter a number: ");
scanf("%d", &a);

printf("Enter a word: ");
scanf("%s", word);
然后输入行
123 abcd
,它会同时完成两个
scanf()
s,但只有在给出换行符之后。第一个
scanf();第二个
scanf()
不会等待您输入另一行(因为输入缓冲区已经包含足够的内容来填充
%s
转换)

这不是用户通常期望的

相反,他们希望按enter键完成输入,如果按enter键,您会得到一个默认值或一个错误,可能会有一个建议,请您真正给出答案

使用
scanf(“%d”)
无法真正做到这一点。如果用户只是点击回车键,什么也不会发生。因为
scanf()
仍在等待号码。终端向前发送该行,但您的程序没有看到它,因为
scanf()
会吃掉它。你没有机会对用户的错误做出反应

这也不是很有用

因此,我建议使用
fgets()
getline()
一次读取一整行输入。这与终端提供的完全匹配,并且总是在用户输入一行后提供程序控制。如何处理输入行取决于您自己,如果您想要一个数字,可以使用:
atoi()
strtol()
,或者实际上是
sscanf(buf),%d,&a)
sscanf()
与scanf()
没有相同的不匹配,因为它读取的缓冲区大小有限,当它结束时,它就结束了——函数不能再等待了

fscanf()
如果文件格式支持像任何空格一样在换行符上浏览,那么在常规文件上也可以。对于面向文件的数据,我仍然会使用
fgets()
sscanf()


因此,与上面的内容不同,使用以下内容:

printf("Enter a number: ");

fgets(buf, bufsize, stdin);
sscanf(buf, "%d", &a);
或者,实际上,还要检查
sscanf()
的返回值,以便我们可以检测空行或其他无效数据:

#包括
内部主(空)
{
常量int bufsize=100;
字符buf[bufsize];
INTA;
int ret;
字符字[bufsize];
printf(“输入一个数字:”);
fgets(buf、bufsize、stdin);
ret=sscanf(buf、%d、&a);
如果(ret!=1){
fprintf(stderr,“好的,您不必\n”);
返回1;
}
printf(“输入一个单词:”);
fgets(buf、bufsize、stdin);
ret=sscanf(buf,“%s”,字);
如果(ret!=1){
fprintf(stderr,“你让我难过。\n”);
返回1;
}
printf(“您输入了%d和%s\n”,一个字);
}