I am trying to use a double void
pointer but I am a little bit confused about the usage.
I have a struct
that contains a void **
array.
struct Thing{
void ** array;
};
struct Thing * c = malloc (sizeof(struct Thing));
c->array = malloc( 10 * sizeof(void *) );
So If I want to assign a different object to each pointer and try to retrieve the value
// Option 1
*(c->array + index) = (void *) some_object_ptr;
// Option 2
c->array[index] = (void *) some_object_ptr;
then, I have another function that gives (void *) item
that points to each cell, not the some_object_ptr
.
If I want to retrieve the value which pointed to by some_object_ptr
,
should I do
function return type is 'void *' and takes argument 'void *'
// Option 3
return (void**) item
// Option 4
return *((void**)item)?
the weird thing is that when I used array the array subscript method I couldn't use option 4, only option 3; and when I used *(c->array + index)
I could only use opt.4. and not opt.3. ..
Can anyone please tell me about this? If I am making any invalid assumptions, then could you please correct me?
The void pointer in C is a pointer which is not associated with any data types. It points to some data location in the storage means points to the address of variables. It is also called general purpose pointer. In C, malloc() and calloc() functions return void * or generic pointers.
C pointers int *ptr; This declares ptr as the identifier of an object of the following type: pointer that points to an object of type int.
void* is a "pointer to anything". void ** is another level of indirection - "pointer to pointer to anything". Basically, you pass that in when you want to allow the function to return a pointer of any type.
Why do we use a void pointer in C programs? We use the void pointers to overcome the issue of assigning separate values to different data types in a program. The pointer to void can be used in generic functions in C because it is capable of pointing to any data type.
A void **
is just a pointer to a pointer to memory with an unspecified type. You can only dereference it once (since you can't dereference a void *
). However, apart from that, it is basically like any other pointer type. If it helps you, think of it the same way as you would with int *
.
So, in your specific situation, we have:
void** array;
int arrayLen = 10;
array = (void**)malloc(arrayLen * sizeof(void*));
some_type_t* some_object_ptr;
// The following two assignment are equivalent since in C,
// array[index] <=> *(array + index)
array[index] = (void*)some_object_ptr;
*(array + index) = (void*)some_object_ptr;
Then array
is a pointer to the whole array, while *array
is a pointer to the first element, since it is equivalent to array[0]
.
One quick hint about pointers: if you are casting it, you are probably doing something wrong.
As for your question. I am not sure what item
is in your problem. In your first part you've already discovered how to acces a member in your array. You could simply use it:
void *get_item(Thing *c, int index)
{
return *(c->array + index); // or return c->array[index];
}
If you need the address of the pointer at index:
void **get_item_cell(Thing *c, int index)
{
return c->array + index; // or return &c->array[index];
}
In the second part, you don't dereference the pointer (for + option), or take the address of array result, since it automatically dereferences it.
EDIT: I think I now know what you want. You have a function similar to my second one above, but it is:
void *get_item_cell(Thing *c, int index)
{
return (void *)(c->array + index);
}
You want to dereference the value returned from this function, and access the object. In that case, you can only use Option 4 safely. Since you don't have the index, you cannot move to any other cell (you don't know if you are at the end of the array, or at the beginning - so no additions or subtractions). You can only fix the mistake of the above function: cast to void **
, and then dereference it: *(void **)item
. This will give you a void *
. If you want to access the object pointed from this cell, you need to cast that to the correct type as well: some_object_ptr *obj = *(void**)item
.
The fact you are working with void*
and void**
doesn't matter, pointer arithmetic still works fine, so both options you wrote are correct.
Here's an example:
struct Thing
{
void ** array;
};
struct Object
{
int i;
char c;
};
int main ()
{
struct Thing * c = malloc (sizeof(struct Thing));
c->array = malloc(10 * sizeof(void*));
struct Object * o = malloc (sizeof(struct Object));
o->i = 2; o->c = 'a';
*(c->array + 2) = o;
printf("Object: i = %d, c = %c\n", ((Object*)c->array[2])->i, ((Object*)c->array[2])->c);
free(o);
free(c->array);
free(c);
return 0;
}
Since it's void*
you can put there pointer to whatever, just don't forget it to cast to original type before using it ;)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With