转载缓冲区

 

 

来源: 徐南木
文章作者: 徐南木
文章链接: http://blog.xunanmu.com/2019/09/20/scanf-he-printf-han-shu-xiang-jie/#toc-heading-7

 

4.1 关于printf缓冲

在 printf 的实现中,在调用 write 之前先写入 IO 缓冲区,这是一个用户空间的缓冲。系统调用是软中断,频繁调用,需要频繁陷入内核态,这样的效率不是很高,而 printf 实际是向用户空间的 IO 缓冲写,在满足条件的情况下才会调用 write 系统调用,减少IO次数,提高效率。
printf 在 glibc 中默认为行缓冲,遇到以下几种情况会刷新缓冲区,输出内容:

  • (1)缓冲区填满;
  • (2)写入的字符中有换行符\n或回车符\r;
  • (3)调用fflush手动刷新缓冲区;
  • (4)调用scanf要从输入缓冲区中读取数据时,也会将输出缓冲区内的数据刷新。
    可使用setbuf(stdout,NULL)关闭行缓冲,或者setbuf(stdout,uBuff)设置新的缓冲区,uBuff为自己指定的缓冲区。也可以使用setvbuf(stdout,NULL,_IOFBF,0);来改变标准输出为全缓冲。全缓冲与行缓冲的区别在于遇到换行符不刷新缓冲区。

printf 在 VC++ 中默认关闭缓冲区,输出时会及时的输到屏幕。如果显示开启缓冲区,只能设置全缓冲.

4.2 关于scanf缓冲

在使用 scanf 函数的时候,需要特别注意的就是缓冲区问题。对 scanf 函数来说,估计最容易出错、最令人捉摸不透的问题应该是缓冲区问题了。

  • 标准输入缓冲区 stdin 使用行缓冲的方式存储输入。用户的输入数据首先被暂存在临时缓冲区中,当用户键入回车键或临时缓冲区满后,stdin 才进行 I/O 操作,将数据由临时缓冲区拷贝至 stdin 中。C语言提供的输入输出函数如 scanf 、getchar 等则从上述缓冲区 stdin 中读取数据输入。

  scanf 和 getchar 等函数会在stdin 中读取数据,若上述缓冲区中已存在数据,则直接读取其中的数据,若上述缓冲区为空,则上述函数会挂起,等待数据缓冲的完成( 用户输入回车键或数据缓冲区满后, stdin 会进行数据缓冲,之后上述函数才能继续执行)。 用户一次输入的数据可能会超过 scanf 、getchar 等函数调用所需要的数据,那么所需数据被读取后,剩余的数据仍会存放在缓冲区中,之后的函数调用会直接读取 stdin 中已有的数据。只有当缓冲区为空后,scanf 等函数才会等待用户输入,实际应该是等待stdin的缓冲。
解决办法

  1. 最简单就是在scanf()函数扫描前留空格.
     
    c
    scanf(" %c",&ch);
  2. 可以使用 fflush() 函数清理缓冲区。C标准规定 fflush()函数可用来刷新输出(stdout)缓冲区(一般是将缓冲区数据写回存储设备)。但对于标准输入(stdin)则没有明确定义。部分编译器定义了 fflush( stdin )的实现,如微软的VC。也就是不同的编译器对于 fflush( stdin )的支持可能不同。GCC编译器没有定义它的实现,所以不能使用 fflush( stdin )来刷新输入缓冲区。



posted @ 2020-04-24 10:12  传说中的旅行者  阅读(93)  评论(0)    收藏  举报