环形缓冲区实现(C语言)_^^不加糖^^的博客-程序员宅基地_c语言环形缓冲实现

技术标签: C语言  c语言  数据结构  

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


要求

完成环形缓冲区函数库封装,生成成静态库和动态库,编写测试程序验证库文件,编写makefile实现编译,要求实现函数:
a、缓冲区初始化
b、往缓冲区写数据;
c、从缓冲区读数据;
d、计算缓冲区数据长度;
e、销毁缓冲区;

需要考虑到多个用户同时读写的情况,用到锁机制(互斥量)。

一、环形缓冲区

关于什么是环形缓冲区,这里就不介绍了,网上大量文章都会介绍,读几篇基本就了解了。
参考:
C语言实现环形缓冲区
环形缓冲区ring_buffer的c语言实现
【数据结构及算法】环形缓冲区(ring buffer)实现原理及代码实现(C语言)

不罗嗦,直接上代码。

二、环形缓冲区实现(C语言)

1. ringBuf.h

#ifndef _RINGBUF_H
#define _RINGBUF_H

#define read    0
#define write   1
#define quit    2
#define length  3

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct ringBuf
{
    
	char *buffer;	/*缓冲区的数据*/
	int  size;		/*缓冲区大小*/
	int  pRead;		/*读指针,名义上的指针,只是为了记录位置而已*/
	int  pWrite;	/*写指针,名义上的指针,只是为了记录位置而已*/
};
/*先不考虑互斥锁*/
/*先不考虑写覆盖和读重复问题,后续设计有效数据记录变量来解决*/

struct ringBuf *ringBufInit(struct ringBuf *ringBuffer,int size);
int ringBufRead(struct ringBuf *ringBuffer,char *readBuf,int readLength);
int ringBufWrite(struct ringBuf *ringBuffer,char *writeBuf,int writeLength);
int ringBufDataLen(struct ringBuf *ringBuffer);
void ringBufFree(struct ringBuf *ringBuffer);
int cmdHand(char *cmd);

#endif

2. ringBufInit.c

#include "ringBuf.h"
#include <stdlib.h>

/*环形缓冲区初始化函数*/
/*不使用全局变量,将环形缓冲区结构体返回*/
struct ringBuf *ringBufInit(struct ringBuf* ringBuffer,int size)
{
    
	ringBuffer = (struct ringBuf*)malloc(sizeof(struct ringBuf));
	if(NULL == ringBuffer)
	{
    
		printf("ringBuffer malloc error!\n");
		exit(-1);
	}
	memset(ringBuffer,0,sizeof(struct ringBuf));
	
	ringBuffer->buffer = (char*)malloc(size);
	memset(ringBuffer->buffer,0,size);

	ringBuffer->size   = size;
	ringBuffer->pRead  = 0;
	ringBuffer->pWrite = 0;

	return ringBuffer;
}

3. ringBufRead.c

#include "ringBuf.h"

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

int ringBufRead(struct ringBuf *ringBuffer,char *readBuf,int readLength)
{
    
	int pre  = 0;	//记录read指针到缓冲区尾端数据长度
	int last = 0;	//记录剩余数据长度,也就是缓冲区头部的部分数据

	if(NULL == ringBuffer)
	{
    
		printf("ringBuffer is NULL,ringBuffer init error!\n");
		exit(-1);
	}
	if(NULL == readBuf)
	{
    
		printf("readBuf is NULL,readBuf init error!\n");
		exit(-1);
	}

	/*readLength超出缓冲区大小*/
	/*可设置只读有效数据或直接报错*/
	/*后续设计有效数据记录变量,防止读重复,同时也解决了readLength超缓冲区的问题*/
	if(readLength > ringBuffer->size)
	{
    
		printf("readLength is too long!\n");
		exit(-1);
	}

	if(readLength+ringBuffer->pRead <= ringBuffer->size)
	{
    
		/*readLength + pRead < size,要读的数据没有到达尾部*/
		memcpy(readBuf,ringBuffer->buffer+ringBuffer->pRead,readLength);
	}else
	{
    
		/*readLength + pRead > size,一部分数据在尾端,一部分在头端*/
		int pre  = ringBuffer->size - ringBuffer->pRead;
		int last = readLength - pre;
		memcpy(readBuf,ringBuffer->buffer+ringBuffer->pRead,pre);
		memcpy(readBuf+pre,ringBuffer->buffer,last); 
	}

	/*移动pRead指针*/
	ringBuffer->pRead = (ringBuffer->pRead + readLength) % (ringBuffer->size);
	
	return readLength;	//后续要返回读有效数据长度
}

4. ringBufWrite.c

#include "ringBuf.h"

