0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
会员中心
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言环形队列的原理和特点

strongerHuang 来源:嵌入式Linux 作者:写代码的篮球球痴 2021-05-11 13:56 次阅读
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

什么是环形队列?

环形缓冲区是一个非常典型的数据结构,这种数据结构符合生产者,消费者模型,可以理解它是一个水坑,生产者不断的往里面灌水,消费者就不断的从里面取出水。

那就可能会有人问,既然需要灌水,又需要取出水,为什么还需要开辟一个缓冲区内存空间呢?直接把生产者水管的尾部接到消费者水管的头部不就好了,这样可以省空间啊。

答案是不行的,生产者生产水的速度是不知道的,消费者消费水的速度也是不知道的,如果你强制接在一起,因为生产和消费的速度不同,就非常可能存在水管爆炸的情况,你说这样危险不危险?

音频系统框架下,alsa就是使用环形队列的,在生产者和消费者速度不匹配的时候,就会出现xrun的问题。

环形队列的特点

1、数组构造环形缓冲区

假设我们用数组来构造一个环形缓存区,如下图

59134ccc-b20d-11eb-bf61-12bb97331649.png

我们需要几个东西来形容这个环形缓冲区,一个的读位置,一个是写位置,一个是环形缓冲区的长度

5928e3fc-b20d-11eb-bf61-12bb97331649.png

从图片看,我们知道,这个环形缓冲区的读写位置是指向数组的首地址的,环形缓冲区的长度是 5 。

那如何判断环形缓冲区为空呢?

如果 R == W 就是读写位置相同,则这个环形缓冲区为空

那如何判断环形缓冲区满了呢?

如果 (W - R )= Len ,则这个环形缓冲区已经满了。

2、向环形缓冲区写入 3个数据

写入 3 个数据后,W 的值等于 3 了,R 还是等于 0。

3个企鹅已经排列

3、从环形缓冲区读取2个数据

读出两个数据后,R = 2 了,这个时候,W还是等于 3,毕竟没有再写过数据了。

4、再写入3个数据

如果 W 》 LEN 后,怎么找到最开始的位置的呢?这个就需要进行运算了,W%LEN 的位置就是放入数据的位置 ,6%5 = 1。

5、再写入1个数据

这个时候环形队列已经满了,要是想再写入数据的话,就不行了,(W - R) = 5 == LEN

代码实现

/* 实现的最简单的ringbuff 有更多提升空间,可以留言说明 */

#include “stdio.h”

#include “stdlib.h”

#define LEN 10

/*环形队列结构体*/

typedef struct ring_buff{

int array[LEN];

int W;

int R;

}*ring;

/*环形队列初始化*/

struct ring_buff * fifo_init(void)

{

struct ring_buff * p = NULL;

p = (struct ring_buff *)malloc(sizeof(struct ring_buff));

if(p == NULL)

{

printf(“fifo_init malloc error

”);

return NULL;

}

p-》W = 0;

p-》R = 0;

return p;

}

/*判断环形队列是否已经满了*/

int get_ring_buff_fullstate(struct ring_buff * p_ring_buff)

{

/*如果写位置减去读位置等于队列长度,就说明这个环形队列已经满*/

if((p_ring_buff-》W - p_ring_buff-》R) == LEN)

{

return (1);

}

else

{

return (0);

}

}

/*判断环形队列为空*/

int get_ring_buff_emptystate(struct ring_buff * p_ring_buff)

{

/*如果写位置和读的位置相等,就说明这个环形队列为空*/

if(p_ring_buff-》W == p_ring_buff-》R)

{

return (1);

}

else

{

return (0);

}

}

/*插入数据*/

int ring_buff_insert(struct ring_buff * p_ring_buff,int data)

{

if(p_ring_buff == NULL)

{

printf(“p null

”);

return (-1);

}

if(get_ring_buff_fullstate(p_ring_buff) == 1)

{

printf(“buff is full

”);

return (-2);

}

p_ring_buff-》array[p_ring_buff-》W%LEN] = data;

p_ring_buff-》W ++;

//printf(“inset:%d %d

”,data,p_ring_buff-》W);

return (0);

}

/*读取环形队列数据*/

int ring_buff_get(struct ring_buff * p_ring_buff)

{

int data = 0;

if(p_ring_buff == NULL)

{

printf(“p null

”);

return (-1);

}

if(get_ring_buff_emptystate(p_ring_buff) == 1)

{

printf(“buff is empty

”);

return (-2);

}

data = p_ring_buff-》array[p_ring_buff-》R%LEN];

p_ring_buff-》R++;

return data;

}

/*销毁*/

int ring_buff_destory(struct ring_buff * p_ring_buff)

{

if(p_ring_buff == NULL)

{

printf(“p null

”);

return (-1);

}

free(p_ring_buff);

return (0);

}

