как правильно использовать указатель void **? - PullRequest
17 голосов
/ 28 января 2012

Я пытаюсь использовать двойной указатель void, но я немного запутался в использовании. У меня есть struct, который содержит массив void **.

struct Thing{
    void ** array;
};

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

Итак, если я хочу назначить отдельный объект каждому указателю и попытаться получить значение

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

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

тогда у меня есть другая функция, которая дает (void *) item, которая указывает на каждую ячейку, а не some_object_ptr.

Если я хочу получить значение, на которое указывает some_object_ptr,
я должен сделать

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

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

странная вещь в том, что когда я использовал массив метод индексирования массива, я не мог использовать вариант 4, только вариант 3; и когда я использовал *(c->array + index), я мог использовать только opt.4. и не опт.3. ..

Может кто-нибудь сказать мне об этом? Если я делаю какие-либо неверные предположения, то не могли бы вы исправить меня?

Ответы [ 4 ]

23 голосов
/ 28 января 2012

A void ** - это просто указатель на указатель на память с неопределенным типом.Вы можете разыменовать его только один раз (поскольку вы не можете разыменовать a void *).Однако, кроме этого, он в основном похож на любой другой тип указателя.Если это поможет вам, подумайте об этом так же, как и с int *.

Итак, в вашей конкретной ситуации мы имеем:

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 являетсяуказатель на весь массив, тогда как *array - указатель на первый элемент, поскольку он эквивалентен array[0].

2 голосов
/ 28 января 2012

Один быстрый совет о указателях: если вы разыгрываете его, вы, вероятно, делаете что-то не так.

Что касается вашего вопроса. Я не уверен, что item в вашей проблеме. В первой части вы уже узнали, как получить доступ к члену в вашем массиве. Вы можете просто использовать это:

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

Если вам нужен адрес указателя в индексе:

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

Во второй части вы не разыменовываете указатель (для опции +) или не берете адрес результата массива, поскольку он автоматически разыменовывает его.


EDIT: Я думаю, что теперь я знаю, что вы хотите. У вас есть функция, аналогичная моей второй выше, но это:

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

Вы хотите разыменовать значение, возвращаемое этой функцией, и получить доступ к объекту. В этом случае вы можете безопасно использовать только вариант 4. Поскольку у вас нет индекса, вы не можете перейти в любую другую ячейку (вы не знаете, находитесь ли вы в конце массива или в начале - так что никаких сложений или вычитаний). Вы можете только исправить ошибку вышеупомянутой функции: приведите к void **, а затем разыменуйте ее: *(void **)item. Это даст вам void *. Если вы хотите получить доступ к объекту, указанному в этой ячейке, вам также необходимо привести его к правильному типу: some_object_ptr *obj = *(void**)item.

1 голос
/ 28 января 2012

Тот факт, что вы работаете с void* и void**, не имеет значения, арифметика с указателями по-прежнему работает нормально, поэтому оба написанных вами варианта верны.

Вот пример:

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

Так как это void*, вы можете поместить туда указатель на что угодно, только не забудьте его привести к исходному типу перед его использованием;)

0 голосов
/ 06 марта 2016

Всемогущий толчок!

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

Всемогущий удар!

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

Остерегайтесь потери / получения цифр

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...