循环队列及C语言实现二

  在我的上一篇博文中已经讲到循环队列的特点作用以及C语言实现,当然实现和操作的方式比较简单,在实际项目应用中略显粗糙。因此,这一篇提供一个进阶篇的实现与操作接口。具体函数作用可以参见我的注释部分,使用的时候直接把里面的接口函数放在一个头文件里面直接调用就可以啦,十分方便易用,但是可以实现的功能不可小觑哦,比如我在写高速USB设备驱动(20MB/s)以及网络抓包缓存的时候用到的都是这个看似简单的数据结构,所以还没有熟练运用的要加把劲了。需要注意的地方包括:

<1> 不再利用上一篇中 “q->front = (q->rear + 1) % q->size” 的关系来进行队列空还是满的判断了,这次利用 space 剩余缓存空间大小来判断。

<2> 写缓冲区的时候,要进行缓冲区剩余空间大小 space 的判断,如果要写入空间小于等于剩余空间,那么就可以将数据完全写入缓冲区,此时写入长度等于要写入的数据长度,否则只能将部分数据写入缓冲区,返回长度就等于剩余空间大小了。

<3> 读缓冲区同理,要进行当前缓冲区中可用缓存的大小的判断,也即已写入缓存大小的判断。若要读出的数据长度小于已写入缓存,那么返回长度为希望读出的数据长度,否则为已写入缓存的长度。

<4> 在写入和读出的时候尤其需要注意到达缓冲区边界的时候,数据和读写位置的处理。如果读写到了边界,那么就要分两次读取了,另外读写位置一定不能超越分配的缓冲区边界,所以在循环队列中数据的读写位置前移的时候都要对缓冲区长度取余以保证数据操作的安全性。

  下面就是代码部分了,若有不明或不妥之处,可以直接 send comments to me :-D

/** Queue operation API - 1.0** Copyright (C) 2016 SoldierJazz (SoldierJazz@163.com)** This program is free software; you can redistribute it and/or* modify it. **/#include <stdio.h>
#include <stdlib.h>
#include <string.h>/*** Queue - queue structure* @buf: queue buffer* @read: position of read* @write: position of write* @size: buffer size* @space: writable buffer size*/
typedef struct {char *buf;unsigned int read;unsigned int write;unsigned int size;unsigned int space;
} Queue;#define Avail(q) (q->size - q->space)/*** Queue_Init - init a queue* @q: pointer of queue* @size: size of buffer in queue** Must be called when started. */
void Queue_Init(Queue *q, int size)
{q->buf = (char *)malloc(sizeof(char) * size);q->read = 0;q->write = 0;q->size = size;q->space = size;
}/*** Queue_Destroy - destroy a queue* @q: pointer of queue*/
void Queue_Destroy(Queue *q)
{free(q->buf);
}/*** Queue_Empty - tests whether a queue is empty* @q: the queue to test*/
bool Queue_Empty(Queue *q) 
{return (q->space == q->size);
}/*** Queue_Full - tests whether a queue is full* @q: the queue to test*/
bool Queue_Full(Queue *q)
{return (q->space == 0);
}/*** AddQueue - add a byte to queue* @q: the queue to add to* @val: the char to add*/
bool AddQueue(Queue *q, char val)
{if (!Queue_Full(q)) {q->buf[q->write] = val;q->write = (q->write + 1) % q->size;q->space--;return true;} return false;
}/*** DelQueue - delete a byte from queue* @q: the queue to delete from* @val: the char deleted*/
bool DelQueue(Queue *q, char *val)
{if (!Queue_Empty(q)) {*val = q->buf[q->read];q->read = (q->read + 1) % q->size;q->space++;return true;}return false;
}/*** WriteQueue - write buffers to queue* @q: the queue to write in* @buf: pointer of write buffer* @len: length of write buffer*/
static int WriteQueue(Queue *q, char *buf, unsigned int len)
{unsigned int ret = 0;unsigned int rest = q->size - q->write;if (!Queue_Full(q)) {if (q->space >= len) {ret = len;if (rest >= len) {memcpy(q->buf + q->write, buf, len);q->write = (q->write + len) % q->size;q->space -= len;} else {memcpy(q->buf + q->write, buf, rest);q->write = 0;memcpy(q->buf, buf + rest, len - rest);q->write = len -rest;q->space -= len;}} else {ret = q->space;if (rest >= q->space) {memcpy(q->buf + q->write, buf, q->space);q->write = (q->write + q->space) % q->size;q->space = 0;} else {memcpy(q->buf + q->write, buf, rest);q->write = 0;memcpy(q->buf, buf + rest, q->space - rest);q->write = q->space -rest;q->space = 0;}}   } return ret;
}/*** ReadQueue - read buffers from queue* @q: the queue to read from* @buf: pointer of read buffer* @len: read length*/
static int ReadQueue(Queue *q, char *buf, unsigned int len)
{unsigned int rest = q->size - q->read;unsigned int ret = 0;if (!Queue_Empty(q)) {if (Avail(q) >= len) {ret = len;if (rest >= len) {memcpy(buf, q->buf + q->read, len);q->read = (q->read + len) % q->size;q->space += len;} else {memcpy(buf, q->buf + q->read, rest);q->read = 0;memcpy(buf + rest, q->buf, len - rest);q->read = len -rest;q->space += len;}return len;} else {ret = Avail(q);if (rest >= Avail(q)) {memcpy(buf, q->buf + q->read, Avail(q));q->read = (q->read + Avail(q)) % q->size;q->space = q->size;} else {memcpy(buf, q->buf + q->read, rest);q->read = 0;memcpy(buf + rest, q->buf, Avail(q) - rest);q->read = Avail(q) -rest;q->space = q->size;}}} return ret;
}void main()
{int ret = 0;char buf[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};char buf2[10];Queue q;Queue_Init(&q, 10);ret = WriteQueue(&q, buf, 5);printf("writed %d bytes.\n", ret);ret = ReadQueue(&q, buf2, 2);printf("readed %d bytes.\n", ret);ret = WriteQueue(&q, buf, 10);printf("writed %d bytes.\n", ret);ret = ReadQueue(&q, buf2, 7);printf("readed %d bytes.\n", ret);ret = ReadQueue(&q, buf2, 7);printf("readed %d bytes.\n", ret);Queue_Destroy(&q);
}

