how to use void ** pointer correctly?

家住魔仙堡 提交于 2019-11-27 10:22:26

问题


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?


回答1:


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




回答2:


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.




回答3:


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




回答4:


Almighty push!

any_type x ;
void * v = * ( void * * ) & x ;

almighty pull!

void * v ;
any_type x = * ( any_type * ) & v ;

beware of losing/gaining digits



来源:https://stackoverflow.com/questions/9040818/how-to-use-void-pointer-correctly

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!