scanf的陷阱

来源:互联网 发布:淘宝上的epiphone 编辑:程序博客网 时间:2024/05/21 09:38

    scanf函数从标准输入流得到数据。以下几点需要注意:
    1、scanf的返回值表示成功读入数据的个数。何为成功读入?例如,scanf("%d%d", &a, &b); 要求读入2个十进制的整数,scanf会到输入缓冲区中寻找。如果成功找到2个整数就返回2;如果找到1个就返回1,表示只有a被成功读入;如果找完整个输入缓冲区都没有找到,就返回0,表示读入失败。

程序如下:
#include<stdio.h>
int main()
{
 int a=1,b=1;
 int ret;

 ret = scanf("%d %d",&a,&b);
 printf("a=%d b=%d\n",a,b);
 printf("ret=%d\n", ret);
 return 0;
}
输入2个整数:
2 3       //输入
a=2 b=3   //输出
ret=2     //输出

输入2个字符:
a b       //输入
a=1 b=1   //输出
ret=0     //输出
当然,由于没有读取出a b,在缓冲区中的a b并不会消失。

 

    2、scanf遇到空格、回车和Tab键都会认为输入结束。

程序如下:
#include<stdio.h>
int main()
{
 char ch1[10];

#if 1
 scanf("%s",ch1);
 printf("%s\n", ch1);
#else
 gets(ch1);
 printf("%s\n", ch1);
#endif
 return 0;
}
输入abc de
abc de    //输入
abc       //输出

将#if 1改为#if 0
输入abc de
abc de    //输入
abc de    //输出

    关于scanf和gets的区别:
scanf :当遇到回车,空格和tab键会自动在字符串后面添加'\0',但是回车,空格和tab键仍会留在输入的缓冲区中。
gets:可接受回车键之前输入的所有字符,并用'\0'替代 '\n'.回车键不会留在输入缓冲区中。

    如果非要用scanf,可以将scanf("%s",ch1);改为scanf("%[^\n]",ch1);表示接受除了'\n'外的任何字符。但是,'\n'仍然留在缓冲区中。

 

    3、在用"%c"输入时,空格和“转义字符”均作为有效字符。

例如:
#include<stdio.h>
int main()
{
 char ch1[10];
 char c;

 scanf("%s",ch1);
 scanf("%c", &c);
 printf("%s\n", ch1);
 printf("%d\n", c);

 return 0;
}
输入abc
abc    //输入
abc    //输出
10     //输出
10即'\n'的ASCII值

 

    4、刷新缓冲区
    在使用scanf时,如果不及时刷新输入缓冲区,有时会出现莫名其妙的错误。

例如:
#include<stdio.h>
int main()
{
 int c;

 do
 {
  scanf("%d",&c);
  printf("%d\n", c);
 }while (c != 20);

 return 0;
}
    程序意思是让用户输入一个整数,如果这个数不是20,就继续输入。
    当用户输入整数时,这个程序能正常工作。但是,当输入的不是数字时,程序就会死锁,不断循环输出数字。
    如何解决这个问题?这就需要用到scanf的返回值。当返回值不是1时,刷新缓冲区。

    在windows中,可以使用fflush(stdin);来刷新输入缓冲区。但是,标准C并没有定义fflush对输入缓冲区的操作:

int fflush(FILE* stream);
Flushes stream stream and returns zero on success or EOF on error.
Effect undefined for input stream. fflush(NULL) flushes all output streams.
    使用fflush是个很不明智的决定(gcc不支持fflush刷新输入缓冲区)。可以自己定义一个刷新输入缓冲区的函数:
void flush()
{
 char c;
 while ((c=getchar()) != '\n'&&c!=EOF) ;
}
这样就可以解决我们之前的问题了:
int main()
{
 int c;

 do
 {
  if (scanf("%d",&c) != 1)
   flush();
  else
   printf("%d\n", c);
 }while (c != 20);

 return 0;
}

原创粉丝点击