运行结果如下:

这里写图片描述
关于循环队列主题的系列文章,可移步至以下链接:
1. 《循环队列及C语言实现<一>》
2. 《循环队列及C语言实现<二>》
3. 《循环队列及C语言实现<三>》

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

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

相关文章

MAC下secureCRT无法保存密码的解决方法

From: http://www.php230.com/securecrt-for-mac-store-password.html 在mac下新安装了secureCRT&#xff0c;取代系统自带的终端工具&#xff0c;主要是为了方便链接服务器。 mac下面的secureCRT默认保存不上密码&#xff0c;我们选择了保存密码后&#xff0c;下次登录还是提…

Intellij idea 快键键

1.快速进入实现类&#xff1a; Command AltB2.全局查找&#xff1a; Shift Shift3.类继承关系&#xff1a; Ctrl H4.在继承层次上跳转则用 Command B / CommandAltB分别对应父类或父方法定义和子类或子方法实现5.查看当前类的所有方法 Command F126.查看类或方法在哪里使用…

微信小程序下拉刷新列表onPullDownRefresh;微信小程序上划加载列表onReachBottom;uni-app微信小程序下拉加载数据;uni-app微信小程序上划页面加载数据

需求&#xff1a;微信小程序列表加载有两种方式&#xff0c;分别是按住页面下拉加载数据数据&#xff08;触发onPullDownRefresh&#xff09;和直接上划滚动页面到底部加载数据&#xff08;触发onReachBottom函数&#xff09;。 本文主要是使用上划滚动页面触底加载数据&#x…

table下面appendChild别忘了tbody

table下面appendChild别忘了tbody

ARP协议在同网段及跨网段下的工作原理

一、ARP在同个网段下的工作原理 首先&#xff0c;每台主机都会在自己的ARP缓冲区中建立一个 ARP列表&#xff0c;以表示IP地址和MAC地址的对应关系。当源主机需要将一个数据包要发送到目的主机时&#xff0c;会首先检查自己 ARP列表中是否存在该 IP地址对应的MAC地址&#xff0…

decode 类似 case when

