C語言實(shí)現(xiàn)環(huán)形緩沖區(qū)

環(huán)形緩沖區(qū)


image.png

環(huán)形緩沖區(qū)的特性
1、先進(jìn)新出
2迷帜、當(dāng)緩沖區(qū)被使用完物舒,且又有新的數(shù)據(jù)需要存儲(chǔ)時(shí),丟掉歷史最久的數(shù)據(jù)戏锹,保存最新數(shù)據(jù)
現(xiàn)實(shí)中的存儲(chǔ)介質(zhì)都是線性的冠胯,因此我們需要做一下處理,才能在功能上實(shí)現(xiàn)環(huán)形緩沖區(qū)


image.png

算法說明:
1锦针、pHead和pTail分別是連續(xù)存儲(chǔ)介質(zhì)的首地址和尾地址

2荠察、pTail - pHead 的值是環(huán)形緩沖區(qū)的總長(zhǎng)度
3、pValid 是使用區(qū)域的起始指針奈搜,取數(shù)據(jù)時(shí)的起點(diǎn)悉盆,當(dāng)取數(shù)據(jù)時(shí)pValid要發(fā)生偏移
4、pValidTail 是使用區(qū)域的的結(jié)尾指針馋吗,存數(shù)據(jù)時(shí)的起點(diǎn)焕盟,當(dāng)存數(shù)據(jù)時(shí),pValidTail要發(fā)生偏移
5宏粤、現(xiàn)有長(zhǎng)度為addLen字節(jié)要存入,當(dāng)pValidTail + addLen > pTail 時(shí)(超出了緩沖區(qū)京髓,這時(shí)就要繞到開頭pHead)
int len1 = pTail - pValidTail;
int len2 = addLen - len1;
pValidTail = pHead + len2;//新的使用區(qū)的尾指針
6、判斷總長(zhǎng)度是否變更商架,即是否有數(shù)據(jù)覆蓋pValid所指向的區(qū)域,如果有芥玉,要偏移pValid
下面是已驗(yàn)證的代碼

ringBuffer.c:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <assert.h>
#include "ringBuffer.h"
#define BUFFER_SIZE  16   //緩沖區(qū)的長(zhǎng)度,可以修改

static u32 validLen;//已使用的數(shù)據(jù)長(zhǎng)度
static u8* pHead = NULL;//環(huán)形存儲(chǔ)區(qū)的首地址
static u8* pTail = NULL;//環(huán)形存儲(chǔ)區(qū)的結(jié)尾地址
static u8* pValid = NULL;//已使用的緩沖區(qū)的首地址
static u8* pValidTail = NULL;//已使用的緩沖區(qū)的尾地址

/*
 * 初始化環(huán)形緩沖區(qū)
 * 環(huán)形緩沖區(qū)這里可以是malloc申請(qǐng)的內(nèi)存,也可以是Flash存儲(chǔ)介質(zhì)
 * */
void initRingbuffer(void)
{
    if(pHead == NULL)
    {
        pHead = (u8*) malloc(BUFFER_SIZE);
    }
    pValid = pValidTail = pHead;
    pTail = pHead + BUFFER_SIZE;
    validLen = 0;
}

/*
 * function:向緩沖區(qū)中寫入數(shù)據(jù)
 * param:@buffer 寫入的數(shù)據(jù)指針
 *       @addLen 寫入的數(shù)據(jù)長(zhǎng)度
 * return:-1:寫入長(zhǎng)度過大
 *        -2:緩沖區(qū)沒有初始化
 * */
int wirteRingbuffer(u8* buffer,u32 addLen)
{
    if(addLen > BUFFER_SIZE) return -2;
    if(pHead==NULL) return -1;
    assert(buffer);

    //將要存入的數(shù)據(jù)copy到pValidTail處
    if(pValidTail + addLen > pTail)//需要分成兩段copy
    {
        int len1 = pTail - pValidTail;
        int len2 = addLen - len1;
        memcpy( pValidTail, buffer, len1);
        memcpy( pHead, buffer + len1, len2);
        pValidTail = pHead + len2;//新的有效數(shù)據(jù)區(qū)結(jié)尾指針
    }else
    {
        memcpy( pValidTail, buffer, addLen);
        pValidTail += addLen;//新的有效數(shù)據(jù)區(qū)結(jié)尾指針
    }

    //需重新計(jì)算已使用區(qū)的起始位置
    if(validLen + addLen > BUFFER_SIZE)
    {
        int moveLen = validLen + addLen - BUFFER_SIZE;//有效指針將要移動(dòng)的長(zhǎng)度
        if(pValid + moveLen > pTail)//需要分成兩段計(jì)算
        {
            int len1 = pTail - pValid;
            int len2 = moveLen - len1;
            pValid = pHead + len2;
        }else
        {
            pValid = pValid + moveLen;
        }
        validLen = BUFFER_SIZE;
    }else
    {
        validLen += addLen;
    }

    return 0;
}

/*
 * function:從緩沖區(qū)內(nèi)取出數(shù)據(jù)
 * param   :@buffer:接受讀取數(shù)據(jù)的buffer
 *          @len:將要讀取的數(shù)據(jù)的長(zhǎng)度
 * return  :-1:沒有初始化
 *          >0:實(shí)際讀取的長(zhǎng)度
 * */
