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

首先,我先说一下对缓存区的理解

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

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


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

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

#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],n
2[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)
















  • 4
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值