You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

环形缓冲区莫名添加额外元素?代码问题排查求助

环形缓冲区出现未写入元素5的问题排查

问题描述

练习环形缓冲区代码时,预期缓冲区满时丢弃传入数据,但添加4个元素后,缓冲区中出现了未写入的元素5。以下是相关代码和运行输出:

示例代码

#include <stdio.h>
#include <stdint.h>
#include <sys/types.h>
#include <unistd.h>
#include <stdbool.h>
#include <stdlib.h>
#include <assert.h>
#include <string.h>

typedef struct {
    void *buf;
    ssize_t ri; //read index
    ssize_t wi; //write index
    ssize_t capacity; // total size of buffer in bytes
    size_t max_count;
    size_t count;
    ssize_t sz; // size of individual elements in bytes
    bool full;
} r_buffer_t;

r_buffer_t* ring_buffer_init(unsigned int count, ssize_t dsize) {
    r_buffer_t *buffer = malloc(sizeof(r_buffer_t));
    if(buffer != NULL){
        buffer->buf =  malloc(count * sizeof(dsize));
        if(buffer->buf != NULL) {
            buffer->max_count = count;
            buffer->sz = dsize;
            buffer->count = 0;
            buffer->ri = 0;
            buffer->wi = 0;
            buffer->capacity = count * dsize;
            buffer->full = false;
            return buffer;
        }
        free(buffer);
    }
    return NULL;
}

int put_item(r_buffer_t *buffer, void *data) {
    assert(buffer && data); // exception catch on stderr;
    if(!buffer->full) {
        printf("\nw-memcpy");
        memcpy((buffer->buf + (buffer->wi * buffer->sz)), data, sizeof(buffer->sz));
        printf("\n\t\tret\tdata\tcount\tfull\twi");
        printf("\nAdding data :\t%d\t%d\t%ld\t%d\t%ld", 0, *((int*)data), buffer->count, buffer->full, buffer->wi);
        buffer->count++;
        buffer->wi++;
        buffer->wi %= buffer->max_count;
        if(buffer->count >= buffer->max_count) {
            printf("\n>>>Full for count = %ld, buffer-full = %d, index ri = %ld, wi=%ld",
                buffer->count, buffer->full, buffer->ri, buffer->wi);
            buffer->full = true;
        }
        return 0;
    }
    printf("\n>>>Dropping data. Buffer Full for count = %ld, buffer-full = %d, index ri = %ld, wi=%ld",
                buffer->count, buffer->full, buffer->ri, buffer->wi);
    return -1;
}

int get_item(r_buffer_t *buffer, void *data) {
    assert(buffer && data);
    if(buffer->count > 0) {
        printf("r-memcpy");
        memcpy(data, (buffer->buf + (buffer->ri * buffer->sz)), buffer->sz);
        memset((buffer->buf + (buffer->ri * buffer->sz)), 0, buffer->sz);
        buffer->count--;
        buffer->ri++;
        buffer->ri %= buffer->max_count;
        buffer->full = (buffer->count >= buffer->max_count);
        return 0;
    }
    return -1;
}
void print_buffer(r_buffer_t *buffer) {
    int i = 0;
    printf("\n*************Buffer***********\n");
    printf("\ncount = %ld, full = %d, ri = %ld, wi = %ld",
            buffer->count, buffer->full, buffer->ri, buffer->wi);
    printf("\n\t");
    for(i =0; i < buffer->max_count; i++){
        if(buffer->ri == i)
            printf("R  ");
        else
            printf("   ");
    }
    printf("\n\t");
    for(i =0; i < buffer->max_count; i++)
        printf("%d |", *(int *)(buffer->buf + i * buffer->sz));
    printf("\n\t");
    for(i =0; i < buffer->max_count; i++){
        if(buffer->wi == i)
            printf("W  ");
        else
            printf("   ");
    }
    printf("\n*********************************\n");
}
int main() {
    int i = 0;
    int d1[] = {1,2,3,4,5,6,7,8,9,10};
    int rd = 0;
    int ret = 0;
    r_buffer_t *buf = ring_buffer_init(5, sizeof(unsigned int));
    print_buffer(buf);
    printf("\nAdding 4 items to buffer");
    for(i = 0; i < 4; i++) { 
        printf("\nCalling put for %d", d1[i]);
        ret = put_item(buf, (void *)&d1[i]);
    }
    print_buffer(buf);
    printf("\nRemoving and printing 2");
    for(i = 0; i < 2; i++){
        get_item(buf, &rd);
    }
    print_buffer(buf);
    printf("\nAdding 4 more items to buffer");
    for(i = 4; i < 9; i++) { 
        ret = put_item(buf, &d1[i]);
    }
    print_buffer(buf);
    return 0;
}

运行输出

*************Buffer***********

count = 0, full = 0, ri = 0, wi = 0
        R              
        0 |0 |0 |0 |0 |
        W              
*********************************

Adding 4 items to buffer
Calling put for 1
w-memcpy
                ret     data    count   full    wi
Adding data :   0       1       0       0       0
Calling put for 2
w-memcpy
                ret     data    count   full    wi
Adding data :   0       2       1       0       1
Calling put for 3
w-memcpy
                ret     data    count   full    wi
Adding data :   0       3       2       0       2
Calling put for 4
w-memcpy
                ret     data    count   full    wi
Adding data :   0       4       3       0       3
*************Buffer***********

count = 4, full = 0, ri = 0, wi = 4
        R              
        1 |2 |3 |4 |5 |
                    W  
*********************************

问题原因及修正

1. memcpy复制长度错误(直接导致元素5出现)

在put_item函数中,memcpy的第三个参数错误使用了sizeof(buffer->sz),这会取变量buffer->sz的类型大小(ssize_t通常为8字节),而非单个元素的实际大小(buffer->sz的值,此处为4字节)。

当写入第4个元素(d1[3],值为4)时,memcpy会从&d1[3]开始复制8字节,而d1是连续存储的int数组,这会同时把d1[3](4)和d1[4](5)复制到缓冲区,覆盖了缓冲区的索引3和索引4位置,因此出现未写入的元素5。

修正代码:

memcpy((buffer->buf + (buffer->wi * buffer->sz)), data, buffer->sz);

2. 缓冲区内存分配计算错误

在ring_buffer_init函数中,内存分配时错误使用了sizeof(dsize),这会取参数dsize的类型大小(ssize_t通常为8字节),而非传入的单个元素大小(dsize的值,此处为4字节)。这会导致缓冲区分配的内存远大于实际需求,造成内存浪费,极端场景下可能引发越界问题。

修正代码:

buffer->buf = malloc(count * dsize);

内容的提问来源于stack exchange,提问作者preetam

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.31 17:35:14