C/C++_IO缓存问题

news2024/9/21 3:31:20

平常在练习的时候,总是忽略IO的缓存,这篇笔记记录下C和C++的缓存问题。

1 什么是缓存

缓存就是程序在内存中开辟的用来存放数据的空间,之所以叫缓存是因为这个变量时用来暂存数据用的。比如下面的语句,

int a ; 
int *p = malloc(sizeof(int) * 1);

a 和 p都是缓存,

2 应用缓存、库缓存、内核缓存,驱动缓存

应用缓存:应用代码在内存中开辟的缓存空间,比如应用层定义的变量。
库缓冲:库函数代码在内存中开辟的缓存空间。
内核缓存:内核代码在内存中开辟的缓存空间。
驱动缓存:驱动层的层序开辟的缓存,工作中驱动层接收到ROS层传下的数据进行存储并处理。
在这里插入图片描述

3 标准IO读写数据时,数据在缓存中流向

应用程序读写文件时候,数据并不会直接写到文件中,而是一层层向上或向下流动。
比如读数据时,内核函数通过设备驱动代码将数据从文件中读到内核缓存中;
标准IO函数,比如从外部设备读数据时用的cin scanf等IO函数,数据的执行流程是,将数据从内核缓存读到IO库缓存中。
最后,应用程序从IO库缓存中读取数据。
写数据的过程与读数据正好相反。

4 库缓存的三种缓冲方式:无缓冲,行缓冲,全缓冲

缓冲就是暂存的意思,就是把数据暂时存在库缓存中,库缓存一般为4096字节。

4.1 为什么需要暂存?

之所以要暂存是处于速度方面的考虑。比如,只输入一个字符,就立刻调用文件IO将数据写到磁盘,会降低效率,所以先将数据暂存起来,当达到“刷新”条件时候(刷新:就是将缓存中的数据取走),再一次性的将缓存的数据写到文件中。

4.2 无缓冲

无缓冲就是,主要库缓存中有数据就立刻刷新,哪怕只有一个字符也会立刻刷新。无缓冲非常适合用于输出错误信息,因为出错信息很紧急,不能被积压,所以有了错误信息后就应该被立即无条件刷新输出。stderr(标准出错输出)就是专门用来输出错误信息的,所以就是“无缓冲”的情况。无缓冲特点是数据立刻被刷新,但是效率会比较低。

无缓冲的刷新方式

只要“库缓存”中有数据就无条件立即刷新输出,比如下面的例子。

#include <stdio.h>

void main()
{
	fprintf(stderr, "hello wolrd"); 

	while(1);

	return 0;
}

在这里插入图片描述

hello wolrd被立即输出。

4.3 行缓冲

数据会积压,直到“满一行”时才会刷新,然后将数据输入/输出。\n就是一行的判断条件之一,只要数据中有\n,就代表数据满一行了。也就是说,对于标准IO库的库缓存来说,\n不仅仅只是换行,还是数据满一行的标志。
行缓冲非常适合用于正常的键盘输入和打印显示(正常的人机交互),人与计算机的交互就跟人与人的说话一样,一句一句的来是最方便的。人机交互时一行其实就是一句,**stdin、stdout(标准输入、标准输出)**就是专门用来进行正常人机交互用的,所以都是行缓冲的,满足一行的条件时就会立即刷输入、输出数据。C标准中,stderr为无缓冲,stdin和stdout为行缓冲。
但是不同的OS中不一定会严格的按照C标准,比如:
在Linux下:stderr为“无缓冲”、stdin、stdout为“行缓冲”,遵守了c标准的规定;
在Windows下:stderr、stdin、stdout都是无缓冲,只要库缓存有数据就会立即刷新。

行缓冲刷新方式

#include <stdio.h>

void main()
{
		fprintf(stdout, "hello wolrd");
		fprintf(stdout, "@@@@@@@@@@@");
		printf("22222222222");
		fprintf(stdout, "!!!!!!!!");
		
		while(1); //死循环
		return 0;
}

在这里插入图片描述
【linux下运行结果】
在这里插入图片描述
【windows下运行结果】

上面实验代码中,LInux下运行时,如果加了\n时,即fprintf(stdout, “!!!!!!!!\n”);数据就会全部被输出。

4.3 全缓冲

特点是必须等到“库缓存”的空间全部被数据积压满后,才会输出。就好比说以一盆水满了以后才会溢出一样。读写硬盘上普通文件时就是“全缓冲”,比如以写为例,写普通文件时由于不涉及人机交互时的“及时性”问题,所以并不需要立即写到文件中,完全可以先将大量数据积压到缓存中,等填满整个缓存之后再一次性刷新输出。读写fopen所打开的普通文件时,就是“全缓冲”的。

全缓冲的刷新方式

在这里插入图片描述
在这里插入图片描述
fp指向了普通文件,此时就是全缓存的,尽管"hello world\n"中有个一\n,但是全缓冲不受\n影响,由于数据太少,还不足以填满整个库缓存,所以无法被刷新,此时打开file.txt文件时,里面不会有数据。当调用fclose()函数时候,数据就会被刷新。

5 缓冲的其它刷新方式

