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

news2024/11/19 2:46:31

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

  • 前言
  • 预备知识
    • 回车和换行的区别
    • 输出缓冲区
      • /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

谢谢观看

谢谢观看

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

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

相关文章

ABAP - SALV教程07 斑马纹显示和SALV标题

SALV设置斑马纹和标题 METHOD set_layout.DATA: lo_display TYPE REF TO cl_salv_display_settings. * 取得显示对象lo_display co_alv->get_display_settings( ).* 设置ZEBRA显示lo_display->set_striped_pattern( X ). * 设置Titlelo_display->set_list_he…

内存空间担保机制

什么是内存空间担保机制&#xff1f; 内存空间担保机制&#xff08;Memory Space Guarantee&#xff09;是垃圾回收&#xff08;Garbage Collection&#xff09;算法中的一种策略。它用于在进行垃圾回收过程&#xff08;如Minor GC或Full GC&#xff09;时&#xff0c;确保老年…

Linux创建,删除用户

Linux创建&#xff0c;删除用户 怎么登陆xshell创建用户设置密码 删除用户 我找了好久市面上的资料&#xff0c;我觉得写得不好&#xff0c;所以自己写一个 怎么登陆xshell ssh用户名ip地址 创建用户 adduser 用户名 设置密码 passwd 用户名 删除用户 userdel -r 用户…

【小尘送书-第十一期】编程的基石,开发的核心:《算法秘籍》

大家好&#xff0c;我是小尘&#xff0c;欢迎你的关注&#xff01;大家可以一起交流学习&#xff01;欢迎大家在CSDN后台私信我&#xff01;一起讨论学习&#xff0c;讨论如何找到满意的工作&#xff01; &#x1f468;‍&#x1f4bb;博主主页&#xff1a;小尘要自信 &#x1…

利用小蜜蜂AI智能问答ChatGPT+AI高清绘图生成图文故事案例

利用小蜜蜂AI智能问答ChatGPTAI高清绘图生成图文故事案例 这段时间利用小蜜蜂AI网站做了一些编程、绘图以及数据分析方面的案例。再过几个月&#xff0c;我的大孙子就要出生了。我要用小蜜蜂AI智能问答和AI高清绘图为大孙子生成一个1-9的数字图文故事。 小蜜蜂AI网站可以扫如…

基于springboot+vue的高校教师科研管理系统

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

pdf如何压缩文件大小?pdf文件在线压缩方法介绍

在日常工作中&#xff0c;我们经常使用PDF文件进行传输和保存&#xff0c;然而&#xff0c;有时候我们会遇到过大的PDF文件&#xff0c;这不仅会导致传输困难&#xff0c;还会占用过多的设备空间&#xff0c;因此&#xff0c;我们需要对PDF压缩一下以便更轻松地传输和保存&…

基于springboot+vue的电商平台

博主主页&#xff1a;猫头鹰源码 博主简介&#xff1a;Java领域优质创作者、CSDN博客专家、阿里云专家博主、公司架构师、全网粉丝5万、专注Java技术领域和毕业设计项目实战&#xff0c;欢迎高校老师\讲师\同行交流合作 ​主要内容&#xff1a;毕业设计(Javaweb项目|小程序|Pyt…

Maven详细教程(很详细的)

一、maven概述 1.1、项目开发中的问题 1、我的项目依赖一些jar包&#xff0c;我把他们放在哪里&#xff1f;直接拷贝到项目的lib文件夹中?如果我开发的第二个项目还是需要上面的那些jar包&#xff0c;再把它们复制到我当前项目lib中&#xff1f;那如果现在是第三次了&#xf…

babylonjs入门-自由相机 FreeCamera

基于babylonjs封装的一些功能和插件 &#xff0c;希望有更多的小伙伴一起玩babylonjs&#xff1b; 欢迎加群&#xff08;点击群号传送&#xff09;&#xff1a;464146715 官方文档 中文文档 案例传送门 懒得打字 粘贴复制 一气呵成 ​

