scanf,输入错误后,为什么不能再次输入?!

C、C++和Java语言
头像
zongzw
帖子: 94
注册时间: 2008-03-31 16:12
送出感谢: 0
接收感谢: 0

scanf,输入错误后,为什么不能再次输入?!

#1

帖子 zongzw » 2008-07-05 18:42

我的代码及运行情况如下

代码: 全选

#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]$ 
头像
BigSnake.NET
帖子: 12522
注册时间: 2006-07-02 11:16
来自: 廣州
送出感谢: 0
接收感谢: 7 次
联系:

#2

帖子 BigSnake.NET » 2008-07-05 19:07

因为之前的东西被第二个scanf吃掉了
^_^ ~~~
要理解递归,首先要理解递归。

地球人都知道,理论上,理论跟实际是没有差别的,但实际上,理论跟实际的差别是相当大滴。
头像
zongzw
帖子: 94
注册时间: 2008-03-31 16:12
送出感谢: 0
接收感谢: 0

#3

帖子 zongzw » 2008-07-05 20:45

BigSnake.NET 写了:因为之前的东西被第二个scanf吃掉了
那怎么才能不吃掉呢。
头像
zongzw
帖子: 94
注册时间: 2008-03-31 16:12
送出感谢: 0
接收感谢: 0

#4

帖子 zongzw » 2008-07-05 21:27

知道怎么弄了。
*参见这篇文章,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;
}
头像
kofshower
帖子: 1343
注册时间: 2007-03-13 11:23
送出感谢: 0
接收感谢: 0
联系:

#5

帖子 kofshower » 2008-07-06 5:53

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); :em25
"We are all in the mud, but some of us are looking at the stars." (Oscar Wilde)
We are not born for ourselves.
人生天地间,并非为自己
Homepage:http://sites.google.com/site/polarisnotme/
头像
zongzw
帖子: 94
注册时间: 2008-03-31 16:12
送出感谢: 0
接收感谢: 0

#6

帖子 zongzw » 2008-07-06 9:38

thanks to kofshower,
说的很对,我在vc下实验fflush可以但是gcc下就不行了,我用的是gcc4.1,也是不支持fflush的。

于是、然后,scanf("%s",ch)掉多余的没有正确读入的字符就可以了。
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28
送出感谢: 0
接收感谢: 0

#7

帖子 flyinflash » 2008-07-06 9:38

还要考两科,没有写完,先看一下
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;
}
头像
zongzw
帖子: 94
注册时间: 2008-03-31 16:12
送出感谢: 0
接收感谢: 0

#8

帖子 zongzw » 2008-07-06 9:41

to flyinflash
我需要一次读入几个数据而不是1个数据啊,读入几个数据,并每次都敲一下回车,当然可以,我要得可不是这个效果。。,所以我会那样写:("%d %d", &a, &b)
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28
送出感谢: 0
接收感谢: 0

#9

帖子 flyinflash » 2008-07-06 9:46

解决方案

1、使用一个较长数组接收输入,把要的保留,不要的 \10 去掉。

但是,如果不知道哪些要,哪些不要,这个就不可行,与及,“较长“到底要多长?

2、自定义一个函数

我的博客里面没有写完 :D:D:D
http://hi.baidu.com/flyinflash/blog/ite ... 55915.html
头像
zongzw
帖子: 94
注册时间: 2008-03-31 16:12
送出感谢: 0
接收感谢: 0

#10

帖子 zongzw » 2008-07-06 10:05

好,好好借鉴一下
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28
送出感谢: 0
接收感谢: 0

#11

帖子 flyinflash » 2008-07-06 10:17

有时候我们可以在想要的输入之后添加一个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 下工作得不是很好
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28
送出感谢: 0
接收感谢: 0

#12

帖子 flyinflash » 2008-07-06 10:19

我第一次遇到这个问题是在这里
一个小游戏

viewtopic.php?t=106286&postdays=0&postorder=asc&start=0

里面就是使用第一种方案解决的,您看一下吧,说不定您能想到更的办法:D:D:D
头像
kofshower
帖子: 1343
注册时间: 2007-03-13 11:23
送出感谢: 0
接收感谢: 0
联系:

#13

帖子 kofshower » 2008-07-06 10:32

这个是我被培训的时候c/c++编程惯用法里面就提到这些东西,其实这有一个惯用的处理模式。
以c为例:这个惯用法同样适合stdin被重定向到文件的时候
附件
window.png
上次由 kofshower 在 2008-07-06 18:05,总共编辑 5 次。
"We are all in the mud, but some of us are looking at the stars." (Oscar Wilde)
We are not born for ourselves.
人生天地间,并非为自己
Homepage:http://sites.google.com/site/polarisnotme/
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28
送出感谢: 0
接收感谢: 0

#14

帖子 flyinflash » 2008-07-06 14:37

楼上的,你也太不专业了,竟然上图,而已是配色这么漂亮的图
给我拖出去打~~~

代码: 全选

#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
flyinflash
帖子: 2376
注册时间: 2006-09-21 14:28
送出感谢: 0
接收感谢: 0

#15

帖子 flyinflash » 2008-07-06 14:39

代码: 全选

#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$ 
回复

回到 “C/C++/Java”