Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

how to use void ** pointer correctly?

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?

like image 560
in His Steps Avatar asked Jan 27 '12 22:01

in His Steps


People also ask

How do you use void pointer?

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.

What is the use of * In pointer?

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.

What does void * mean in C?

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 void pointer explain with suitable example?

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.


3 Answers

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].

like image 142
Sylvain Defresne Avatar answered Nov 10 '22 00:11

Sylvain Defresne


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.

like image 37
vhallac Avatar answered Nov 10 '22 00:11

vhallac


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 ;)

like image 41
LihO Avatar answered Nov 09 '22 22:11

LihO