C语言构建环形缓冲区
它逻辑上是一个首尾相连的FIFO结构,具体实现上采用简单的线性数组。通过额外的辅助标志(head、tail)能很快知道队列的使用情况(是满还是为空)。正因为其简单高效的原因,甚至在硬件都实现了环形队列。
环形队列广泛用于网络数据收发、程序间的大量数据交换(比如内核与应用程)、硬件接收大量数据。
1、环形缓冲区原理
- 环列队列逻辑上将数组元素array[0]与array[LEN-1]连接起来,形成一个存放队列的环形空间。实际操作中为了方便读写,采用head和tail分别指向可以读的位置和可以写的位置。
- 环形队列的关键是判断队列为空,还是为满。一般有两种方法:
- 一是附加一个标志位tag
- 当head赶上tail,队列空,则令tag=0
- 当tail赶上head,队列满,则令tag=1
- 二是在队尾结点与队首结点之间留有1个元素的空间
- 队列空: head==tail
- 队列满: (tail+1)% MAXN ==head
2、预留1个空位的环形队列
- 开始时head和tail指向同一个地址,但随着数据的push和poll,head和tail之间永远预留一个单元空间。如下图所示即为一个满队列。但箭头所指的位置不准确。tail应该指向空位,head指向9。即从头出去,从尾巴进来。
- 数据结构:
struct ring_queue{ unsigned int head; unsigned int tail; unsigned int size; //环形缓冲区容量int *array; //实际缓冲区(数组)的首地址
};
- 规则:
- head指向可读位置(地址存有数据),tail指向可写位置(地址无数据)。
- 初始化状态: head = tail = 0;
- 判定队列为空:head == tail
- 队列为满:**( (tail+1) % SIZE ) == head **
- 入队操作:若队列不满,则写入。
- 出队操作:若队列不空,则读出。
- 缓冲区必须是连续的内存空间,可以通过静态数组变量或局部数组变量的方式定义,但绝不能从堆上分配(malloc),因为malloc分配的内存空间是不连续的!!!
- 头文件:
#ifndef __RINGQ_H__
#define __RINGQ_H__#ifdef __cplusplus
extern "C" {#endiftypedef struct { unsigned int head; unsigned int tail;unsigned int size;int *array;
}RINGQ; #define ringq_is_empty(q) (q->head == q->tail)
#define ringq_is_full(q) (((q->tail+1)%q->size) == q->head )int ringq_init(RINGQ * ringqp, int * array_ptr, unsigned size);
int ringq_free(RINGQ * ringqp);
int ringq_push(RINGQ * ringqp,int data);
int ringq_poll(RINGQ * ringqp,int * val);
void ringq_display(RINGQ * ringqp);#ifdef __cplusplus
}
#endif#endif
- c文件:
1 #include <stdio.h>2 #include <stdlib.h>3 #include "ringq.h"4 5 int ringq_init(RINGQ * ringqp, int * array_ptr, unsigned size)6 {7 /*8 不能从堆里分配空间!!!9 因为堆里的空间不是连续的,而是通过链表链接的一个空间串10 if(!(ringqp->array = (int *)malloc(size))){11 printf("Malloc failed!\n");12 return -1;13 }14 */15 ringqp->array = array_ptr;16 ringqp->size = size;17 ringqp->head = 0;18 ringqp->tail = 0;19 return 0;20 }21 22 int ringq_free(RINGQ * ringqp)23 {24 free(ringqp->array);25 return 0;26 }27 28 29 int ringq_push(RINGQ * ringqp,int data)30 {31 if(ringq_is_full(ringqp))32 {33 printf("ringq is full.\n");34 return -2;35 }36 ringqp->array[ringqp->tail] = data;37 ringqp->tail = (ringqp->tail + 1) % ringqp->size ;38 return 0;39 }40 41 42 int ringq_poll(RINGQ * ringqp,int * val)43 {44 if(ringq_is_empty(ringqp))45 {46 printf("ringq is empty.\n");47 return -3;48 }49 *val = ringqp->array[ringqp->head];50 ringqp->head = (ringqp->head + 1) % ringqp->size ;51 return 0;52 }53 54 void ringq_display(RINGQ * ringqp)55 {56 int i =0;57 unsigned head = ringqp->head;58 unsigned tail = ringqp->tail;59 unsigned size = ringqp->size;60 61 if(ringq_is_empty(ringqp))62 {63 printf("ringq is empty.\n");64 return;65 }66 while(head != tail){67 printf("%04d ",ringqp->array[head]);68 i++;69 if(i == 5){70 printf("\n");71 i = 0;72 }73 head = (head + 1)%(size);74 }75 printf("\n");76 return;77 }
- 测试文件:
1 #include <stdio.h>2 #include <stdlib.h>3 #include "ringq.h"4 5 #define RQ_SIZE 50 6 7 int main(void)8 {9 int data_in = 0;10 int data_out = 0;11 int select = 0;12 13 int array[RQ_SIZE]={};14 RINGQ rq, *rqp;15 rqp = &rq;16 17 ringq_init(rqp, array, RQ_SIZE);18 ringq_display(rqp);19 20 int index = RQ_SIZE - 1; //allways a bank between head and tail21 while (index > 0){22 ringq_push(rqp,1);23 index -= 1;24 }25 26 ringq_display(rqp);27 28 while (index < RQ_SIZE-1){29 ringq_poll(rqp,&data_out);30 index += 1;31 }32 33 ringq_display(rqp);34 35 while (index > 0){36 ringq_push(rqp,2);37 index -= 1;38 }39 40 ringq_display(rqp);41 42 return 0;43 }
- 实验结果:
- 测试文件2
1 #include <stdio.h>2 #include <stdlib.h>3 #include "ringq.h"4 5 #define RQ_SIZE 5 6 7 int main(void)8 {9 int data_in = 0;10 int data_out = 0;11 int select = 0;12 13 int array[RQ_SIZE]={};14 RINGQ rq, *rqp;15 rqp = &rq;16 17 ringq_init(rqp, array, RQ_SIZE);18 ringq_display(rqp);19 42 43 loop: puts("push or poll or quit? [i/o/q]");44 select = getchar();45 getchar(); //丢弃回车46 switch(select){47 case 'i':48 printf("The push data is:");49 scanf("%d",&data_in);50 getchar(); //丢弃回车51 ringq_push(rqp, data_in);52 break;53 case 'o':54 ringq_poll(rqp, &data_out);55 printf("%d poll successfull.\n",data_out);56 break;57 case 'q':58 59 return 0;60 default:61 printf("Wrong choice!enter i or o!\n");62 }63 ringq_display(rqp);64 printf("\n");65 goto loop;66 }
- 实验结果:
- 有关getchar()和输入缓冲区的关系,请查看一文搞懂getchar()和putchar()的奇怪现象_Leon的博客-CSDN博客或者C语言 getchar()原理及易错点解析_Kevin.wang-CSDN博客_c语言getchar
3、附加满空标志位的环形队列
- 数据结构
typedef struct ringq{int head;int tail;int tag ;int size ;int space[RINGQ_MAX];}RINGQ;
- 规则
- 初始化状态: q->head = q->tail = q->tag = 0;
- 队列为空:(q->head == q->tail) && (q->tag == 0)
- 队列为满**: ((q->head == q->tail) && (q->tag == 1))**
- 入队操作:如队列不满,则写入q->tail = (q->tail + 1) % q->size ;
- 出队操作:如果队列不空,则从head处读出。下一个可读的位置在 q->head = (q->head + 1) % q->size
- 头文件
#ifndef __RINGQ_H__
#define __RINGQ_H__#ifdef __cplusplus
extern "C" {#endif#define QUEUE_MAX 20
typedef struct ringq{int head;int tail;int tag ;int size ;int space[QUEUE_MAX];
}RINGQ;extern int ringq_init(RINGQ * p_queue);
extern int ringq_free(RINGQ * p_queue);
extern int ringq_push(RINGQ * p_queue,int data);
extern int ringq_poll(RINGQ * p_queue,int *p_data);
#define ringq_is_empty(q) ( (q->head == q->tail) && (q->tag == 0))
#define ringq_is_full(q) ( (q->head == q->tail) && (q->tag == 1))
#define print_ringq(q) printf("ring head %d,tail %d,tag %d\n", q->head,q->tail,q->tag);
#ifdef __cplusplus
}
#endif#endif
- 实现代码
#include <stdio.h>
#include "ringq.h"int ringq_init(RINGQ * p_queue)
{p_queue->size = QUEUE_MAX ;p_queue->head = 0;p_queue->tail = 0;p_queue->tag = 0;return 0;
}int ringq_free(RINGQ * p_queue)
{return 0;
}
//Write data to the queue
int ringq_push(RINGQ * p_queue,int data)
{print_ringq(p_queue);if(ringq_is_full(p_queue)){printf("ringq is full\n");return -1;}p_queue->space[p_queue->tail] = data;p_queue->tail = (p_queue->tail + 1) % p_queue->size ;if(p_queue->tail == p_queue->head){p_queue->tag = 1;}return p_queue->tag ;
}
//Get data from the queue
int ringq_poll(RINGQ * p_queue,int * p_data)
{print_ringq(p_queue);if(ringq_is_empty(p_queue)){printf("ringq is empty\n");return -1;}*p_data = p_queue->space[p_queue->head];p_queue->head = (p_queue->head + 1) % p_queue->size ;if(p_queue->tail == p_queue->head){p_queue->tag = 0;}return p_queue->tag ;
}
- 测试代码
//请参考上节的test.c
参考资料:【转】环形队列理论(C语言) - 程序天空下的骆驼 - 博客园 (cnblogs.com)
C语言构建环形缓冲区相关推荐
- C语言实现环形缓冲区
文章目录 前言 一.什么是环形缓冲区? 二.为什么要使用环形缓冲区及环形缓冲区实用场景 三.环形缓冲区原理及代码的编写 原理 代码编写 总结 前言 本篇文章将为大家介绍一下什么是环形缓冲区,在很多场合 ...
- 环形缓冲区实现(C语言)
提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 要求 一.环形缓冲区 二.环形缓冲区实现(C语言) 1. ringBuf.h 2. ringBufInit.c 3. rin ...
- c语言数组怎么环形阵列,C语言 用于大阵列的无复制线程安全环形缓冲区
对于大数组(10 ^ 7个元素)上的信号处理,我使用与环形缓冲区连接的不同线程.遗憾的是,只需要太多时间将数据复制到缓冲区和从缓冲区复制数据.当前实现基于boost :: lockfree :: sp ...
- 音视频环形缓冲区C语言实现
目录 一.什么是环形缓冲区 二.为什么使用环形缓冲区 三.代码实现 一.什么是环形缓冲区 环形缓冲区(也称为循环缓冲区)是固定大小的缓冲区,工作原理就像内存是连续的且可循环的一样.在生成和使用内存时, ...
- 环形缓冲区C语言实现
环形缓冲区 环形缓冲区的特性 1.先进新出 2.当缓冲区被使用完,且又有新的数据需要存储时,丢掉历史最久的数据,保存最新数据 现实中的存储介质都是线性的,因此我们需要做一下处理,才能在功能上实现环形缓 ...
- c语言数组实现环形缓冲区,[嵌入式开发模块]环形缓冲区/循环队列 C语言实现
忙着毕设,很久没有写文章了,终于答辩完了,得了个校优秀毕业设计.毕设做的是个智能接口模块,用一周时间入门了,MC9S12XEP100的开发,又用一周时间入门了uC/OS-II嵌入式操作系统,在做毕设的 ...
- 架构设计:生产者/消费者模式 第6页:环形缓冲区的实现
2019独角兽企业重金招聘Python工程师标准>>> ◇判断"空"和"满" 上述的操作并不复杂,不过有一个小小的麻烦:空环和满环的时候,R和 ...
- 优雅地用宏实现环形缓冲区
之前写的环行缓冲区文章 柔性数组和环形队列之间的故事 C语言,环形队列 循环缓冲区是嵌入式软件工程师在日常开发过程中的关键组件. 多年来,互联网上出现了许多不同的循环缓冲区实现和示例.我非常喜欢这个模 ...
- Ring Buffer (circular Buffer)环形缓冲区简介
https://blog.csdn.net/langeldep/article/details/8888582 关于环形缓冲区的知识,请看这里 http://en.wikipedia.org/wiki ...
最新文章
- 【Android游戏开发二十五】在Android上的使用《贝赛尔曲线》!
- 移动端H5图片上传的那些坑
- 初探AngularJs框架(三)
- 浅谈JavaScript作用域,关于Java的学习路线资料
- oj2894(贝尔曼福特模板)
- Hark的数据结构与算法练习之地精(侏儒)排序
- 安装Spark集群(在CentOS上)
- 超详细的SFtp工具类及使用
- 演讲者模式投影到幕布也看到备注_PPT的备注功能怎么使用?如何让备注仅被演示者看到?...
- 数学笔记——导数5(指数函数和对数函数的导数)
- python_csv文件写入
- 2015总结与新年计划
- 基于wavesurfer,regions 封装的可视化音标标注控件
- Python爬虫-抓取PC端网易云音乐评论(GUI界面)
- 如何彻底关闭win11自动更新
- 像素和分辨率的关系 完全剖析
- Python 1-10 字符串操作
- Cortex-M3处理器出众的控制和连通性
- Unity2D游戏开发之保卫萝卜
- http://bbs.sjz7.com/forum.php,国内 3S 论坛集合(最新)