int main()

{

int i = 0;

/*定义一个环形缓冲区*/

ring pt_ring_buff = fifo_init();

/*向环形缓冲区中写入数据*/

for(i = 0;i《10;i++)

{

ring_buff_insert(pt_ring_buff,i);

}

/*从环形缓冲区中读出数据*/

for(i = 0;i《10;i++)

{

printf(“%d ”,ring_buff_get(pt_ring_buff));

}

/*销毁一个环形缓冲区*/

ring_buff_destory(pt_ring_buff);

return (1);

}

599cb322-b20d-11eb-bf61-12bb97331649.png

换一个写法,这个写法是各种大神级别的

/* 实现的最简单的ringbuff 有更多提升空间,可以留言说明 */

#include “stdio.h”

#include “stdlib.h”

#define LEN 64

/*环形队列结构体*/

typedef struct ring_buff{

int array[LEN];

int W;

int R;

}*ring;

/*环形队列初始化*/

struct ring_buff * fifo_init(void)

{

struct ring_buff * p = NULL;

p = (struct ring_buff *)malloc(sizeof(struct ring_buff));

if(p == NULL)

{

printf(“fifo_init malloc error

”);

return NULL;

}

p-》W = 0;

p-》R = 0;

return p;

}

/*判断环形队列是否已经满了*/

int get_ring_buff_fullstate(struct ring_buff * p_ring_buff)

{

/*如果写位置减去读位置等于队列长度,就说明这个环形队列已经满*/

if((p_ring_buff-》W - p_ring_buff-》R) == LEN)

{

return (1);

}

else

{

return (0);

}

}

/*判断环形队列为空*/

int get_ring_buff_emptystate(struct ring_buff * p_ring_buff)

{

/*如果写位置和读的位置相等,就说明这个环形队列为空*/

if(p_ring_buff-》W == p_ring_buff-》R)

{

return (1);

}

else

{

return (0);

}

}

/*插入数据*/

int ring_buff_insert(struct ring_buff * p_ring_buff,int data)

{

if(p_ring_buff == NULL)

{

printf(“p null

”);

return (-1);

}

if(get_ring_buff_fullstate(p_ring_buff) == 1)

{

printf(“buff is full

”);

return (-2);

}

//p_ring_buff-》array[p_ring_buff-》W%LEN] = data;

p_ring_buff-》array[p_ring_buff-》W&(LEN -1)] = data;

p_ring_buff-》W ++;

//printf(“inset:%d %d

”,data,p_ring_buff-》W);

return (0);

}

/*读取环形队列数据*/

int ring_buff_get(struct ring_buff * p_ring_buff)

{

int data = 0;

if(p_ring_buff == NULL)

{

printf(“p null

”);

return (-1);

}

if(get_ring_buff_emptystate(p_ring_buff) == 1)

{

printf(“buff is empty

”);

return (-2);

}

//data = p_ring_buff-》array[p_ring_buff-》R%LEN];

data = p_ring_buff-》array[p_ring_buff-》R&(LEN -1)];

p_ring_buff-》R++;

return data;

}

/*销毁*/

int ring_buff_destory(struct ring_buff * p_ring_buff)

{

if(p_ring_buff == NULL)

{

printf(“p null

”);

return (-1);

}

free(p_ring_buff);

return (0);

}

int main()

{

int i = 0;

/*定义一个环形缓冲区*/

ring pt_ring_buff = fifo_init();

/*向环形缓冲区中写入数据*/

for(i = 0;i《10;i++)

{

ring_buff_insert(pt_ring_buff,i);

}

/*从环形缓冲区中读出数据*/

for(i = 0;i《10;i++)

{

printf(“%d ”,ring_buff_get(pt_ring_buff));

}

/*销毁一个环形缓冲区*/

ring_buff_destory(pt_ring_buff);

return (1);

}

总结

环形队列的使用场景非常多,安卓的音频数据读写,很多都用到环形队列,我们在开发过程中使用的环形队列肯定比我上面的那个例子要复杂的多,我这里演示的是比较简单的功能,但是麻雀虽小,五脏俱全,希望这个麻雀让你们了解这个数据结构。在实际项目中大展身手。

原文标题:C语言实现环形队列的原理和方法

文章出处:【微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

责任编辑:haq

声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • 数据
    +关注

    关注

    8

    文章

    7314

    浏览量

    93968
  • C语言
    +关注

    关注

    183

    文章

    7642

    浏览量

    144599

原文标题:C语言实现环形队列的原理和方法

文章出处:【微信号:strongerHuang,微信公众号:strongerHuang】欢迎添加关注!文章转载请注明出处。

收藏 人收藏
加入交流群
微信小助手二维码

