C 通用环形缓冲区

C 通用环形缓冲区,c,C,我已经实现了一个通用的环形缓冲区,但是我遇到了一些奇怪的结果。首先我成功地推送了15个整数,但是当我试图打印到缓冲区的内容时,它打印出了一些错误的元素 首先我为10个整数分配内存。然后我尝试推15,然后调整缓冲区的大小。也许调整缓冲区的大小会以某种方式破坏它,因为没有它,它工作得很好 RingBuffer.c #include<stdlib.h> #include<string.h> #include <stdio.h> #include"RingB

我已经实现了一个通用的环形缓冲区,但是我遇到了一些奇怪的结果。首先我成功地推送了15个整数,但是当我试图打印到缓冲区的内容时,它打印出了一些错误的元素

首先我为10个整数分配内存。然后我尝试推15,然后调整缓冲区的大小。也许调整缓冲区的大小会以某种方式破坏它,因为没有它,它工作得很好

RingBuffer.c

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

unsigned char RingInit(RingBuffer* buffer, int elemLen, int elemSize, void (*fn)(void*))
{
    buffer->dataLen = elemLen;
    buffer->dataSize = elemSize;
    
    if( (buffer->data = malloc( buffer->dataSize * buffer->dataLen )) == NULL){
        
        return 1;
    }

    buffer->head = 0;
    buffer->tail = 0;
    buffer->elemCount = 0;
    buffer->freeFn = fn;
    buffer->doResize = 1;
    buffer->resizeBy = 2;
    
    return 0;
}

unsigned char RingPush(RingBuffer* buffer, void* elem)
{
    if(RingIsFull(buffer)){

        if(!buffer->doResize || RingResize(buffer)){
            
            return 1;
        }
    }

    memcpy((buffer->data + (buffer->head*buffer->dataSize)), elem, buffer->dataSize);
    buffer->head = (buffer->head + 1) % buffer->dataLen;
    buffer->elemCount++;
    
    return 0;
}

unsigned char RingRead(RingBuffer* buffer, void* elem)
{
    if(!RingIsEmpty(buffer)){
        
        memcpy(elem, (buffer->data + (buffer->tail*buffer->dataSize)), buffer->dataSize);
        buffer->tail = (buffer->tail + 1) % buffer->dataLen;
        buffer->elemCount--;

        return 0;
    }

    return 1;
}

unsigned char RingIsEmpty(RingBuffer* buffer)
{
    return (buffer->elemCount == 0);
}

unsigned char RingIsFull(RingBuffer* buffer)
{
    return (buffer->elemCount == buffer->dataLen);
}

void RingFree(RingBuffer* buffer)
{
    buffer->freeFn(buffer->data);
}

unsigned char RingResize(RingBuffer* buffer)
{
    unsigned char* newMemory = NULL;

    if ( (newMemory = realloc(buffer->data, buffer->dataLen + (buffer->resizeBy * buffer->dataSize))) == NULL){
        
        return 1;
    }
    
    buffer->data = newMemory;
    buffer->dataLen += buffer->resizeBy;    
    buffer->head = buffer->elemCount;
    
    return 0;
}
#include<stdlib.h>
#include<string.h>
#include <stdio.h>
#include"RingBuffer.h"

#define ARRAY_LENGTH(a)     sizeof(a)/sizeof(a[0])

void freeInt(void* data)
{
    free(data);
}

