문제

So learning pointers in C and i thought that as an exercise i could do some generic array and i got it working when using void** like this:

struct array{
    void **data;
    size_t size, capacity;
};

inserting elements like this:

void array_append(array *a, void *element){
    if(a->size == a->capacity){
        a->capacity += ARRAY_GROW_CONSTANT;
        a->data = realloc(a->data, sizeof(void*)*a->capacity);
    }
    a->data[a->size++] = element;
}

But this is not really good. The array stores pointers to elements so when the scope of element ends, it becomes invalid, and also it makes the content of array to be scattered across entire memory. This i think can be solved by allocating the elements themselves so instead

a->data[a->size++] = element;

i would do something like

a->data[a->size] = malloc(inserted_element_size);
memcpy(a->data[a->size], &element, inserted_element_size);
size++;

but i thought that i could get the same funcionality when using plain void*, instead of void**

struct array{
    void *start;
    size_t element_size, size;
};

and inserting elements like

void array_append(array *a, void *element){
    a->size += 1;
    a->data = realloc(a->data, (a->size*a->element_size));
    memcpy(a->data + (a->size - 1)*a->element_size, &element, a->element_size);
}

but this results into segfault and i don't know why. As i understand it (obviously i don't), pointers are adresses in memory, so if i have a contiguous block of memory, i can store variable of any type in it with offset.

Edit: Thanks for the explanation, it really helped.

What is a->data initialized to?

I used a function to initialize the array and the a->data was initialized to element_size.

the caller will have to cast the resutl into element *

I thought i could use macro to make the typing shorter (i think this is a bad thing?), but i don't know about the performance of typecasting from void* to struct*.

Creating a dynamic array of elements directly seems more practical to me.

But that wouldn't allow me to use the array as generic one? What i wanted was to define a generic array that i could use to store any type, like

array *a1 = create_array(sizeof(int)); // array of int
array *a2 = create_array(sizeof(double)); // array of double
etc...

why do you want your data to be stored in a contiguous block?

Because i thought that you need a contiguous block of memory to use memcpy with offset.

도움이 되었습니까?

해결책

What is a->data initialized to? For this to work, it should be set to NULL when the (empty) array is created.

Also, you address computation does not take pointers arithmetics into account. a->data is a pointer (to void *), so the (a->size - 1)*a->element_size offset will be multiplied by the size of a pointer (to void *). Setting a->data to void * should cause a compiler error since void has no size.

If you really want to do this, better declare a->data as a char *, which is guaranteed to have a size of 1.

Beware: accessing your array will require a cast to (element*). This will prevent you from using square brackets.
You will have to provide an accessor function like void * array_at(size_t index) { return &a->data[index*a->element_size]; }
and then the caller will have to cast the resutl into element *.

Creating a dynamic array of elements directly seems more practical to me.
You can still call realloc on it if you want.

But the first question that springs to my mind is: why do you want your data to be stored in a contiguous block?

This is not as memory-efficient as you might think, since calling realloc() repeatedly will stress the memory allocator, waste time doing copies and possibly fragment the heap even more than a collection of individual mallocs.

다른 팁

Commenting on the last portion of the code using void* as the array for data. The code should work but it has problems:

You are passing the address of the element pointer instead of just the pointer itself, which already pointer to correct( hopefully ) data.

Also you cannot do pointer arithmetic on void, but certain compilers allow it.

The correct version of memcpy would be

memcpy ( ( unsigned char* )a->data + (a->size - 1)*a->element_size, element, a->element_size);
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top