int readRingbuffer(u8* buffer,u32 len)
{
    if(pHead==NULL) return -1;

    assert(buffer);

    if(validLen ==0) return 0;

    if( len > validLen) len = validLen;

    if(pValid + len > pTail)//需要分成兩段copy
    {
        int len1 = pTail - pValid;
        int len2 = len - len1;
        memcpy( buffer, pValid, len1);//第一段
        memcpy( buffer+len1, pHead, len2);//第二段蛇摸,繞到整個(gè)存儲(chǔ)區(qū)的開頭
        pValid = pHead + len2;//更新已使用緩沖區(qū)的起始
    }else
    {
        memcpy( buffer, pValid, len);
        pValid = pValid +len;//更新已使用緩沖區(qū)的起始
    }
    validLen -= len;//更新已使用緩沖區(qū)的長(zhǎng)度

    return len;
}

/*
 * function:獲取已使用緩沖區(qū)的長(zhǎng)度
 * return  :已使用的buffer長(zhǎng)度
 * */
u32 getRingbufferValidLen(void)
{
    return validLen;
}

/*
 * function:釋放環(huán)形緩沖區(qū)
 * */
void releaseRingbuffer(void)
{
    if(pHead!=NULL) free(pHead);
    pHead = NULL;
}

ringBuffer.h

#ifndef RINGBUFFER_H_
#define RINGBUFFER_H_
typedef unsigned char u8;
typedef unsigned int u32;

void initRingbuffer(void);
int wirteRingbuffer(u8* buffer,u32 len);
int readRingbuffer(u8* buffer,u32 len);
u32 getRingbufferValidLen(void);
void releaseRingbuffer(void);

#endif /* RINGBUFFER_H_ */

測(cè)試 main 函數(shù)

#include <stdio.h>
#include <stdlib.h>
#include "ringBuffer.h"
// 主函數(shù)
int main()
{
    char c;
    int readLen;
    u8 readBuffer[10];
    //setvbuf(stdout,NULL,_IONBF,0); //pinrtf、putchar不能立馬輸出灿巧,打開此注釋
    initRingbuffer();

    printf("Please enter a line [blank line to terminate]> ");
    do{
        c=getchar();
        putchar(c);
        switch(c)
        {
            case 'Q':
                goto exit;
            break;
            case 'R':
                readLen = readRingbuffer(readBuffer,10);
                printf("readRingbuffer len:%d\n",readLen);
                if(readLen > 0){
                    printf("readRingbuffer:");
                    for(int i=0;i<readLen;i++){
                        printf("%c ",(char)readBuffer[I]);
                    }
                    printf("\n");
                }
            break;
            default :
                if(c!='\n') wirteRingbuffer((u8*)&c,1);
            break;
        }
    }while (1);



exit:
    releaseRingbuffer();
    printf("exit.\n");
    return 0;
}

原文鏈接:https://blog.csdn.net/maowentao0416/article/details/81984269

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末赶袄,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子抠藕,更是在濱河造成了極大的恐慌饿肺,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,546評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件盾似,死亡現(xiàn)場(chǎng)離奇詭異敬辣,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,224評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門溉跃,熙熙樓的掌柜王于貴愁眉苦臉地迎上來村刨,“玉大人,你說我怎么就攤上這事撰茎∏段” “怎么了?”我有些...
    開封第一講書人閱讀 164,911評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵龄糊,是天一觀的道長(zhǎng)逆粹。 經(jīng)常有香客問我,道長(zhǎng)炫惩,這世上最難降的妖魔是什么僻弹? 我笑而不...
    開封第一講書人閱讀 58,737評(píng)論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮诡必,結(jié)果婚禮上奢方,老公的妹妹穿的比我還像新娘。我一直安慰自己爸舒,他們只是感情好蟋字,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,753評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著扭勉,像睡著了一般鹊奖。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上涂炎,一...
    開封第一講書人閱讀 51,598評(píng)論 1 305
  • 那天忠聚,我揣著相機(jī)與錄音,去河邊找鬼唱捣。 笑死两蟀,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的震缭。 我是一名探鬼主播赂毯,決...
    沈念sama閱讀 40,338評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼拣宰!你這毒婦竟也來了党涕?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,249評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤巡社,失蹤者是張志新(化名)和其女友劉穎膛堤,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體晌该,經(jīng)...
    沈念sama閱讀 45,696評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡肥荔,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,888評(píng)論 3 336
  • 正文 我和宋清朗相戀三年绿渣,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片次企。...
    茶點(diǎn)故事閱讀 40,013評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡怯晕,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出缸棵,到底是詐尸還是另有隱情舟茶,我是刑警寧澤,帶...
    沈念sama閱讀 35,731評(píng)論 5 346
  • 正文 年R本政府宣布堵第,位于F島的核電站吧凉,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏踏志。R本人自食惡果不足惜阀捅,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,348評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望针余。 院中可真熱鬧饲鄙,春花似錦、人聲如沸圆雁。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,929評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽伪朽。三九已至轴咱,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間烈涮,已是汗流浹背朴肺。 一陣腳步聲響...
    開封第一講書人閱讀 33,048評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留坚洽,地道東北人戈稿。 一個(gè)月前我還...
    沈念sama閱讀 48,203評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像讶舰,于是被迫代替她去往敵國(guó)和親器瘪。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,960評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容