对缓冲区的初步认识——制作进度条小程序

对缓冲区的初步认识--进度条小程序

  • 前言
  • 预备知识
    • 回车和换行的区别
    • 输出缓冲区
      • /n 有清空输出缓冲区的作用
      • stdout是什么?
      • 验证一切皆文件
      • 为什么是\n行刷新?
    • 倒计时程序
      • 原理
    • 代码实现
    • 为什么这里要强制刷新?没有会怎样?
    • 为什么是输出的是格式是%2d?正常的行不行?
  • 进度条程序
    • 数组长度为什么是102
    • 为什么我们要初始化数组?
    • 旋转的指针怎么实现的?
    • vison1完整代码
    • vison2
      • 构造场景
    • 效果
    • 稍微改进一下download函数
  • 最终效果
  • 谢谢观看

前言

这个小程序最好还是在Linux环境下实验,更能体现缓冲区作用

预备知识

回车和换行的区别

我们经常把回车换行连起来说,但他们是一样的吗?
换行:只有竖直方向改变
在这里插入图片描述
回车:只有横轴方向改变
在这里插入图片描述
回车换行:从第一行的末尾到第二行的起始位置
在这里插入图片描述
老式键盘的回车键 就是这个横竖造型

在这里插入图片描述
在c语言中\r是回车 \n是回车换行

输出缓冲区

我们暂且把缓冲区只是认为是内存的一块空间
为什么要有缓冲区呢?如果没有缓冲区 cup要更多次访问硬件设备
举个例子就像是我们宿舍扔垃圾总是攒得有点多了才开始扔,而不是有一点就扔

/n 有清空输出缓冲区的作用

例子:

这里有两个小程序 唯一的区别就是 第5句是否加了\n

#include <stdio.h>
#include<unistd.h>
int main()
{                                                                                                  
    printf("hello word");
    sleep(3);
   
	return 0;
}

#include <stdio.h>
#include<unistd.h>
int main()
{                                                                                                  
    printf("hello word\n");
    sleep(3);
    return 0;
}

这两个程序执行的结果是 第二个程序直接打印了,第一个程序快结束时才打印 这是为什么呢?

QQ2024229-164212

是因为第一个程序的sleep先执行吗?不是的 没有多线程的情况都是从上到下执行的。答案是 \n是作为情况缓冲区的标志
没有\n的时候hello word还在缓冲区了 程序结束了才释放
怎么解决这个问题呢?
我们在后面加fflush(stdout)
有个问题这个参数好奇怪

stdout是什么?

在这里插入图片描述
是一种文件类型的变量用于控制显示器的 ,我们在c语言阶段也学过File的指针来操作文件的读写。为什么能把显示器也看成文件呢?因为在Linux下一切皆文件

验证一切皆文件

我们在/dev/pts/ 1 中写的文件 却在另一个终端显示了!
在这里插入图片描述

为什么是\n行刷新?

因为如果只追求效率 全部内容到缓冲区才刷新 这样会爆发式的内容增多,人来不及看。一行一行的刷新符合人的习惯。

倒计时程序

原理

我们写1的时候光标到下一个格子,然后又返回来写2把1覆盖,同一个位置不停的刷新
在这里插入图片描述

代码实现

#include <stdio.h>                                                                                 
#include<unistd.h> // linux环境 如果windos <windows.h>

   int main()
   {
     int cnt = 10;
     while(cnt >= 0)
     {
       printf("%2d\r",cnt);// 如果不加2 长度不统一 覆盖不完全 
       fflush(stdout);
      sleep(1);
      cnt--;
    }
    printf("\n"); // 这里的作用是避免命令提示符覆盖
    return 0;
 }

为什么这里要强制刷新?没有会怎样?

我们先把fflush屏蔽了 看看会发生什么
在这里插入图片描述
在这里插入图片描述

只输出个0,为什么呢?
因为我们写一个字符串到缓冲区里,光标就回车了,然后再写就被覆盖了直到写到最后一个0没有东西能覆盖它了,于是就只把0从缓冲区输出到屏幕了。

为什么是输出的是格式是%2d?正常的行不行?

我们在屏幕上输出123是数字还是字符串呢?答案其实是字符串
如果我们就%d输出 看看会发什么
从10一下就到90了 这是因为 9只有一位 而10 有两位 只能覆盖一位所以显示就是90只把1覆盖了
在这里插入图片描述
在这里插入图片描述