当不满足刷新条件时,我们可以使用其它“刷新方式”来刷新?可以调用fflush函数进行刷新。

  #include <stdio.h>
   int fflush(FILE *stream);

下面例子

void main(void)
{
	fprintf(stdout, "hello wolrd");
	fprintf(stdout, "@@@@@@@@@@@");
	printf("22222222222");
	fprintf(stdout, "!!!!!!!!");
	fflush(stdout); //手动刷新
	
	while(1); //死循环

	return 0;
}

6 平时练习时,cin,scanf读取数据时存在的问题

从键盘输入数据时,不管输入什么数据,只有敲了回车(\n)后才会输入,从键盘输入数据时,输入的最后输入的字符一定是’\n’。
但是scanf等读取函数从“库缓存”里面读取数据时,往往会将\n留在“库缓存”里面,如果后续紧跟着scanf/fscanf/getc/getchar等函数来读取数时,读取到的将是“库缓存”中遗留的’\n’,或者其它无用字符。
比如,输入w \n ,可以看到第二个scanf读取到了回车。
在这里插入图片描述
**注意:**以%d、%f格式输入时,输入的必须是0~9的数字,如果是a、b、c、d的英文字母的话,会直接将这些字符遗留在库缓存中,影响后续的读取。
如何解决呢?
很简单,只要将“库缓存”中所有的字符全部取走,将“库缓存”全部清空后,就不会受到这些遗留字符的干扰,不管使用getchar、getc、scanf(“%c”, &ch)中那个函数,都能将遗留的字符全部取走,下面使用最简洁getchar来实现。
比如以%d接收数字时候,输入的a后,就不会被解析,而是留在缓冲中。
在这里插入图片描述
这种情况下就可以用scanf将缓冲中的数据全部读走,学习时候最常用的就是while(getchar() != ‘\n’); 方式。
在这里插入图片描述
上面都是学习过程中遇到的问题,实际工作中,最多的是通过条件编译输出,并没有遇到输入的时候。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/58242.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

2023最新SSM计算机毕业设计选题大全(附源码+LW)之java高考信息发布平台cnj61

最近大四学弟学妹们开始准备设计了&#xff0c;有一些问题问我&#xff0c;比如设计怎么做&#xff0c;有没有模板等等吧&#xff0c;大家都没有去学校&#xff0c;老师都是通过远程指导的&#xff0c;答辩也是远程答辩&#xff0c;这种情况下同学们不在一起&#xff0c;可能碰…

PPT素材、PPT模板免费下载

想要PPT模板、PPT素材、PPT图表、PPT教程等相关素材&#xff0c;一定要知道这几个网站&#xff0c;不仅能免费下载&#xff0c;质量还非常高&#xff0c;话不多说&#xff0c;直接上内容。1、菜鸟图库 https://www.sucai999.com/search/ppt/0_0_%E6%9E%81%E7%AE%80_0.html?vNT…

译码器的电路

译码器与编码器正好是相反的操作&#xff0c;编码器是把高低电平转换成二进制信号 译码是把二进制编码转换成高低电平输出 译码器的逻辑功能是将每一个对应的二进制编码转化成高低电平或者另一种信号&#xff0c;是编码的另一种逆向的操作&#xff0c;编码器有二进制&#xf…

【专栏】核心篇07| Redis “jio”美的集群模式

关注公众号 【离心计划】呀&#xff0c;一起逃离地球表面 Redis专栏合集 【专栏】01| Redis夜的第一章 【专栏】基础篇02| Redis 旁路缓存的价值 【专栏】基础篇03| Redis 花样的数据结构 【专栏】基础篇04| Redis 该怎么保证数据不丢失&#xff08;上&#xff09; 【专…

Tableau:详细表达式(LOD表达式)的计算过程

写在最前 很早以前写过一篇关于Tableau详细级别表达式的博客&#xff0c;具体可以参考https://blog.csdn.net/yeshang_lady/article/details/104945361。前序博客重点在于介绍三种详细级表达式&#xff0c;这篇博客主要介绍使用详细级别表达式时的注意事项。 1 LOD表达式与非聚…

毕业设计-深度学习的施工安全帽图像检测算法

目录 前言 课题背景和意义 实现技术思路 实现效果图样例 前言 &#x1f4c5;大四是整个大学期间最忙碌的时光,一边要忙着备考或实习为毕业后面临的就业升学做准备,一边要为毕业设计耗费大量精力。近几年各个学校要求的毕设项目越来越难,有不少课题是研究生级别难度的,对本科…

2022 年超详细过程步骤讲解 CentOS 7 安装jdk1.8

linux系统下安装jdk以及环境变量的设置、真的是比window下方便一万倍 1、卸载系统自带jdk 1.1 查看系统自带jdk java -version1.2 查看java相关文件 rpm -qa | grep java1.3 删除openjdk相关文件 我上边有四个对应文件 命令介绍&#xff1a; rpm     管理套件 -e   …

VMware=win’server2016=Hyper-V的使用安装

VMware=win’server2016=Hyper-V的使用安装 实验准备 VMware软件--win’server2016虚拟机一台 从外部本地计算机或U盘 上传/共享 一个映像文件进虚拟机 win2016虚

