-1

I have to create a generic array that can contain generic data structures. How can i put a generic structure into an empty slot of my void array?

This is my code.

struct CircularBuffer {
    int E;
    int S;
    int length;   // total number of item allowable in the buffer
    int sizeOfType;   // size of each element in the buffer
    void *buffer;
};

struct CircularBuffer* circularBufferInit(int length, int sizeOfType) {

    struct CircularBuffer *cb = malloc(sizeof(struct CircularBuffer));
    cb->E = 0;
    cb->S = 0;
    cb->length = length;
    cb->sizeOfType = sizeOfType;
    cb->buffer = malloc(sizeOfType *length);
    return cb;
}

int circularBufferIsEmpty(struct CircularBuffer* cb) {
    if (cb->S == cb->E)
        return 1; //empty
    else
        return 0;
}

int circularBufferIsFull(struct CircularBuffer *cb) {
    int nE = (cb->E + 1) % (cb->length);
    if (nE == cb->S)
        return 1; //full
    else
        return 0;
}

void circularBufferAdd(struct CircularBuffer *cb, void* obj) {
    memcpy(cb->buffer + cb->E, obj, cb->sizeOfType);
}
[...]

memcpy is the problem...

Simon
  • 95
  • 1
  • 11
  • SO is no tutorial or consulting site. If you ahve a _specific_ problem please provide a [mcve]. First you might want to take the [tour]. – too honest for this site Jul 30 '15 at 21:22
  • 1
    `memcpy((char *)cb->buffer + (cb->E * cb->sizeOfType), obj, cb->sizeOfType);` – Dmitri Jul 30 '15 at 21:24
  • 2
    Basically, you can't do pointer arithmetic on `void *`, so you need to cast to `char *`... then multiply the element number by the size to get the right offset in `char`s. – Dmitri Jul 30 '15 at 21:27
  • Shouldn't `circularBufferAdd()` also do something like, `cb->E = (cb->E + 1) % cb->length;`? – Dmitri Jul 30 '15 at 21:56
  • yes, @Dmitri, exactly – Simon Jul 30 '15 at 22:53
  • @Dmitri: Note that GCC has an extension, enabled by default, that treats `void *` as if type '`void`' has a size of `1`, like a `char` has a size of `1`. This can lead to people being confused. Strict standard compliance disallows arithmetic on void pointers, as you indicate. – Jonathan Leffler Aug 06 '15 at 04:37

1 Answers1

2

It seems that essentially you're trying to figure out how to offset a void * to the address of an array element of known size but unknown type so you can pass it to memcpy().

It looks as though, in circularBufferAdd(), cb->E gives the index of the element you want to copy to, cb->buffer is the void * to the array, obj is the item to be copied, and cb->sizeOfType is the size each array element (and obj). In that case you can change:

    memcpy(cb->buffer + cb->E, obj, cb->sizeOfType);

to:

    memcpy((char *)cb->buffer + (cb->E * cb->sizeOfType), obj, cb->sizeOfType);

Since you can't use pointer arithmetic with a void *, you'd cast it to char *. Then, you can multiply the element index by the element size to get the offset of the element in bytes, and use that to get the address of the element you need.

Dmitri
  • 9,175
  • 2
  • 27
  • 34
  • I have tried with your hint: `struct CircularBuffer* cb = circularBufferInit(20, sizeof(int)); circularBufferAdd(cb, (void*)6); int i; i = (int) circularBufferRead(cb); printf("%d", i); ` But there is a segmentation fault. – Simon Jul 30 '15 at 22:44
  • @Simon That's a different problem... "`(void *)6`" doesn't make sense (it gives a `void *` that points at the memory address `6`, not the address of an integer with the value 6). You need to give the address of an actual object/variable. Also, a `circularBufferRead()` function (which you hadn't shown) can't return the object from the array without knowing its type... you'd have to use pointers. – Dmitri Jul 30 '15 at 22:55
  • It's true! My bad! Thank you. So, now: `int a = 6; circularBufferAdd(cb, &a); [...]`. Now it works fine. Thanks :) And for `circularBufferRead`, yes...i use a pointer! `void* circularBufferRead(struct CircularBuffer *cb) { void* obj = malloc(cb->sizeOfType); obj = &cb->buffer[cb->S]; return obj; }`. So, i can use it in this way: `int i; i = *(int*) circularBufferRead(cb);` – Simon Jul 30 '15 at 23:05
  • Sorry...the last comment is "a lie"!! This is the working code: `memcpy(obj, (char *)cb->buffer + (cb->S * cb->sizeOfType), cb->sizeOfType);` – Simon Jul 30 '15 at 23:18