我们已经了解了预备知识那么进入正题吧

进度条程序

我们要做的程序

QQ202431-214911

我们顶一个字符型数组bar长度为102用来存放进度#

数组长度为什么是102

因为我们用100个#来表示完全下载好 但是字符串结束的标准是’\0’所以我们至少要多用一个空间 但是为了保险再加一些也没关系

然后我们初始化数组

为什么我们要初始化数组?

因为数组不初始化放的都是随机值,我们等下按字符串输出时会出现乱码,最好以‘/0’初始化因为字符串输出遇到’/0‘结束!

 memset(bar, '\0', sizeof(bar)); 

之后我们在定义一个变量cnt表示进度到哪了?
每下载好一个bar[cnt] =‘#’ bar数组就存放一个字符 然后cnt++
直到 cnt <= 100

旋转的指针怎么实现的?

我们固定了输出的字符串长度为100在相当于长度为101的位置不停的写 |/-\ 覆盖着写形成了动画效果就像连环画一样
用一个字符数组储存|/-\ ,进度+1 就打印一个数组里面的内容 arr[p]
为了不越界 p 还要模4

vison1完整代码

但是这个版本就是空架子,没有和具体的场景联系起来

 void processbar()
 {
	 char bar[length];
	 int cnt = 0;
	 memset(bar, '\0', sizeof(bar)); 
	 while (cnt < length) 
	 {
		 printf("[%-100s] [%3d%%] [%c]\r", bar,cnt, lable[cnt%4]); //-100左对齐:长度一百   %%:百分号
		 bar[cnt++] = '#';
		 fflush(stdout); // 如果不强制刷新的话屏幕不显示结果
		 Sleep(50); // 毫秒为单位
	 }
	 printf("\n");
}

vison2

对于我们下载应用这个场景,我们的进度条函数应该知道文件的大小,和当前已经下载了多少时实的更新。所以我们考虑对进度条函数加两个参数 1个total 和 1currnt 代表总的大小 和已经下了的大小

 void processbar(double total, double current)
 {
	 char bar[length];
	 int cnt = 0;
	 memset(bar, '\0', sizeof(bar)); 
	 double rate = (current*100.0) / total;
	 int loop = (int)rate;
	 while (cnt <= loop)
	 {
	
		 printf("[%-100s] [%.1lf%%] [%c]\r", bar, rate, lable[cnt % 4]); //-100左对齐:长度一百   %%:百分号
		 bar[cnt++] = '#';
		 fflush(stdout); // 如果不强制刷新的话屏幕不显示结果
		 Sleep(50); // 毫秒为单位
	 }
	 printf("\n");
 }

构造场景

void loaddown() 
{
    double filesize = 100 * 1024 * 1024 * 1.0; // 100M
    double bandwidth = 10 * 1024 * 1024 * 1.0; //1M/S
    double current = 0.0;

    printf("download begin, current: %lf\n", current);
 
    while (current <= filesize) 
    {
        processbar(filesize, current);
        current += bandwidth;
        Sleep(100);
     
    }
    printf("\ndownload completed\n");
}

我们稍微调整一下进度条函数 调整了两个地方
1.把sleep函数关闭了 因为我们每次都是从零打印的有sleep函数这个卡顿就明显了
2.把printf提在循环外面了因为loaddown多次调用进度条函数在循环里面每次重零打印会卡

 void processbar(double total, double current)
 {
	 char bar[length];
	 int cnt = 0;
	 memset(bar, '\0', sizeof(bar)); 
	 double rate = (current*100.0) / total;
	 int loop = (int)rate;
	 while (cnt <= loop)
	 {
	 	//printf("[%-100s] [%.1lf%%] [%c]\r", bar, rate, lable[cnt % 4]); //-100左对齐:长度一百   %%:百分号
		 bar[cnt++] = '#';
		
		// Sleep(50); // 毫秒为单位
	 }
	 printf("[%-100s] [%.1lf%%] [%c]\r", bar, rate, lable[cnt % 4]); //-100左对齐:长度一百   %%:百分号
	 fflush(stdout); // 如果不强制刷新的话屏幕不显示结果
 }

效果