【Maven】Maven快速入门2022版:从概念、安装到基本使用

本期目录一、 简介1. Maven优点2. 强大的依赖管理3. 工作原理3.1 POM3.2 Maven模型二、 安装配置1. Maven核心程序解压与配置1.1 解压1.2 指定本地仓库1.3 配置阿里云提供的镜像仓库1.4 配置Maven工程的基础JDK版本2. 配置环境变量2.1 检查 JAVA_HOME2.2 配置MAVEN_HOME三、 Ma…

9、Springboot整合Swagger3

1.什么是Swagger&#xff1f; 我们在编写了大量的接口之后&#xff0c;如果接口的调用者不是自身的话&#xff0c;那么就会面临要编写接口文档的苦恼&#xff0c;这时候Swagger就应运而生了。 Swagger 是一个规范和完整的框架&#xff0c;用于生成、描述、调用和可视化 RESTf…

笔试强训(四十)

目录一、选择题二、编程题2.1 发邮件2.1.1 题目2.1.2 题解一、选择题 &#xff08;1&#xff09;上网的时候&#xff0c;访问某个页面却突然出现了某个运营商的网页&#xff0c;出现此问题可能的原因是&#xff08;A&#xff09; A.DNS劫持 B.DDos攻击 C.MAC地址欺骗 D.伪造DH…

springboot+zookeepr+dubbo的远程服务调用

首先一定确保zookeeper正常工作 公共接口模块 为了简化代码&#xff0c;可以把需要其他服务调用的接口&#xff0c;抽取为公共接口模块dubbo-common-service&#xff0c; public interface TestService {public String clientTest(); }服务提供方 导入dubbo、zookeeper依赖…

Python学习基础笔记十六——函数嵌套

1、函数的嵌套调用 def max(a, b):if a > b:return aelse:return bdef the_max(x, y, z): # 函数的嵌套调用c max(x, y)return max(c, z)print(the_max(1, 2, 3)) 2、函数的嵌套定义&#xff1a; a 1def outer():a 1def inner():b 2print(a)print(Inner)def inner2(…

【GlobalMapper精品教程】033:影像地图羽化方式详解

在Globalmapper中,可以很方便的对影响进行多种羽化值设置。 文章目录 1. 不要羽化此图层2. 沿一个或多个边缘羽化3. 羽化到有效数据的多边形覆盖4. 在当前选定的多边形内羽化5. 裁剪到选定的边界,而不是羽化6. 在多边形外部羽化,而不是内部加载配套案例数据包中的data033.ra…

Java基于springboot+vue的家用电器销售购物商城系统 前后端分离

开发背景和意义 随着人们生活的改变&#xff0c;家电基本在家家户户都存在&#xff0c;常用的家电例如冰箱&#xff0c;洗衣机&#xff0c;电视机&#xff0c;空调等设备可以让人们的生活方式变的更加快捷舒适&#xff0c;通常情况下人们购买家电的话都是到指定的家电销售场所…

带你全方位了解光谱共焦位移传感器

任何一个行业的产生和发展都离不开科学技术的进步&#xff0c;这也是市场需求量不断扩大产生的对行业的促进&#xff0c;促使相关人员对产品的不断更新换代&#xff0c;光谱共焦位移传感器的发展也是发生着日新月异的变化。 光谱共焦位移传感器原理&#xff1a; 一束白光&#…

vue基于 input 实现密码的显示与隐藏功能

目录前言&#xff1a;一、准备图标二、Vue程序界面的展示三、代码总结&#xff1a;前言&#xff1a; 大家都知道&#xff0c;一般情况下&#xff0c;输入框的密码我们是看不到密码的&#xff0c;只有当我们点击查看密码的小图标时&#xff0c;密码才会显现出来&#xff0c;实现…

3D深度相机---结构光

去年的仪器仪表的课有汇报&#xff0c;我还专门为3D深度像机做了个调研&#xff0c;一直用inter realsense的&#xff0c;最近老师让看结构光方案的&#xff0c;正好总结一下。 1. 结构光(Structured-light) 由于基于双目立体视觉的深度相机对环境光照强度比较敏感&#xff0…

台式电脑怎么格式化重装系统

我们都知道电脑重装系统默认是会格式化磁盘的&#xff0c;那么如果是自己选择需要格式化的其它磁盘需要怎么操作呢&#xff1f;一般我们都是在pe里面手动格式化磁盘&#xff0c;这样就能避免直接格式化导致的某些问题了&#xff0c;下面就来讲讲台式电脑怎么格式化重装系统吧。…

[信息系统项目管理师-2023备考]信息化与信息系统(二)

目录 一、软件工程 1.需求 1.1 需求分类 1.2 需求分析 2.UML 2.1 类图 2.2 对象图 2.3 构件图 2.4 组合结构图 2.5 用例图 2.6 顺序图 2.7 通信图 2.8 定时图 2.9 状态图 2.10 活动图 2.11 部署图 3.软件架构 4.软件设计 4.1 设计模式分类 4.2 能力成熟度模…