循环缓冲区的结束指针问题

时间:2011-02-21 11:20:47

标签: c memory pointers buffer circular-buffer

我正在使用Visual c ++。

我正在尝试实现循环缓冲区,这个CB必须处理特定类型的数据......实际上,它是一个结构数据,我们将某种原始数据存储在char类型和日期中与该数据相关联......这已经使用结构实现。

以下是有关详细信息的代码:

#include <stdio.h>
#include <time.h>
#include <windows.h>



//data=date_label+raw_data
typedef struct DataFragment 
{
    char data[4];
    clock_t date;

 }DataFragment;

typedef struct CircularBuffer
{
    DataFragment *buffer;     // data buffer
    DataFragment *buffer_end; // end of data buffer
    size_t capacity;  // maximum number of items in the buffer
    size_t count;     // number of items in the buffer
    size_t sz;        // size of each item in the buffer
DataFragment *head;       // pointer to head
    DataFragment *tail;       // pointer to tail
 } CircularBuffer;


void cb_init(struct CircularBuffer *cb, size_t capacity, size_t sz)
 {

 if((cb->buffer = (DataFragment*) malloc(capacity * sz))!=NULL)
    puts("success alocation");
//if(cb->buffer == NULL)
     //handle error
cb->buffer_end = (DataFragment *)cb->buffer + (capacity-1)*sz;
cb->capacity = capacity;
cb->count = 0;
cb->sz = sz;
cb->head = cb->buffer;
cb->tail = cb->buffer;
}

 void cb_free(struct CircularBuffer *cb)
 {
     free(cb->buffer);
     // clear out other fields too, just to be safe
 }

 void cb_push_back(struct CircularBuffer *cb, const DataFragment *item)
  {
     //if(cb->count == cb->capacity)
       //handle error when it's full
memcpy(cb->head->data, item->data,4);
cb->head->date=item->date;
cb->head = (DataFragment*)cb->head + cb->sz;
    if(cb->head == cb->buffer_end)
      cb->head = cb->buffer;
    cb->count++;
   }

 void cb_pop_front(struct CircularBuffer *cb, DataFragment *item)
 {
   //if(cb->count == 0)
     //handle error
memcpy(item->data, cb->tail->data,4);
item->date=cb->tail->date;
cb->tail = (DataFragment*)cb->tail + cb->sz;
    if(cb->tail == cb->buffer_end)
      cb->tail = cb->buffer;
    cb->count--;
  }

int main(int argc, char *argv[])
 {

struct CircularBuffer pbuf;

pbuf.buffer=NULL;
pbuf.buffer_end=NULL;
pbuf.capacity=0;
pbuf.count=0;
pbuf.head=NULL;
pbuf.sz=0;
pbuf.tail=NULL;
struct CircularBuffer *buf= &pbuf;
size_t sizz = sizeof(DataFragment);

//initialisation of the circlar buffer to a total bytes 
//of capacity*sizz=100*sizeof(struct DataFragment)
cb_init(buf,100,sizz);

//temporary container of data
DataFragment temp,temp2;

for(int i=0;i<4;i++)
    temp.data[i]='k';
for(int i=0;i<4;i++)
    temp2.data[i]='o';

//pushing temporary buffer to the CB...40*2=80<capacity of the CB
for(int i=0;i<40;i++)
{
    Sleep(20);
    temp.date=clock();
    cb_push_back(buf,&temp);
    Sleep(10);
    temp2.date=clock();
    cb_push_back(buf,&temp2);
}

DataFragment temp3;
for(int i=0;i<20;i++)
{
    cb_pop_front(buf,&temp3);
    printf("%d\n", temp3.data); //print integers....no need of end caracter
}
cb_free(buf);

return 0;
}

当我编译代码时,一切都很好,但是当我调试时,我注意到buffer_end指针有问题,它说bad_pointer ....如果容量大于56,就会发生这种情况......我不知道知道为什么指针不能指向缓冲区的末尾。但是如果容量小于56,则指针指向缓冲区的末尾

如果有人知道为什么会发生这种情况,以及如何解决,请帮帮我..

提前致谢

4 个答案:

答案 0 :(得分:2)

我认为您需要删除* sz。 (而且我认为你不需要演员。)

cb->buffer_end = cb->buffer + (capacity-1);

指针运算自动计算指向的类型的大小。

我还应该指出boost::circular_buffer

答案 1 :(得分:2)

似乎你误解了指针算法

cb->buffer_end = (DataFragment *)cb->buffer + (capacity-1)*sz;
cb->head = (DataFragment*)cb->head + cb->sz;
cb->tail = (DataFragment*)cb->tail + cb->sz;

指针算法已经考虑了基础类型的大小。你真正需要的只是

++cb->head;
++cb->tail;

如果想要破解sizeof(DataFragment) - 可能为一个项目分配比结构大小更多的存储空间 - 出于某种恶意目的 - 你需要先将指针强制转换为char* (因为sizeof(char) == 1)。

cb->tail = (DataFragment*)((char*)cb->tail + cb->sz);

设计方面,结构似乎有太多成员:buffer_endcapacity相互重复(给定一个,你总能找到另一个),sz成员不是必要的(它应该始终是sizeof(DataFragment)

另外,我相信你可以只指定结构

*(cb->head) = *item;

似乎有完全不必要的强制转换(可能是由于对指针算术的误解造成的):

cb->buffer_end = (DataFragment *)cb->buffer + (capacity-1)*sz;

如果它应该是C ++,那么它包含许多“C-isms”(typedeffing结构,使用struct XXX var; - 尽管它有typedeffed等),并且代码通常是纯粹设计的C风格(没有利用C ++的最大优势,使用RAII进行自动资源管理)。


我还要指出clock()几乎没有给你一个日期:)

答案 2 :(得分:1)

你假设指针是4字节宽。在所有平台(x86_64)上可能并非如此。因此,memcpy()应该使用sizeof运算符。 “end = buffer +(capacity - 1)* size”似乎还有另一个错误。与cb_push_back()一起使用时,你要分配一个元素太多(或者你没有使用ringbuffer的最后一个元素).cb_count会增加在每个push_back中,所以你的缓冲区可以拥有比元素更多的“计数”。

答案 3 :(得分:0)

如果要用C ++编写代码,至少要使用STL。试试std::list