Mysql学习之MVCC解决读写问题

多版本并发控制 什么是MVCC MVCC &#xff08;Multiversion Concurrency Control&#xff09;多版本并发控制。顾名思义&#xff0c;MVCC是通过数据行的多个版本管理来实现数据库的并发控制。这项技术使得在InnoDB的事务隔离级别下执行一致性读操作有了保证。换言之&#xff0…

node.js最准确历史版本下载

先进入官网:Node.js https://nodejs.org/en 嫌其他博客多可以到/release下载:Node.js,在blog后面加/release https://nodejs.org/en/blog/release/ 点击next翻页,同样的道理

在 Ubuntu 终端输出不同颜色、粗体、下划线或其他样式的字体

嗯。调试时总发现自己打印的调试信息太过普通、单调&#xff0c;于是乎…… Notice 要在终端实现字体的特殊样式&#xff0c;通常通过使用特殊的控制字符来实现&#xff0c;而不是通过某语言本身的功能来实现。 在大多数终端中&#xff0c;可以使用 ANSI 转义序列来设置字体的…

爬虫入门到精通_实战篇7(Requests+正则表达式爬取猫眼电影)_ 抓取单页内容,正则表达式分析,保存至文件,开启循环及多线程

1 目标 猫眼榜单TOP100&#xff1a;https://www.maoyan.com/board 2 流程框架 抓取单页内容&#xff1a;利用requests请求目标站点&#xff0c;得到单个网页HTML代码&#xff0c;返回结果。正则表达式分析&#xff1a;根据HTML代码分析得到电影名称,主演,上映时间,评分,图片…

overleaf上传到arxiv 参考文献无法引用(?)

记一下overleaf上传到arxiv的bug 参考文献无法引用&#xff08;&#xff1f;&#xff09; 因为需要上传bbl文件而不是bib 用overleaf生成bbl 另外需要将bbl和txt的文件名设置成一样的

详解 JavaScript 中的数组

详解 JavaScript 中的数组 创建数组 注&#xff1a;在JS中的数组不要求元素的类型&#xff0c;元素类型可以一样&#xff0c;也可以不一样 1.使用 new 关键字创建 let array new Array()2.使用字面量方式创建(常用) let array1 [1,2,3,"4"]获取数组元素 使用下…

VMware Workstation Pro 17 虚拟机软件安装教程

VMware软件介绍 VMware Workstation是一款功能强大的桌面虚拟计算机软件&#xff0c;提供用户可在宿主机操作系统上同时运行不同的操作系统(虚拟化技术)&#xff0c;所运行的操作系统可方便的进行复制和移动&#xff0c;突破传统架构的限制。本文将以VMware Workstation Pro 1…

【leetcode】圆圈中最后剩下的数字

目录 1. 问题 2. 思路 3. 代码 4. 运行 1. 问题 本题即为典型的约瑟夫问题&#xff0c;通过递推公式倒推出问题的解。原始问题是从n个人中每隔m个数踢出一个人&#xff0c;原始问题变成从n-1个人中每隔m个数踢出一个人…… 示例 1&#xff1a; 输入: n 5, m 3 输出: 3…

Java快读

java的快读 (1)BufferedReader BufferedReader br new BufferedReader(new InputStreamReader(System.in));//定义对象String[] strings br.readLine().split(" ");//读取一行字符串&#xff0c;以空格为分隔转化为字符串数组int n Integer.parseInt(strings[0])…

H12-821_108

108.路由器R1和R2分别使用GigabitEthernet0/0/0直连&#xff0c;并试图建立OSFP邻居&#xff0c;然而邻居关系并没有成功建立&#xff0c;排错过程如图所示。那么以下哪一个操作可以使R1和R2邻居管理正常建立&#xff1f; A. [R2] ospf 1 [R2-ospf-1]area 0 [R2-ospf-1-area-0.…