/*往环形缓冲区写数据*/
int ringBufWrite(struct ringBuf *ringBuffer,char *writeBuf,int writeLength)
{
    
    int pre  = 0;   //记录write指针到缓冲区尾端长度
    int last = 0;   //记录剩余所需空间,也就是要往缓冲区头部写的部分空间

    if(NULL == ringBuffer)
    {
    
        printf("ringBuffer is NULL,ringBuffer init error!\n");
        exit(-1);
    }
    if(NULL == writeBuf)
    {
    
        printf("writeBuf is NULL,writeBuf init error!\n");
        exit(-1);
    }

    /*writeLength超出缓冲区大小*/
    /*可设置只写有效空间或直接报错*/
	/*后续设计有效数据记录变量,防止写覆盖,同时也解决了writeLength超缓冲区的问题*/
    if(writeLength > ringBuffer->size)
    {
    
        printf("writeLength is too long!\n");
        exit(-1);
    }

    if(writeLength+ringBuffer->pWrite <= ringBuffer->size)
    {
    
        /*writeLength + pWrite < size	写空间足够,不用回到头部*/
        memcpy(ringBuffer->buffer+ringBuffer->pWrite,writeBuf,writeLength);
    }else
    {
    
        /*writeLength + pRead > size	一部分数据写在尾部,一部分数据写在头部*/
        int pre  = ringBuffer->size - ringBuffer->pWrite;
        int last = writeLength - pre;
        memcpy(ringBuffer->buffer+ringBuffer->pWrite,writeBuf,pre);
        memcpy(ringBuffer->buffer,writeBuf+pre,last);
    }

    /*移动pWrite指针*/
    ringBuffer->pWrite = (ringBuffer->pWrite + writeLength) % (ringBuffer->size);

    return writeLength;	//后续要返回写有效数据长度
}

5. ringBufDataLen.c

#include "ringBuf.h"

/*计算环形缓冲区数据长度*/
/*write指针可能在read指针前,也可能在read指针后*/

int ringBufDataLen(struct ringBuf *ringBuffer)
{
    
	int dataLen = 0;

	if(NULL == ringBuffer)
	{
    
		printf("ringBuffer is NULL!\n");
		exit(-1);
	}

	if(ringBuffer->pWrite >= ringBuffer->pRead)
	{
    
		return (ringBuffer->pWrite - ringBuffer->pRead);
	}else
	{
    
		return (ringBuffer->size - ringBuffer->pRead + ringBuffer->pWrite);
	}
}

6. ringBufFree.c

#include "ringBuf.h"

/*释放环形缓冲区*/
void ringBufFree(struct ringBuf *ringBuffer)
{
    
	if(NULL == ringBuffer)
	{
    
		printf("ringBuffer is NULL!\n");
		exit(-1);
	}
	if(ringBuffer->buffer != NULL)
	{
    
		free(ringBuffer->buffer);
		ringBuffer->buffer =NULL;
	}
	free(ringBuffer);
	ringBuffer = NULL;
}

7. cmdHand.c

#include "ringBuf.h"

int cmdHand(char *cmd)
{
    
	if(NULL == cmd)
	{
    
		printf("cmd is NULL!\n");
		exit(-1);
	}
	if(strcmp("read",cmd) == 0)
	{
    
		return 0;
	}
	if(strcmp("write",cmd) == 0)
	{
    
		return 1;
	}
	if(strcmp("quit",cmd) == 0)
	{
    
		return 2;
	}
	if(strcmp("length",cmd) == 0)
	{
    
		return 3;
	}
	return 4;
}

8. main.c

#include "ringBuf.h"

