2012-01-27 3 views
12

Я пытаюсь использовать указатель double void, но я немного смущен об использовании. У меня есть struct, который содержит массив void **.Как правильно использовать указатель 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. и не opt.3. ..

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

+1

Почему вы работаете с '' недействительным *? Еще хуже, 'void **'? – Kevin

+10

Может, ему это нужно? –

+0

Кроме того, опции 3 и 4 не совпадают, 3 возвращает 'void **' и 4 возвращает 'void *'. А что такое 'item'? – Kevin

ответ

18

A void ** - это просто указатель на указатель на память с неопределенным типом. Вы можете только разыменовать его один раз (так как вы не можете разыскивать 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].

+0

, тогда, когда я вернусь, я должен использовать opt 3 или выбрать 4? Я немного смущен. –

+0

Это зависит от того, что вы хотите вернуть. Вы хотите вернуть первый элемент в массив или массив. Если бы у вас был массив 'int *;', вы бы делали 'return array;' или 'return array [0];'? Здесь будет одно и то же. –

+0

Я хочу вернуть то, что находится в ячейке, которая, как мне кажется, является указателем void, указывающим на другой объект, и возвращающая часть находится в другой функции, которая не знает индекса. Вместо этого ему присваивается элемент void *, который указывает на ячейку, содержащую указатель void –

1

Дело в том, что вы работаете с 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* вы можете поставить там указатель на то, что, только не забудьте его приведение к исходному типу перед его использованием;)

+2

. Вам не нужно указывать возвращаемое значение malloc(). C явно указывает, что void * совместим с * любым типом указателя *. Несколько уважительных программистов на С, например, Линус Торвальдс, и такие предприятия, как GNU, возражают против этого литья и называют его плохой практикой, поскольку он снижает читаемость. –

+0

Кроме того, арифметика указателя не совпадает с целыми числами. AFAIK GCC предполагает, что void * является байтом ptr, и, например, в 32-битной системе int составляет 4 байта, поэтому (int *) ptr + 1 даст другой адрес памяти от адреса (void *) ptr + 1 будет. –

+0

Извините, я привык работать с Microsoft Visual Studio, даже когда я код в C. Компилятор не позволит мне писать malloc без кастования его возвращаемого значения ... Я отредактировал свой ответ – LihO

2

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

Что касается вашего вопроса. Я не уверен, что в вашей проблеме находится 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.

+0

ой, поэтому возвращающаяся часть в другой функции, что он не знает, что индекс и элемент void * указывают на массив ячейки –

+0

Только мое понимание того, что вы хотите сделать. Если у вас есть адрес pointee (объект в массиве) и хотите вернуться к индексу или ячейке массива, вам нужно будет пропустить каждую ячейку, проверить, является ли pointee тем же объектом, что и тот, который вы хотите, затем верните соответствующую информацию, когда она есть. Если это то, что вы хотите, я могу добавить это к моему ответу. – vhallac

-1

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

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

всесоразродный тяга!

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

остерегайтесь проигрыша/набирает цифры

+0

Какая цель 'void * v = * (void **) & x;' служить за пределами 'void * v = & x;'? Листинг и разыменование '& x' ничего не делает.A * адрес памяти * не имеет типа для начала. –

+0

"*' any_type' * "уверен? Я бы сказал только типы указателей. – alk

+0

@ DavidC.Rankin: Можно было обмануть это ограничение C, не позволяющее присваивать значение функции-указателю указателю 'void'. – alk

Смежные вопросы