您的位置:首页 > 其它

缓存区 及scanf() getchar() gets()的区别

2016-07-17 19:12 246 查看
首先,我先说一下对缓存区的理解

缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储

空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是

输出设备,分为输入缓冲区和输出缓冲区。

我这边以一个例子说下缓存区是如何进行工

#include <stdio.h>

int main()

{

    int n;

    scanf("%d", &n);

    printf("%d", n);

return 0;

}

首先,程序运行到scanf()时会停止,请求外界输入,然后比如你输入一个34然后回车,实际上你在键盘

上输入了字符'3''4'还有一个‘\0’;

当键盘输入结束时会将字符输入到缓存区中,scanf函数以及其他标准输入函数便会立刻从缓存区中获取

内容,然后按照%d的规则从缓存区中获取字符
 它获取了''3''4'  并且将其转变为整数34 存入了变量n中,

题目要求scanf获取一个整数到n中 
它完成了但是并没有结束  因为缓存区中并不干净  回车符'\n'仍然留

在缓存区中,这样加入还有一个scanf函数要求输入就一个字符,那么此时将不需要从键盘上面输入,会

自动将回车符给这个scanf函数

有一点要牢记,输入列表中的内容全是字符,格式说明符对于scanf是十分重要的,它便是“规则”
告诉

scanf如何从缓存区中获取字符并且如何做转换

以上基本是缓存区的工作道理,下面我将会说一些例子来进一步理解这几个函数

1.scanf(
)

(一)先看下scanf()对字符的处理

   #include 

   int main()

   {

      char ch1, ch2;

      scanf("%c", &ch1); 

      scanf("%c", &ch2);

      printf("%d  %d\n", ch1, ch2);

      return 0;

    }

我们准备输入字符a和b,但是我们会发现当我们输入a后回车准备继续输入时,你会发现此时已经结束,

并且输出结果为97 10,为什么会这样呢,因为当你输入a回车后,字符a和回车符‘\0’已经存储到缓存区

然后将字符a保存到ch1 中,可是此时缓存区中有存留了'\0',当运行到第二个scanf时,就不会等待外界

输入而是直接将'\0'存储到ch2中,并以%d输出,及为10

(二)scanf()对字符串的处理

#include
<stdio.h> 

   int main()

   {

     char n1[10],n2[10];

   scanf("%s",n1);     
     scanf("%s",n2);  
     printf("n1 = %s, n2 = %s\n", n1, n2 );  
     return 0;
   }

输入:hello回车world回车

得到如下的输出:

n1=hello,n2=wolrd光标处(程序结束)

这里hello后面就是输入再多个回车、空格也不会被赋值到n2中的,因为使用scanf函数输入字符串的

时候他们只是被当做分隔符。另外就是输入n2的时候,n2后面的那个回车也被当做了分隔符,所以输

出的时候,只是简单的输出了n1和n2的内容,而没有输出回车换行符。

如果再定义一个字符变量n3,并在printf后加上

scanf("%c", &n3);

printf("%c", n3):

输入:hello回车world回车

得到:  

n1=hello,n2=wolrd

光标处(程序结束)

说明此时缓冲区内只有一个'\n ',这说明了 scanf不会把回车、空格赋给字符串但是会赋给字符

总结一下就是:

如果scanf输入的不是字符,那么分隔符为回车,空格、tab键时,两个数据之间的分隔符只是
起区别两个数据的作用,把分隔好的两个数据分别赋值到各自定义好的变量或数组中去,两个
数据之间的分隔符被从缓冲区读出但是不起任何作用,当然最后一个'\n '会被留在缓冲区内,除
非用getchar();或scanf("%c",&c);把它读出来。回车是一定要有的,不管getchar还是scanf只要
通过缓冲区输入数据的函数都是等待回车键'\n '出现才进入缓冲区的。