扫码添加小助手

加入工程师交流群

    评论

    相关推荐
    热点推荐

    为什么单片机还在用C语言编程?

    ,只是C语言是最适合单片机编程的高级语言。 一、单片机编程的特点 1.对单片机编程来说,我们首先要考虑的是单片机的程序空间和数据空间都是有限的,所以我们在编写程序时要尽量做到让程
    发表于 11-28 07:37

    C语言特性

    1、高效性:直接操作硬件 C 语言代码的执行效率极高,这是其最为显著的优势之一。它能够直接访问硬件资源,与底层硬件进行紧密交互,充分发挥硬件的性能潜力。在嵌入式开发中,硬件资源往往十分有限,对程序
    发表于 11-24 07:01

    C语言和单片机C语言有什么差异

    单片机c语言相对于普通C语言增加了一些基本的指令,还有变量的赋值是16进制,当然单片机c语言只牵
    发表于 11-14 07:55

    基于环形队列的UART收发回显实验

    问题。在本实验中,我们使用环形队列来实现实验1的串口收发回显,将串口接收到的数据暂存在队列中,待完成一次接收后再将队列中的数据全部发出去。
    的头像 发表于 10-27 13:51 1687次阅读
    基于<b class='flag-5'>环形</b><b class='flag-5'>队列</b>的UART收发回显实验

    MiniVC6(C语言快速部署)资料

    MiniVC6(C语言快速部署)软件,无需安装。
    发表于 09-04 16:59 0次下载

    RabbitMQ消息队列解决方案

    在现代分布式系统架构中,消息队列作为核心组件,承担着系统解耦、异步处理、流量削峰等重要职责。RabbitMQ作为一款成熟的消息队列中间件,以其高可用性、高可靠性和丰富的特性,成为众多企业的首选方案。本文将从运维工程师的角度,详细阐述RabbitMQ从单机部署到集群搭建的完
    的头像 发表于 07-08 15:55 427次阅读

    主流的 MCU 开发语言为什么是 C 而不是 C++?

    在单片机的地界儿里,C语言稳坐中军帐,C++想分杯羹?难喽。咱电子工程师天天跟那针尖大的内存空间较劲,C++那些花里胡哨的玩意儿,在这儿真玩不转。先说内存这道坎儿。您当stm32f4的
    的头像 发表于 05-21 10:33 777次阅读
    主流的 MCU 开发<b class='flag-5'>语言</b>为什么是 <b class='flag-5'>C</b> 而不是 <b class='flag-5'>C</b>++?

    NVME控制器之队列管理模块

    队列管理模块是整个NVMe Host控制器的核心模块,该模块实现了提交队列与完成队列的管理,多队列请求的仲裁判决等功能。队列管理模块中含有数
    的头像 发表于 05-03 15:32 420次阅读
    NVME控制器之<b class='flag-5'>队列</b>管理模块

    单片机c语言编程实例大全

    单片机c语言编程实例大全_18
    发表于 04-30 16:11 6次下载

    深入理解C语言C语言循环控制

    C语言编程中,循环结构是至关重要的,它可以让程序重复执行特定的代码块,从而提高编程效率。然而,为了避免程序进入无限循环,C语言提供了多种循环控制语句,如break、continue和
    的头像 发表于 04-29 18:49 1733次阅读
    深入理解<b class='flag-5'>C</b><b class='flag-5'>语言</b>:<b class='flag-5'>C</b><b class='flag-5'>语言</b>循环控制

    浅谈环形铁心兼谈环形变压器

    近年来,在电子市场上,环形变压器已广泛用于家庭影院和多种电子设备中,而绕制环形变压器所用的铁心即环形铁心,可分A、B两种系列,现介绍如下: 1. A系列环形铁心 A系列
    发表于 04-16 15:04

    C语言的历史及程序介绍

    电子发烧友网站提供《C语言的历史及程序介绍.pdf》资料免费下载
    发表于 04-09 16:10 0次下载

    OptiSystem应用:环形通量仿真

    环形通量,顾名思义就是描述了光纤内部圆形半径内的通量。环绕通量通常被量化为从光纤中心开始的半径,该半径需要环绕穿过光纤的25%到75%的光能。由环绕通量值描述的光纤的功率分布是确保千兆以太网系统中所
    发表于 04-09 08:47

    51单片机C语言学习笔记

    c51语言快速入门
    发表于 03-24 14:04 3次下载

    Triton编译器支持的编程语言

    编写和优化深度学习代码。Python是一种广泛使用的高级编程语言,具有简洁易读、易于上手、库丰富等特点,非常适合用于深度学习应用的开发。 二、领域特定语言(DSL) Triton也提供了一种针对深度学习领域的特定编程
    的头像 发表于 12-24 17:33 1452次阅读