分页: 1 / 2
scanf,输入错误后,为什么不能再次输入?!
发表于 : 2008-07-05 18:42
由 zongzw
我的代码及运行情况如下
代码: 全选
#include <stdio.h>
int main()
{
int a, b;
printf("enter:");
int n = scanf("%d %d", &a, &b);
if(n<2)
{
printf("err--n:%d\n", n);
printf("enter:");
//fflush(stdin);
scanf("%d %d", &a, &b);
}
return 0;
}
执行情况:
代码: 全选
[zongzw@localhost stdin]$ a.out
enter:1 2
[zongzw@localhost stdin]$ a.out
enter:[b]1,[/b]
err--n:1
enter:[zongzw@localhost stdin]$
发表于 : 2008-07-05 19:07
由 BigSnake.NET
因为之前的东西被第二个scanf吃掉了
发表于 : 2008-07-05 20:45
由 zongzw
BigSnake.NET 写了:因为之前的东西被第二个scanf吃掉了
那怎么才能不吃掉呢。
发表于 : 2008-07-05 21:27
由 zongzw
知道怎么弄了。
*参见这篇文章,
http://blog.csdn.net/fxwzzbd/archive/20 ... 14042.aspx
键盘输入缓冲区与scanf()原理。
键盘缓冲区用来缓存“按键”的ASCII码,而scanf()每次从键盘缓冲区中读取一个字符(ASCII码),直键盘缓冲区为空。如果键盘缓冲区为非空状态,执行scanf()不会要求输入,如果键盘缓冲区为空,执行scanf()则会等待用户的输入。
有时候我们可以在想要的输入之后添加一个scanf("%s", ch);来把标准输入中没有正确读入的信息读掉,清空标准输入。
代码: 全选
#include <stdio.h>
#include <string.h>
int main()
{
int a, b;
int enough_len = 256;
char ch[enough_len];
memset(ch, 0, enough_len);
printf("enter:");
int n = scanf("%d %d", &a, &b);
if(n<2)
{
scanf("%s", ch);
printf("err--n:%d\n", n);
printf("enter:");
//fflush(stdin);
scanf("%d %d", &a, &b);
}
return 0;
}
发表于 : 2008-07-06 5:53
由 kofshower
zongzw 写了:知道怎么弄了。
*参见这篇文章,
http://blog.csdn.net/fxwzzbd/archive/20 ... 14042.aspx
键盘输入缓冲区与scanf()原理。
键盘缓冲区用来缓存“按键”的ASCII码,而scanf()每次从键盘缓冲区中读取一个字符(ASCII码),直键盘缓冲区为空。如果键盘缓冲区为非空状态,执行scanf()不会要求输入,如果键盘缓冲区为空,执行scanf()则会等待用户的输入。
有时候我们可以在想要的输入之后添加一个scanf("%s", ch);来把标准输入中没有正确读入的信息读掉,清空标准输入。
代码: 全选
#include <stdio.h>
#include <string.h>
int main()
{
int a, b;
int enough_len = 256;
char ch[enough_len];
memset(ch, 0, enough_len);
printf("enter:");
int n = scanf("%d %d", &a, &b);
if(n<2)
{
scanf("%s", ch);
printf("err--n:%d\n", n);
printf("enter:");
//fflush(stdin);
scanf("%d %d", &a, &b);
}
return 0;
}
我一看到这个,这是我的第一反应。
C和C++的标准里从来没有定义过 fflush(stdin)。也许有人会说:“可是我用 fflush(stdin) 解决了这个问题,你怎么能说是错的呢?”的确,某些编译器(如VC6)支持用 fflush(stdin) 来清空输入缓冲,但是并非所有编译器都要支持这个功能(gcc3.2不支持),因为标准中根本没有定义 fflush(stdin)。MSDN 文档里也清楚地写着 fflush on input stream is an extension to the C standard (fflush 操作输入流是对C标准的扩充)。当然,如果你毫不在乎程序的移植性,用 fflush(stdin) 也没什么大问题。以下是 C99 对 fflush 函数的定义:
int fflush(FILE *stream);