int main()
{
    

	/*暂时不考虑多用户同时操作的情况*/
	/*暂时不考虑写覆盖和读重复问题,后续设计一个变量
	 * 用来监视有效数据长度*/

	int bufLen = 16;	//缓冲区大小
	char *cmd = NULL;
	int cmdNum = 0;
	int strNum = 0;		//要读取的字符数
	int dataLen = 0;	//缓冲区有效数据长度
	char readBuf[24] = {
    0};		//读缓存
	char writeBuf[24] = {
    0};	//写缓存

	cmd = (char *)malloc(12);
	memset(cmd,0,12);

	struct ringBuf *ringBuffer = NULL;

	ringBuffer = (struct ringBuf*)malloc(sizeof(struct ringBuf));

	/*环形缓冲区初始化*/
	ringBuffer = ringBufInit(ringBuffer,bufLen);


	while(1)
	{
    
		/*输入指令,根据不同指令实现不同功能*/
		printf("请输入指令(不要超过12字符):");
		scanf("%s",cmd);
		//	printf("%s\n",cmd);
		//

		cmdNum = cmdHand(cmd);

		switch(cmdNum)
		{
    

			/*从缓冲区读数据*/
			case read:
				printf("请输入需要读取的字符数:");
				scanf("%d",&strNum);

				memset(readBuf,0,sizeof(readBuf));
				ringBufRead(ringBuffer,readBuf,strNum);
				printf("读取结果:%s\n",readBuf);
				break;

			case write:
				/*往缓冲区写数据*/
				memset(writeBuf,0,sizeof(writeBuf));
				printf("请输入要写入内容:");
				scanf("%s",writeBuf);
				ringBufWrite(ringBuffer,writeBuf,strlen(writeBuf));
				printf("%s已写入\n",writeBuf);
				break;

			case quit:
				/*销毁缓冲区*/
				ringBufFree(ringBuffer);
				printf("环形缓冲区已销毁!\n");
				exit(0);
				break;

			case length:
				/*计算缓冲区数据长度*/
				dataLen = ringBufDataLen(ringBuffer);
				printf("缓冲区的有效数据长度为:%d\n",dataLen);
				break;

			default:
				printf("错误命令!\n");
				break;
		}
	}

	return 0;
}

9. Makefile

#main: main.c libringBufInit.a libringBufWrite.a libringBufRead.a libringBufDataLen.a libringBufFree.a libcmdHand.a
#	gcc -o main main.c -L . -lringBufInit -lringBufWrite -lringBufRead -lringBufDataLen -lringBufFree -lcmdHand

#libringBufInit.a:
#	gcc -c ringBufInit.c -o ringBufInit.o
#	ar rcs libringBufInit.a ringBufInit.o

#libringBufWrite.a:
#	gcc -c ringBufWrite.c -o ringBufWrite.o
#	ar rcs libringBufWrite.a ringBufWrite.o

#libringBufRead.a:
#	gcc -c ringBufRead.c -o ringBufRead.o
#	ar rcs libringBufRead.a ringBufRead.o

#libringBufDataLen.a:
#	gcc -c ringBufDataLen.c -o ringBufDataLen.o
#	ar rcs libringBufDataLen.a ringBufDataLen.o

#libringBufFree.a:
#	gcc -c ringBufFree.c -o ringBufFree.o
#	ar rcs libringBufFree.a ringBufFree.o
#
#libcmdHand.a:
#	gcc -c cmdHand.c -o cmdHand.o
#	ar rcs libcmdHand.a cmdHand.o

#clean:
#	rm *.o
#	rm main
#	rm *.a

main: main.c libringBufInit.so libringBufWrite.so libringBufRead.so libringBufDataLen.so libringBufFree.so libcmdHand.so
	gcc -o main main.c -L . -lringBufInit -lringBufWrite -lringBufRead -lringBufDataLen -lringBufFree -lcmdHand

libringBufInit.so:
	gcc -fPIC -shared ringBufInit.c -o libringBufInit.so

libringBufWrite.so:
	gcc -fPIC -shared ringBufWrite.c -o libringBufWrite.so

libringBufRead.so:
	gcc -fPIC -shared ringBufRead.c -o libringBufRead.so

libringBufDataLen.so:
	gcc -fPIC -shared ringBufDataLen.c -o libringBufDataLen.so

libringBufFree.so:
	gcc -fPIC -shared ringBufFree.c -o libringBufFree.so

libcmdHand.so:
	gcc -fPIC -shared cmdHand.c -o libcmdHand.so

clean:
	rm main
	rm *.so
	
版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/little_rookie__/article/details/121385854

智能推荐

vue本地上传并预览php,基于 vue.js 实现图片本地预览 + 裁剪 + 压缩 + 上传的功能(二)..._nearbas的博客-程序员宅基地

这一篇要说说裁剪、压缩,这两个功能都要用到 canvas 的能力,canvas 在 IE9 以上浏览器都支持良好,也为 IE9 提供为数不多的可以进行文件操作的 API。基础代码const canvas = document.getElementById('box')const ctx = canvas.getContext('2d')如何给 canvas 导入图片通过实例方法 drawImage...

VirtualBox上虚拟机网络配置并且使用iTerm ssh登录_silence12393的博客-程序员宅基地

网络小白,记录网络配置过程。环境:mac+virtualbox6.0.8+centos7一、创建网卡打开VirtualBox,左上角=&gt;管理=&gt;主机网络管理器=&gt;创建网卡,手动配置以下两种配置都可以保证主宿机互动网络,和虚拟机外网访问,任选一个即可。二、配置虚拟机网络(双卡)1.选中要配置的虚拟机,设置网络,添加第一块网卡仅主机(Host-only)...