QQ202431-231356

稍微改进一下download函数

♥1:每个文件的大小并不是一样的,我们要根据实际情况传参数。
♥2:我们把进度条函数当作download的回调函数。这样做有什么好处呢?
我们以后修改进度条函数的时候可以不用修改download函数

void loaddown(double filesize,callback_t cb) 
{

    double current = 0.0;

    printf("download begin, current: %lf\n", current);
 
    while (current <= filesize) 
    {
        cb(filesize, current);
        current += bandwidth;
        Sleep(100);
     
    }
    printf("\ndownload completed\n");
}

最终效果

QQ202431-233851

谢谢观看

谢谢观看

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

英福康INFICON XTC/3/2薄膜镀层控制仪软件和使用说明

英福康INFICON XTC/3/2薄膜镀层控制仪软件和使用说明

【嵌入式实践】【芝麻】【设计篇-3】从0到1给电动车添加指纹锁:项目整体规划

0. 前言 该项目是基于stm32F103和指纹模块做了一个通过指纹锁控制电动车的小工具。支持添加指纹、删除指纹&#xff0c;电动车进入P档等待时计时&#xff0c;计时超过5min则自动锁车&#xff0c;计时过程中按刹车可中断P档状态&#xff0c;同时中断锁车计时。改项目我称之为“芝…

[Python] 获取当前函数名的三种方法

使用__name__获取当前函数名 函数内和函数外都可以用__name__特殊属性。 def get_fun_name_1():fun_name get_fun_name_1.__name__print(fun_name)get_fun_name_1.__name__输出&#xff1a;get_fun_name_1 使用sys模块获取当前运行的函数名 sys._getframe()可以用来获取当…

编码器原理图

操作 旋转编码器提供两种交互方式&#xff1a; 每次用户旋转旋钮时&#xff0c;都会在 DT 和 CLK 引脚上产生低电平信号&#xff1a; 顺时针旋转会先使CLK引脚变为低电平&#xff0c;然后DT引脚也变为低电平。 逆时针旋转会使 DT 引脚首先变为低电平&#xff0c;然后 CLK 引脚…

linux环境安装cuda toolkit

1 全新安装 如果环境中没安装过cuda版本&#xff0c; 这种情况下比较简单。 直接在https://developer.nvidia.com/cuda-toolkit-archive选择对应版本下载安装即可。 如下为安装cuda toolkit 11.8. 2 环境中已经存在其他版本 这种情况下比较复杂一些。 首先要确认最高支持的…

NLP - 共现矩阵、Glove、评估词向量、词义

Word2vec算法优化 J(θ): 损失函数 问题&#xff1a;进行每个梯度更新时&#xff0c;都必须遍历整个语料库&#xff0c;需要等待很长的时间&#xff0c;优化将非常缓慢。 解决&#xff1a;不用梯度下降法&#xff0c;用随机梯度下降法 &#xff08;SGD&#xff09;。 减少噪音&…

Javaweb之SpringBootWeb案例之自动配置的原理分析的详细解析

3.2.3 原理分析 3.2.3.1 源码跟踪 前面我们讲解了在项目当中引入第三方依赖之后&#xff0c;如何加载第三方依赖中定义好的bean对象以及配置类&#xff0c;从而完成自动配置操作。那下面我们通过源码跟踪的形式来剖析下SpringBoot底层到底是如何完成自动配置的。 源码跟踪技巧…

python-分享篇-控制摄像头

文章目录 准备代码效果 准备 安装cv2 pip install opencv-python &#xff08;如果只用主模块&#xff0c;使用这个命令安装&#xff09; pip install opencv-contrib-python &#xff08;如果需要用主模块和contrib模块&#xff0c;使用这个命令安装&#xff09; 我的代码l里…

C语言:预处理

C语言&#xff1a;预处理 预定义符号#define定义常量定义宏宏与函数对比 #操作符##操作符条件编译头文件包含库文件包含本地文件包含嵌套文件包含 预定义符号 C语⾔设置了⼀些预定义符号&#xff0c;可以直接使⽤&#xff0c;预定义符号也是在预处理期间处理的。 __FILE__ //…

ctf_show笔记篇(web入门---php特性)

