C语言之缓冲区

您所在的位置:网站首页 c语言代码进入无限循环是会显示什么 C语言之缓冲区

C语言之缓冲区

2023-03-30 04:13| 来源: 网络整理| 查看: 265

先来看一段代码:

#include int main() { printf("我不会被输出。。。"); while(1); }

上面的main方法中只有一个printf函数和一个死循环,作用看似很简单:输出一句话然后进入死循环。但是它的实际运行结果可能会让你很意外:什么也没输出,程序进入了死循环。printf似乎被跳过了?要解释这一现象,就要了解C语言的缓冲区。

什么是缓冲区

缓冲区又称为缓存,它是内存空间的一部分。也就是说,在内存空间中预留了一定的存储空间,这些存储空间用来缓冲输入或输出的数据,这部分预留的空间就叫做缓冲区。缓冲区根据其对应的是输入设备还是输出设备,分为输入缓冲区和输出缓冲区。

为什么要引入缓冲区: 比如我们从磁盘里取信息,我们先把读出的数据放在缓冲区,计算机再直接从缓冲区中取数据,等缓冲区的数据取完后再去磁盘中读取,这样就可以减少磁盘的读写次数,再加上计算机对缓冲区的操作大大快于对磁盘的操作,故应用缓冲区可大大提高计算机的运行速度。 打个比方,一个搬砖龙鸣工正在工地上搬砖,他肯定会先把砖头放进小推车中,等小推车放满了后再把小推车运走,而不会地上拿起一块砖就开始运。这里的小推车的作用就好比是缓冲区,它大大提高了我们的工作效率。

现在您基本明白了吧,缓冲区就是一块内存区,它用在输入输出设备和CPU之间,用来缓存数据。它使得低速的输入输出设备和高速的CPU能够协调工作,避免低速的输入输出设备占用CPU,解放出CPU,使其能够高效率工作。

缓冲区的大小: 如果我们没有自己设置缓冲区的话,系统会默认为标准输入输出设置一个缓冲区,这个缓冲区的大小通常是4096个字节的大小,这和计算机中的分页机制有关,因为进程在计算机中分配内存使用的就是分页与分段的机制,并且每个页的大小是4096个字节,因此通常情况下缓冲区的大小会设置为4096个字节的大小。

缓冲区的类型

缓冲区分为三种类型:全缓冲、行缓冲和不带缓冲。

全缓冲 在这种情况下,当填满标准I/O缓存后才进行实际I/O操作。全缓冲的典型代表是对磁盘文件的读写。

行缓冲 在这种情况下,当在输入和输出中遇到换行符时,执行真正的I/O操作。这时,我们输入的字符先存放在缓冲区,等按下回车键换行时才进行实际的I/O操作。典型代表是标准输入(stdin)和标准输出(stdout)。

不带缓冲 也就是不进行缓冲,标准出错情况stderr是典型代表,这使得出错信息可以直接尽快地显示出来。

输出缓冲区:

当使用printf/puts/puchar等函数显示数据时,并不会直接显示在屏幕上,而是先放入输出缓冲区中(提高程序的运行),当满足一定条件时才会显示在屏幕上:

遇到换行符/n, 从输出转换到输入状态(即遇到scanf函数) 当程序结束(方法正常结束,或者调用exit(0)使程序强制退出) 手动刷新,fflush(stdout); 当缓冲区满4k时自动输出。

至此,我们应该能解释文章开头代码的printf为什么没有输出到控制台了:运行到printf方法后,编译器将数据缓存到了内存的缓冲区中等待被输出。不巧的是,我们的程序不满足它输出的条件,因此它并没有输出,它只是一直存在于缓冲区中。

我们可以把程序改写成下面这样(使用任意一个方法都可以使printf正确输出了):

#include int main() { int n; printf("我能被正确输出啦!!!"); //printf("\n"); 方法1 //scanf("%d",&n); 方法2 //exit(0); 方法3 //fflush(stdout); 方法4 for(;;) { //printf("我会不断地填充缓冲区"); 方法5 } } 输入缓冲区:

在了解了输出缓冲区后,我们再来看看输入缓冲区的问题:

#include int main() { int i = 0; char c = '0'; scanf("%d", &i); scanf("%c", &c); printf("-%d-\n", i); printf("-%c-\n", c); } /* in:1← out:-1- - - in:1 b← out:-1- - - */

main方法中定义了两个变量,然后从控制台输入它们的值,再输出它们。当我们在控制台输入1再按回车后,发现程序结束了并输出了。从输出结果来看,很明显是因为回车符被当成了字符输入。解决这种问题的方法就是在%c前加一个空格符。

下面我们再看一段代码:

#include int main(){ int a = 0; int b = 0; scanf("%d",&a); scanf("%d",&b); printf("-%d-\n",a); printf("-%d-\n",b); } /* in:a← out:-0- -0- */

这次我们直接输入a再回车,发现程序结束并且输出了0和0。当输入的有垃圾或错误数据时,a和b都无法正确获取了。

在终端输入的数据会先存储到输入缓冲区中,然后再根据占位解析成对应的数据,如果前一次输入的数据有残留的垃圾,会影响后续数据的输入。

输入字符(char)时,前一次的输入会残留一个空格或’\n’,解决方法:在%c前加一个空格。 如果输入时有若干垃圾数据,会影响后续所有数据的匹配。 1. 使用正则表达式,必须确定有垃圾数据时再使用。 scanf("%*[^\n]"); //从缓冲区中获取数据但不存储到变量中 scanf("%*c"); 2. 设置缓冲区中的位置指针,可以用来清空缓冲区。 stdin->_IO_read_prt 开始位置 stdin->_IO_read_end 结束位置。 stdin->_IO_read_prt = stdin->_IO_read_end

要解决上方代码的问题,可以采用这种方法(此时,第二个数据就能被正确接收了)

#include int main() { int num = 0; if(0 == scanf("%d",&num)) //scanf的返回值表示正确接受的数据的数量 { //scanf("%*[^\n]"); //scanf("%*c"); stdin->_IO_read_ptr = stdin->_IO_read_end; } int num1 = 0; scanf("%d",&num1); printf("%d %d\n",num,num1); } /* in:a← 5← out:0 5 */


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3