jenkins(四)—安装git插件_xiaoqiang65的博客-程序员宅基地_jenkins安装git插件

1:点击 ManageJenkins 找到插件管理 点击搜素Git 如下图所示进行安装:安装成功 如下图所示:测试是否可以用:进入页面点击 "New Item"进入如下页面 点击OK 下拉即可进入如下页面 查看到Git选项则表示 此时还需要在Jenkins 服务主机上 安装Git程序 没有此程序无法在依赖Git程序的仓库拉代码 进入Jenkins 主机的Linux 服务器 进行安装Git 程序 ...

docker的基础操作_虎皮辣椒小怪兽的博客-程序员宅基地

1. 搜索http镜像[[email protected] ~]# docker search httpNAME DESCRIPTION STARS OFFICIAL AUTOMATEDhttpd The Apache HTTP Server Project 3909

mysql数据库密码安全参数_MySQL 参数解析 password_history_weixin_39758956的博客-程序员宅基地

MySQL 8.0 引入新的参数 password_history,用来控制历史密码的使用策略,增强密码安全性。password_history 参数定义了一个阈值,来控制之前使用的密码,在用户修改多少次之后,才能重复使用,该参数设置为0,表示禁用该策略。password_history:作用范围:Global动态修改:Yes默认值:0取值范围:0~4294967295举个例子,设置passwor...

TransCAD实用技术梗概_智能交通技术的博客-程序员宅基地

一、简介TransCAD软件是进行综合交通规划、公交线路规划、交通影响评价项目时交通模型建立的主要技术手段。本文是结合工作实践抽取的主要技术要点。详细操作请还需参考Caliper公司的两个...

随便推点

C语言disc函数,【职场之道】DISC行为模式深入了解_谢流远的博客-程序员宅基地

来源:网络编辑:磚頭哥上周一咱们从西游记里,聊了DISC行为模式的基本特性,今天磚頭哥再跟着大家,深入的讨论下DISC行为模式,以及如何利用DISC来使自己更好的工作,学习。1D型(支配/老板型)看过上周一文章的各位都应该知道,脾气大有魄力,高支配力的D型,我们也称之为老虎型。表现在平时的特点为:主动与他人握手,而且很用力从来不怕目光直视对方,而且表情严厉,让人望而生畏说话的口吻常常是命令式的在谈...

两大图灵奖得主力作:计算机架构的新黄金时代_OneFlow深度学习框架的博客-程序员宅基地_计算机架构的新黄金时代

未来十年,将会有一场新计算机架构的寒武纪爆炸,这对业界和学界的架构师们来说将是激动人心的时刻。

Python3的安装_xingkongyu_cc的博客-程序员宅基地

因为用的是mac,所以是自带python的,不过版本是2.7.1的,所以需要安装python3.6的版本。要安装最新的Python 3.6,有两个方法:方法一:从Python官网下载Python 3.6的安装程序(网速慢的同学请移步国内镜像),双击运行并安装;方法二:如果安装了Homebrew,直接通过命令brew install python3安装即可。注:

Python-CCF:Getting Start_无名J0kзr的博客-程序员宅基地

CCF-CSP认证模拟考试杂大概三十天时间吧,争取每天一道,只做1-4题,第5题应该不会做太多,有时间可能会看看大一还是大二用C考过,惨不忍睹,四个小时只做了两道,拿了160,太菜了如今携Python再次出征,先立个flag:目标是300+吧三月份考完来还愿。黄沙百战穿金甲不破楼兰终不还资源...

从几个问题开始理解CFS调度器_didi8206050的博客-程序员宅基地

CFS(完全公平调度器)是Linux内核2.6.23版本开始采用的进程调度器,它的基本原理是这样的:设定一个调度周期(sched_latency_ns),目标是让每个进程在这个周期内至少有机会运行一次,换一种说法就是每个进程等待CPU的时间最长不超过这个调度周期;然后根据进程的数量,大家平分这个调度周期内的CPU使用权,由于进程的优先级即nice值不同,分割调度周期的时候要加权;每个进程的累计运行

JSONP跨域请求+简答实现百度搜索_Helios_nannan的博客-程序员宅基地

什么是跨域呢?比如说ajax必须在自己的域(名)之下,才能进行异步的请求,如果不是在同一个域之下就不能进行请求,会报错。比如说我们用ajax去请求腾讯的API如果我们的这个域不在腾讯那个接口的’白名单’里面,腾讯的接口就会拒绝给我返回数据。但是大多数情况下,我们不可能每次都去去相应的网站申请一个’白名单’,这个时候我们就要用到跨域这种方法,跨域有很多方式比如说用iframe但是这种的可操作性太差了,

推荐文章

热门文章

相关标签