将查询的结果翻译成其他值,类似 case when to_char(创建时间,mm) 01 then 查询统计的是1月 when to_char(创建时间,mm) 02 then 查询统计的是2月 when to_char(创建时间,mm) 03 then 查询统计的是3月 ....................... select decode( to_char(创建时间,mm) , 01…

如何查看服务器当前的负载信息

From: http://blog.csdn.net/mal327/article/details/7423750 如何查看服务器当前的负载信息http://www.flybaaa.com/help/69_1.html网吧内突然很卡&#xff0c;这个情况我相信大家都有遇见过&#xff0c;但是通过什么方法来排查是否linux服务器的负载过大导致的这个问题呢&am…

前端vue实现图片压缩并且将其转换为jpg格式图片;前端转换图片格式;前端使用js转换图片格式;前端使用canvas将png格式图片转成jpg格式

需求中可能有时需要将png图片转成jpg图片或者格式互转&#xff0c;前端使用js和canvas转换图片的格式&#xff1b; 原理&#xff1a; 是使用FileReader来把文件读入内存&#xff0c;并且读取文件中的数据。 readAsDataURL方法可以在浏览器主线程中异步访问文件系统&#xff0c;…

mysql中创建表时提示 no database selected

用习惯了oracle或者sqlserver的界面形式 当用到mysql时创建表时往往就会忘记添加表空间这个前提。在一个用户下面可建多个表空间使用语句 create database your_database_name;下面讲一下在建表时有两种方法&#xff1a;1、在命令窗口中用命令 use database_name;该命令将会转…

系统中已安装了vmware,请先卸载干净并重启电脑

打开VMware目录&#xff0c;有个卸载的.cmd 以管理员身份运行&#xff0c;成功之后注销一下电脑。进入系统把VM目录删除&#xff0c;重新解压缩或者安装&#xff0c;再以管理员身份运行安装的.cmd&#xff0c;就可以了。

前端读取文件图片信息流;js读取图片不同信息流;js读取图片;前端就js读取二进制数据;前端js读取文件流使用FileReader对象的readAsDataURL方法来读取图像文件;

原文链接 FileReader来把文件读入内存&#xff0c;并且读取文件中的数据。 readAsDataURL方法可以在浏览器主线程中异步访问文件系统&#xff0c;读取文件中的数据&#xff0c;且读取后 result 为 DataURL, DataURL 可直接 赋值给 img.src。 FileReader 的 result 可以有 3 种形…

【转】LAMP网站架构方案分析【精辟】

【转】LAMP网站架构方案分析【精辟】 http://www.cnblogs.com/mo-beifeng/archive/2011/09/13/2175197.htmlXubuntu下LAMP环境安装(最佳的PHP环境搭建) http://www.cnblogs.com/mo-beifeng/archive/2011/08/13/2137605.html 转载于:https://www.cnblogs.com/bravehunter/p/5709…

有源晶振和无源晶振的区别

1、晶振在电路中就相当于人的一个心脏&#xff0c;晶振为电路提供了一个时钟信号。有源晶振比较贵&#xff0c;但是有源晶振自身就能震动。而无论是无源晶振&#xff0c;还是有源晶振&#xff0c;都有自身的优点和缺点所在&#xff0c;若考虑产品成本&#xff0c;建议可以选择无…

免费设计图标的网站;免费设计的网站;免费设计的网站;

链接1&#xff1a;canva设计logo和图标 链接2&#xff1a;包图网 可以自行设计、编辑、下载logo图标海报等

介绍Linux中cp直接覆盖不提示的方法

From: http://www.php100.com/html/webkaifa/Linux/2011/0220/7570.html 新做了服务器&#xff0c;cp覆盖时&#xff0c;无论加什么参数-f之类的还是提示是否覆盖&#xff0c;这在大量cp覆盖操作的时候是不能忍受的。把a目录下的文件复制到b目录以下是代码片段&#xff1a;cp …

路由的Modem信号控制

中低端路由器上使用disp interface 查看相应串口状态信息&#xff0c;其中DCD、DTR、DSR、RTS及CTS等五个状态指示分别代表什么意思&#xff1f; DCD&#xff08;Data Carrier Detect 数据载波检测&#xff09; DTR&#xff08;Data Terminal Ready 数据终端准备好&#xff09;…

项目回顾1-图片上传-form表单还是base64-前端图片压缩

第一个项目终于上线了&#xff0c;是一个叫亲青筹的公益众筹平台&#xff0c;微信端&#xff0c;电脑端还有后台界面大部分都是我完成的&#xff0c;几个月过来&#xff0c;感觉收获了很多&#xff0c;觉得要总结一下。 首先想到的是图片上传的问题。在通常表单数据都是ajax上传…

4.6 【共享源】流的生产者(一)

一,什么是生产者? 生产者创建内容并与有权限的消费者共享。 作为生产者,必须相应地设置流以供消费。通常,我们需要在生产者应用程序中执行接下来的流程来共享产生的内容。 二,创建生产者的流 调用 screen_create_stream() 为生产者创建流以进行渲染。例如 ... screen…

vue路由传参两种方式;vue路由传参query与params区别;vue路由跳转的带参与不带参,路由跳转传参方式:name 、 path;

vue项目的路由传参常用的有两种方式&#xff1a;query和params 1.query传参特点&#xff1a;1.1可以用path也可以用name传递路径 注意name是路由页面vue文件的名称 不需要/1.2跳转页面地址栏可以看到路径和参数 通过 this.$route.query.id 可以获取到参数1.3刷新不会丢失参数t…

Qt下Undefined reference to 'vtable for xxx'

QT下遇到这种错误提示时候需要注意以下情况&#xff1a; 一、cpp文件里使用了Q_OBJECT 分析&#xff1a;qmake不会处理.cpp文件里的Q_OBJECT&#xff0c;所以如果在.cpp文件中有它的话将会产生undefined reference to vtable for "xxx::xxx"。 方法1&#xff1a;…