发表于 : 2008-07-06 9:38
由 zongzw
thanks to kofshower,
说的很对,我在vc下实验fflush可以但是gcc下就不行了,我用的是gcc4.1,也是不支持fflush的。
于是、然后,scanf("%s",ch)掉多余的没有正确读入的字符就可以了。
发表于 : 2008-07-06 9:38
由 flyinflash
还要考两科,没有写完,先看一下
http://hi.baidu.com/flyinflash/blog/ite ... 55915.html
代码: 全选
int n = scanf("%d %d", &a, &b);
我不明白,你为什么会这样写,scanf 的返回值一般没有什么意义
概述:
不管是 scanf 还是 getchar,它们都不会接收 enter,
比如使用 scanf 接收输入
abc<-enter
则输入流为
abc\10(\10为回车)
但是scanf 仅认abc,\10会被下一个接收输入函数接收,所以会出现“跳过”的怪异情况
使用 getchar 接收输入
a<-enter
则输入流为
a\10
getchar 跟 scanf 一个样,不理 \10 的
代码: 全选
#include <stdio.h>
int main()
{
int a, b;
a = getchar();
b = getchar();
printf("\n a = %d :: %c ", a, a);
printf("\n b = %d :: %c ", b, b);
return 0;
}
发表于 : 2008-07-06 9:41
由 zongzw
to flyinflash
我需要一次读入几个数据而不是1个数据啊,读入几个数据,并每次都敲一下回车,当然可以,我要得可不是这个效果。。,所以我会那样写:("%d %d", &a, &b)
发表于 : 2008-07-06 9:46
由 flyinflash
解决方案
1、使用一个较长数组接收输入,把要的保留,不要的 \10 去掉。
但是,如果不知道哪些要,哪些不要,这个就不可行,与及,“较长“到底要多长?
2、自定义一个函数
我的博客里面没有写完

:D:D
http://hi.baidu.com/flyinflash/blog/ite ... 55915.html
发表于 : 2008-07-06 10:05
由 zongzw
好,好好借鉴一下
发表于 : 2008-07-06 10:17
由 flyinflash
有时候我们可以在想要的输入之后添加一个scanf("%s", ch);来把标准输入中没有正确读入的信息读掉,清空标准输入。
思想和我的第一个解决方案有异曲同工之妙
代码: 全选
NAME
fflush - flush a stream
SYNOPSIS
#include <stdio.h>
...
CONFORMING TO
C89, C99.
NOTES
Note that fflush() only flushes the user space buffers provided by the
C library. To ensure that the data is physically stored on disk the
kernel buffers must be flushed too, for example, with sync(2) or
fsync(2).
fflush 定义在 stdio 头文件里面,它是标准库的函数
但是,GCC 下工作得不是很好
发表于 : 2008-07-06 10:19
由 flyinflash
我第一次遇到这个问题是在这里
一个小游戏
viewtopic.php?t=106286&postdays=0&postorder=asc&start=0
里面就是使用第一种方案解决的,您看一下吧,说不定您能想到更的办法:D:D:D
发表于 : 2008-07-06 10:32
由 kofshower
这个是我被培训的时候c/c++编程惯用法里面就提到这些东西,其实这有一个惯用的处理模式。
以c为例:这个惯用法同样适合stdin被重定向到文件的时候
发表于 : 2008-07-06 14:37
由 flyinflash
楼上的,你也太不专业了,竟然上图,而已是配色这么漂亮的图
给我拖出去打~~~
代码: 全选
#include <stdio.h>
void flush()
{
int c;
while ((c = getchar() != '\n') && c != EOF) ;
}
int main(int argc, char** argv)
{
int i, j;
i = getchar();
flush();
j = getchar();
putchar(i);
putchar(j);
return 0;
}
我建议把 flush 写进自定义的头文件里面
代码: 全选
sudo mkdir /usr/include/lee
sudo chown lee:lee /usr/include/lee
touch /usr/include/lee/stdiol.h
代码: 全选
#ifndef __STDIOL_H__
#define __STDIOL_H__
#include <stdio.h>
#include <stdlib.h>
int getch(void)
{
int key;
system("stty raw");
// stty - change and print terminal line settings
// raw - same as -ignbrk -brkint -ignpar -parmrk -inpck -istrip -inlcr
key = getchar();
system("stty cooked");
// cooked - same as brkint ignpar istrip icrnl ixon opost isig icanon,
// eof and eol characters to their default values
return key;
}
void flush()
{
int c;
while ((c = getchar() != '\n') && c != EOF) ;
}
#endif
发表于 : 2008-07-06 14:39
由 flyinflash
代码: 全选
#include <stdio.h>
#include <lee/stdiol.h>
int main(int argc, char** argv)
{
int i, j;
i = getchar();
flush();
j = getchar();
printf("\n");
putchar(i);
putchar(j);
printf("\n");
return 0;
}
代码: 全选
1alee@lee-thinkpad:/tmp$ ./t
128391
salkdflasf
1s
lee@lee-thinkpad:/tmp$