web-dev-qa-db-fra.com

comment utiliser correctement le pointeur void **?

J'essaie d'utiliser un double pointeur void mais je suis un peu confus quant à l'utilisation. J'ai un struct qui contient un tableau void **.

struct Thing{
    void ** array;
};

struct Thing * c = malloc (sizeof(struct Thing));
c->array = malloc( 10 * sizeof(void *) );

Donc, si je veux attribuer un objet différent à chaque pointeur et essayer de récupérer la valeur

 // Option 1
 *(c->array + index) = (void *) some_object_ptr;

 // Option 2
 c->array[index] = (void *) some_object_ptr;

puis, j'ai une autre fonction qui donne (void *) item qui pointe vers chaque cellule, pas le some_object_ptr.

Si je veux récupérer la valeur indiquée par some_object_ptr,
devrais-je

 function return type is 'void *' and takes argument 'void *'
 // Option 3 
 return (void**) item

 // Option 4
 return *((void**)item)?

la chose étrange est que lorsque j'utilisais tableau la méthode indice de tableau, je ne pouvais pas utiliser l'option 4, seulement l'option 3; et quand j'ai utilisé *(c->array + index) je ne pouvais utiliser que opt.4. et non opt.3. ..

Quelqu'un peut-il m'en parler? Si je fais des hypothèses invalides, pourriez-vous me corriger?

22
in His Steps

UNE void ** n'est qu'un pointeur vers un pointeur vers la mémoire avec un type non spécifié. Vous ne pouvez le déréférencer qu'une seule fois (puisque vous ne pouvez pas déréférencer un void *). Cependant, à part cela, c'est essentiellement comme tout autre type de pointeur. Si cela vous aide, pensez-y comme vous le feriez avec int *.

Donc, dans votre situation particulière, nous avons:

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;

array est un pointeur sur tout le tableau, tandis que *array est un pointeur sur le premier élément, car il est équivalent à array[0].

28
Sylvain Defresne

Un petit conseil sur les pointeurs: si vous le lancez, vous faites probablement quelque chose de mal.

Quant à votre question. Je ne sais pas ce que item est dans votre problème. Dans votre première partie, vous avez déjà découvert comment accéder à un membre de votre tableau. Vous pouvez simplement l'utiliser:

void *get_item(Thing *c, int index)
{
    return *(c->array + index); // or return c->array[index];
}

Si vous avez besoin de l'adresse du pointeur à l'index:

void **get_item_cell(Thing *c, int index)
{
    return c->array + index; // or return &c->array[index];
}

Dans la deuxième partie, vous ne déréférencez pas le pointeur (pour l'option +), ni ne prenez l'adresse du résultat du tableau, car il le déréférence automatiquement.


EDIT: Je pense que je sais maintenant ce que vous voulez. Vous avez une fonction similaire à ma deuxième ci-dessus, mais c'est:

void *get_item_cell(Thing *c, int index)
{
    return (void *)(c->array + index);
}

Vous souhaitez déréférencer la valeur renvoyée par cette fonction et accéder à l'objet. Dans ce cas, vous ne pouvez utiliser l'option 4 qu'en toute sécurité. Puisque vous n'avez pas l'index, vous ne pouvez pas passer à une autre cellule (vous ne savez pas si vous êtes à la fin du tableau, ou au début - donc pas d'additions ou de soustractions). Vous pouvez uniquement corriger l'erreur de la fonction ci-dessus: transtyper en void **, Puis la déréférencer: *(void **)item. Cela vous donnera un void *. Si vous souhaitez accéder à l'objet pointé à partir de cette cellule, vous devez également le caster dans le type correct: some_object_ptr *obj = *(void**)item.

2
vhallac

Le fait que vous travaillez avec void* et void** n'a pas d'importance, l'arithmétique du pointeur fonctionne toujours bien, donc les deux options que vous avez écrites sont correctes.

Voici un exemple:

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

Depuis ses void* vous pouvez y mettre un pointeur sur n'importe quoi, n'oubliez pas de le transtyper en type original avant de l'utiliser;)

1
LihO