目录 php特性 89&#xff1a;直接数组绕过preg_match当遇到数组时会直接报错输出0 90&#xff1a;这里利用了intval的特性 91&#xff1a;这里需要细节一点 92-93&#xff1a;这两题的方法很多可以发散思维 94&#xff1a;还是利用小数绕过例如4476.0 95&#xff1a;这里…

mysql根据指定顺序返回数据--order by field

在查询数据的时候&#xff0c;在in查询的时候&#xff0c;想返回的数据根据 in里的数据顺序返回&#xff0c;可以直接在orderby中通过 FIELD(字段名称逗号分隔的值的顺序) 进行指定&#xff1b;示例没有加 order by field添加 order by field效果

宝塔面板安装各种组件以及部署应用服务

在linux服务器安装宝塔面板 一、从宝塔官网下载exe安装包&#xff0c;安装命令从宝塔官网&#xff08;https://www.bt.cn/&#xff09;获取 yum install -y wget && wget -O install.sh http://download.bt.cn/install/install_6.0.sh && sh install.sh二、安…

C++复习笔记——多态

1 多态 基本概念&#xff1a; 静态多态&#xff1a;编译时多态&#xff0c;运算符重载和函数重载动态多态&#xff1a;运行时多态&#xff0c;派生类重写基类的虚函数实现 静态多态和动态多态的区别就是函数地址是早绑定(静态联编&#xff0c;静态绑定)还是晚绑定(动态联编&a…

使用pyannote-audio实现声纹分割聚类

使用pyannote-audio实现声纹分割聚类 # GitHub地址 https://github.com/MasonYyp/audio1 简单介绍 pyannote.audio是用Python编写的用于声纹分割聚类的开源工具包。在PyTorch机器学习基础上&#xff0c;不仅可以借助性能优越的预训练模型和管道实现声纹分割聚类&#xff0c;还…

一文了解docker与k8s

随着 k8s 作为容器编排解决方案变得越来越流行&#xff0c;有些人开始拿 Docker 和 k8s 进行对比&#xff0c;不禁问道&#xff1a;Docker 不香吗&#xff1f; k8s 是 kubernetes 的缩写&#xff0c;8 代表中间的八个字符。 其实 Docker 和 k8s 并非直接的竞争对手两者相互依存…

蜻蜓FM语音下载(mediadown)

一、介绍 蜻蜓FM语音下载&#xff08;mediadown&#xff09;&#xff0c;能够帮助你下载蜻蜓FM音频节目。如果你是蜻蜓FM会员&#xff0c;它还能帮你下载会员节目。 二、下载地址 本站下载&#xff1a;蜻蜓FM语音下载&#xff08;mediadown&#xff09; 百度网盘下载&#…

【JS】解构赋值注意点,解构赋值报错

报错代码 const 小明 { email: 6, pwd: 66 } const 小刚 { email: 9, pwd: 99 }const { email } 小明 const { email } 小刚 报错图 原因 2个常量重复&#xff0c;重复在同一个作用域内是不能重复的&#xff0c;例如大括号内{const a 1; const a 2} 小伙伴A提问 问&…

微信小程序云开发教程——墨刀原型工具入门(编辑页面)

引言 作为一个小白&#xff0c;小北要怎么在短时间内快速学会微信小程序原型设计&#xff1f; “时间紧&#xff0c;任务重”&#xff0c;这意味着学习时必须把握微信小程序原型设计中的重点、难点&#xff0c;而非面面俱到。 要在短时间内理解、掌握一个工具的使用&#xf…

探索Manticore Search:开源全文搜索引擎的强大功能

在当今信息爆炸的时代&#xff0c;数据的快速检索变得至关重要。无论是在电子商务网站、新闻门户还是企业内部文档&#xff0c;高效的搜索引擎都是确保用户满意度和工作效率的关键因素之一。而在搜索引擎领域&#xff0c;Manticore Search 作为一款开源的全文搜索引擎&#xff…

09 闭环线程 LoopClosing

文章目录 09 闭环线程 LoopClosing9.1 主函数&#xff1a;Run()9.1.1 闭环检测9.1.2 计算Sim3变换&#xff08;相似变换&#xff09;: ComputeSim3()9.1.4 闭环矫正: CorrectLoop() 09 闭环线程 LoopClosing 9.1 主函数&#xff1a;Run() 成员函数/变量访问控制意义CheckNewK…