2012-01-27 63 views
12

我正在尝试使用双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 2012-01-27 22:27:06

+10

也许他需要它? – 2012-01-27 22:29:21

+0

另外,选项3和4不一样,3返回'void **',4返回'void *'。 '物品'究竟是什么? – Kevin 2012-01-27 22:30:58

回答

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?我有点困惑.. – 2012-01-27 22:36:03

+0

它取决于你想要返回。你想返回数组或数组中的第一个元素吗?如果你有一个'int *数组;',你会'返回数组;'或'返回数组[0];'?这在这里也是一样的。 – 2012-01-27 22:38:52

+0

我想返回单元格中的内容,我认为它是指向另一个对象的空指针,并且返回的部分处于不知道索引的不同函数中。相反,它被赋予void *项,它指向包含void指针的单元格 – 2012-01-27 22:42:18

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 *与任何*指针类型兼容。一些尊敬的C程序员,例如Linus Torvalds,以及像GNU这样的企业都反对这种铸造方式,并认为这是不好的做法,因为它降低了可读性。 – 2012-01-27 22:38:07

+0

另外,指针运算与整数不一样。 AFAIK GCC假定void *是一个字节ptr,例如在32位系统上,int是4个字节,所以(int *)ptr + 1将给出与(void *)ptr不同的存储地址+ 1会。 – 2012-01-27 22:41:35

+0

对不起,我已经习惯于使用微软Visual Studio,即使我用C编写代码。编译器不会让我写malloc而不会将其转换为返回值...我编辑了我的答案 – LihO 2012-01-27 22:45:04

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

在第二部分中,你不取消引用指针(对于+选项),或取数组结果的地址,因为它会自动解引用它。


编辑: 我想我现在知道你想要什么。你有类似我上面的第二个中的功能,但它是:

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 * item指向单元格数组 – 2012-01-27 22:38:29

+0

只有我对你想要做的事情有所了解。如果你有指针对象(数组中的一个对象),并且想要返回到数组的索引或单元格,则必须循环遍历每个单元格,检查指针是否与你想要的那个,然后返回相关信息。如果这是你想要的,我可以将其添加到我的答案中。 – vhallac 2012-01-27 22:40:54

-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'的转换和解引用什么都不做。*内存地址*没有类型开始。 – 2016-03-06 10:30:08

+0

“*'any_type' *”当然?我只会说指针类型。 – alk 2016-03-06 10:58:03

+0

@ DavidC.Rankin:可以绕过C的限制,不允许将函数指针的值赋给“空”指针。 – alk 2016-03-06 10:59:26