当前位置: 首页 > news >正文

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

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

  • 前言
  • 预备知识
    • 回车和换行的区别
    • 输出缓冲区
      • /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; // 100Mdouble bandwidth = 10 * 1024 * 1024 * 1.0; //1M/Sdouble 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

谢谢观看

谢谢观看

相关文章:

  • 微软AI文生图新突破,用于图像生成的多LoRA组合训练模型Multi-LoRA-Composition
  • 02-接口interface 新花样
  • 持安科技亮相张江高科895创业营,总评分第三名荣获「最具创新性企业」!
  • vue diff算法介绍
  • JOSEF约瑟 漏电继电器LLJ-400F 配套零序互感器φ100mm 50-500mA 0.1S 导轨安装
  • 290.【华为OD机试】连续出牌数量(深度优先搜索DFS—JavaPythonC++JS实现)
  • 如何准确获取PDF文件中的标题
  • mac苹果电脑c盘满了如何清理内存?2024最新操作教程分享
  • Stable Video文本生成视频公测地址——Scaling Latent Video Diffusion Models to Large Datasets
  • 【小程序】媒体API能力集成指南——图片API
  • web运行时安全
  • 【并发编程】线程基础知识
  • 我是如何写作的?
  • 深入理解分库、分表、分库分表
  • C#学习总结
  • 【391天】每日项目总结系列128(2018.03.03)
  • 002-读书笔记-JavaScript高级程序设计 在HTML中使用JavaScript
  • 2017 年终总结 —— 在路上
  • AzureCon上微软宣布了哪些容器相关的重磅消息
  • HTTP中的ETag在移动客户端的应用
  • MySQL主从复制读写分离及奇怪的问题
  • ng6--错误信息小结(持续更新)
  • node-glob通配符
  • vue--为什么data属性必须是一个函数
  • vue自定义指令实现v-tap插件
  • 不上全站https的网站你们就等着被恶心死吧
  • 道格拉斯-普克 抽稀算法 附javascript实现
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 关于 Cirru Editor 存储格式
  • 机器学习 vs. 深度学习
  • 计算机常识 - 收藏集 - 掘金
  • 前端每日实战:61# 视频演示如何用纯 CSS 创作一只咖啡壶
  • 三栏布局总结
  • 什么软件可以剪辑音乐?
  • 视频flv转mp4最快的几种方法(就是不用格式工厂)
  • 用Canvas画一棵二叉树
  • ionic异常记录
  • #HarmonyOS:Web组件的使用
  • %3cscript放入php,跟bWAPP学WEB安全(PHP代码)--XSS跨站脚本攻击
  • (173)FPGA约束:单周期时序分析或默认时序分析
  • (5)STL算法之复制
  • (7)STL算法之交换赋值
  • (C#)Windows Shell 外壳编程系列4 - 上下文菜单(iContextMenu)(二)嵌入菜单和执行命令...
  • (js)循环条件满足时终止循环
  • (LeetCode) T14. Longest Common Prefix
  • (编程语言界的丐帮 C#).NET MD5 HASH 哈希 加密 与JAVA 互通
  • (附源码)ssm基于jsp的在线点餐系统 毕业设计 111016
  • (十二)springboot实战——SSE服务推送事件案例实现
  • (转)JAVA中的堆栈
  • (转)Linux整合apache和tomcat构建Web服务器
  • (转)如何上传第三方jar包至Maven私服让maven项目可以使用第三方jar包
  • (转)用.Net的File控件上传文件的解决方案
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • ***利用Ms05002溢出找“肉鸡
  • *1 计算机基础和操作系统基础及几大协议