int main(void)
{
    RingBuffer Ring;
    int buf[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    int i = 0;
    
    if(RingInit(&Ring, ARRAY_LENGTH(buf)-5, sizeof(int), freeInt) == 0){
        
        printf("\nRING INIT OK");
    }
    else{
        
        printf("\nRING INIT FAIL");
        RingFree(&Ring);
        return 0;
    }
    
    Ring.doResize = 1;
    for(i = 0 ; i < ARRAY_LENGTH(buf) ; i++){
        
        if(RingPush(&Ring, &buf[i])){
            
            printf("\nRING PUSH FAIL");
            RingFree(&Ring);
            return 0;
        }
        
        printf("\nRING PUSH OK->%d", buf[i]);
        printf(" %d", ((int*)(Ring.data))[i]); 
    }
    
    printf("\n");
    for(i = 0 ; i < ARRAY_LENGTH(buf); i++){
        
        printf(" %d", ((int*)(Ring.data))[i]);
    }
    
    memset(buf, 0, sizeof(buf));
    printf("\nLOAD ZEROS:");
    for(i = 0 ; i < ARRAY_LENGTH(buf); i++){
        printf(" %d", buf[i]);
    }
    
    i = 0;
    while(!RingIsEmpty(&Ring)){
        
        if(RingRead(&Ring, &buf[i])){
            
            printf("\nRING READ FAIL");
            RingFree(&Ring);
            return 0;
        }
        
        printf("\nRING READ OK->%d", buf[i]);
        i++;
    }
    
    getchar();
    RingFree(&Ring);
    return 0;
}
Test.c

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

unsigned char RingInit(RingBuffer* buffer, int elemLen, int elemSize, void (*fn)(void*))
{
    buffer->dataLen = elemLen;
    buffer->dataSize = elemSize;
    
    if( (buffer->data = malloc( buffer->dataSize * buffer->dataLen )) == NULL){
        
        return 1;
    }

    buffer->head = 0;
    buffer->tail = 0;
    buffer->elemCount = 0;
    buffer->freeFn = fn;
    buffer->doResize = 1;
    buffer->resizeBy = 2;
    
    return 0;
}

unsigned char RingPush(RingBuffer* buffer, void* elem)
{
    if(RingIsFull(buffer)){

        if(!buffer->doResize || RingResize(buffer)){
            
            return 1;
        }
    }

    memcpy((buffer->data + (buffer->head*buffer->dataSize)), elem, buffer->dataSize);
    buffer->head = (buffer->head + 1) % buffer->dataLen;
    buffer->elemCount++;
    
    return 0;
}

unsigned char RingRead(RingBuffer* buffer, void* elem)
{
    if(!RingIsEmpty(buffer)){
        
        memcpy(elem, (buffer->data + (buffer->tail*buffer->dataSize)), buffer->dataSize);
        buffer->tail = (buffer->tail + 1) % buffer->dataLen;
        buffer->elemCount--;

        return 0;
    }

    return 1;
}

unsigned char RingIsEmpty(RingBuffer* buffer)
{
    return (buffer->elemCount == 0);
}

unsigned char RingIsFull(RingBuffer* buffer)
{
    return (buffer->elemCount == buffer->dataLen);
}

void RingFree(RingBuffer* buffer)
{
    buffer->freeFn(buffer->data);
}

unsigned char RingResize(RingBuffer* buffer)
{
    unsigned char* newMemory = NULL;

    if ( (newMemory = realloc(buffer->data, buffer->dataLen + (buffer->resizeBy * buffer->dataSize))) == NULL){
        
        return 1;
    }
    
    buffer->data = newMemory;
    buffer->dataLen += buffer->resizeBy;    
    buffer->head = buffer->elemCount;
    
    return 0;
}
#include<stdlib.h>
#include<string.h>
#include <stdio.h>
#include"RingBuffer.h"

#define ARRAY_LENGTH(a)     sizeof(a)/sizeof(a[0])

void freeInt(void* data)
{
    free(data);
}

int main(void)
{
    RingBuffer Ring;
    int buf[15] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
    int i = 0;
    
    if(RingInit(&Ring, ARRAY_LENGTH(buf)-5, sizeof(int), freeInt) == 0){
        
        printf("\nRING INIT OK");
    }
    else{
        
        printf("\nRING INIT FAIL");
        RingFree(&Ring);
        return 0;
    }
    
    Ring.doResize = 1;
    for(i = 0 ; i < ARRAY_LENGTH(buf) ; i++){
        
        if(RingPush(&Ring, &buf[i])){
            
            printf("\nRING PUSH FAIL");
            RingFree(&Ring);
            return 0;
        }
        
        printf("\nRING PUSH OK->%d", buf[i]);
        printf(" %d", ((int*)(Ring.data))[i]); 
    }
    
    printf("\n");
    for(i = 0 ; i < ARRAY_LENGTH(buf); i++){
        
        printf(" %d", ((int*)(Ring.data))[i]);
    }
    
    memset(buf, 0, sizeof(buf));
    printf("\nLOAD ZEROS:");
    for(i = 0 ; i < ARRAY_LENGTH(buf); i++){
        printf(" %d", buf[i]);
    }
    
    i = 0;
    while(!RingIsEmpty(&Ring)){
        
        if(RingRead(&Ring, &buf[i])){
            
            printf("\nRING READ FAIL");
            RingFree(&Ring);
            return 0;
        }
        
        printf("\nRING READ OK->%d", buf[i]);
        i++;
    }
    
    getchar();
    RingFree(&Ring);
    return 0;
}
它应该打印数字1-15。它会打印出一些错误的数字。每次我启动程序时,不同的元素都是错误的

编译

gcc Test.c RingBuffer.c

编者版本

gcc(MinGW.org gcc-6.3.0-1)6.3.0 版权所有(C)2016免费软件基金会。 这是自由软件;有关复制条件,请参见源。没有
担保甚至不适用于适销性或特定用途。

您将
buffer->dataLen+(buffer->resizeBy*buffer->dataSize)
作为要在函数
RingResize
中分配的大小

不幸的是,
buffer->dataLen
是元素数,而不是字节数

因此,新分配的缓冲区将没有足够的字节数。 这将导致错误


要分配的大小应该是
buffer->dataSize*(buffer->dataLen+buffer->resizeBy)

您传递的
buffer->dataLen+(buffer->resizeBy*buffer->dataSize)
作为要在函数
RingResize
中分配的大小

不幸的是,
buffer->dataLen
是元素数,而不是字节数

因此,新分配的缓冲区将没有足够的字节数。 这将导致错误


要分配的大小应该是
buffer->dataSize*(buffer->dataLen+buffer->resizeBy)

地址Sanitizer在打印前检测到堆缓冲区溢出
环推确定->10 10
数组长度(buf)-5
@ChristianGibbons故意分配一个较小的缓冲区来测试调整大小功能是否有效请使用
size\u t
来调整大小!AddressSanitanizer在打印前检测到堆缓冲区溢出
RING PUSH OK->10 10
ARRAY_LENGTH(buf)-5
@ChristianGibbons故意分配一个较小的缓冲区来测试调整大小功能是否工作请使用
size_t
来调整大小!