2.getchar()
getchar()是stdio.h中的库函数,它的作用是从标准输入流中读入一个字符,也就是说,如果缓存区
有数据的话不用输
入它就可以直接读取了。

 #include <stdio.h> 

    int main()

    {

      char ch1, ch2;

      ch1 = getchar();

      ch2 = getchar();

      printf("%d  %d\n", ch1, ch2);

      return 0;

    }用上面的例子来说一下getchar,同样输入a回车符,结果与scanf的结果是一样的,当程序
调用getchar()函数时,程序就等着用户按键,用户输入的字符被存放在键盘缓冲区中,直到用户
按回车为止(回车字符也放在缓冲区中)。当用户键入回车之后,getchar()函数才开始从键盘缓
冲区中每次读入一个字符。也就是说,后续的getchar()函数调用不会等待用户按键,而直接读取
缓冲区中的字符,直到缓冲区中的字符读完后,才重新等待用户按键。

 通俗一点说,当程序调用getchar()函数时,程序就等着用户按键,并等用户按下回车键返回。期间

按下的字符存放在缓冲区,

第一个字符作为函数返回值。继续调用getchar()函数,将不再等用户按键,而是返回您刚才输入的

第2个字符;继续调用,返回第3个字符,直到缓冲区中的字符读完后,才等待用户按键。

3.gets( )

#include <stdio.h> 

  int main()

  {

    char str1[20], str2[20];

    scanf("%s",str1); 

    printf("%s\n",str1);    

    scanf("%s",str2);  

    printf("%s\n",str2);  

    return 0;

  }

    程序的功能是读入一个字符串输出,在读入一个字符串输出。可我们会发现输入的字符串中不能出现空格,例如:
测试一输入 Hello world!
输出 Hello

   world!

  到此程序执行完毕,不会执行第二次的读取操作!这个问题的原因跟问题一类似,第一次输入Hello 

world!后,字符串Hello world!都会被读到输入缓冲区中,而scanf()函数取数据是遇到回车、空格、

TAB就会停止,也就是第一个scanf()会取出"Hello", 而"world!"还在缓冲区中,这样第二个scanf

会直接取出这些数据,而不会等待从终端输入。

测试二输入Hello 

  输出Hello

  输入world

  输出world

  程序执行了两次从键盘读入字符串,说明第一次输入结束时的回车符被丢弃!即:scanf()读取字符

串会舍弃最后的回车符!

  我们再看一下gets()读取字符串的情况:

  用scanf来读取一个字符串时,字符串中是不可以出现空格的,一旦出现空格,后面的数据就会舍弃

残留在缓冲区中。其实有另外一个函数是可以接受空格的,那就是gets(),下面我们看一下这个函数

的应用,

我们把上面程序改动一下

#include <stdio.h>

  int main()

  {

    char str1[20], str2[20];

    gets(str1); 

    printf("%s\n",str1);    

    gets(str2);  

    printf("%s\n",str2);  

    return 0;

  }

 输入 Hello world! 

 输出 Hello world! 

 输入 12345 

 输出 12345

 显然与上一个程序的执行情况不同,这次程序执行了两次从键盘的读入,而且第一个字符串取了

Hello world! 接受了空格符,而没有像上一个程序那样分成了两个字符串!所以如果要读入一个

带空格符的字符串时因该用gets(), 而不宜用scanf()!

对三个函数进行下总结

第一:要注意不同的函数是否接受空格符、是否舍弃最后的回车符的问题!

  读取字符时:

  scanf()以Space、Enter、Tab结束一次输入,不会舍弃最后的回车符(即回车符会残留在缓冲区中);

  getchar()以Enter结束输入,也不会舍弃最后的回车符;

  读取字符串时:

  scanf()以Space、Enter、Tab结束一次输入

  gets()以Enter结束输入(空格不结束),接受空格,会舍弃最后的回车符!

第二:为了避免出现上述问题,必须要清空缓冲区的残留数据,可以用以下的方法解决:

  C语言里提供了函数清空缓冲区,只要在读数据之前先清空缓冲区就没问题了!

       这个函数是fflush(stdin)
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: