如何正确使用 void ** 指针?
Posted
技术标签:
【中文标题】如何正确使用 void ** 指针?【英文标题】:how to use void ** pointer correctly? 【发布时间】:2012-02-20 21:16:20 【问题描述】:我正在尝试使用双 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。而不是 opt.3。 ..
谁能告诉我这个?如果我做出任何无效的假设,请您纠正我吗?
【问题讨论】:
也许他需要它? 另外,选项 3 和 4 不一样,3 返回void**
,4 返回 void*
。 item
到底是什么?
"那么,我有另一个函数,它给出指向每个单元格的 (void * item),而不是 'some_object_ptr'。"
在 Kevin,抱歉我刚刚编辑了
所以假设它是一个函数,它将 poinere 返回到 some_object_ptr 指向的对象,并且它以 void * 作为指向数组单元格的参数
【参考方案1】:
万能推!
any_type x ;
void * v = * ( void * * ) & x ;
万能的拉!
void * v ;
any_type x = * ( any_type * ) & v ;
谨防丢失/获得数字
【讨论】:
void *v = *(void **) &x;
在void *v = &x;
之外还有什么用途? &x
的强制转换和取消引用什么都不做。 内存地址没有开始的类型。
@DavidC.Rankin:可以绕过这种方式 C 的限制,不允许将函数指针的值分配给 void
-pointer。
只是一个有趣的 * ( void * * ) & ,一种将任何类型转换为 void* 的棘手方法,反之亦然......这个问题没有什么严重的问题,我应该得到 -1 : )
@Fabio 这是未定义的行为,可能会使您的计算机长腿并爬走。将memcpy
用于实现定义的行为,这部分效果更好。【参考方案2】:
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]
。
【讨论】:
这取决于你想要返回什么。你想返回数组还是数组中的第一个元素。如果你有int* array;
,你会选择return array;
还是return array[0];
?这里也是一样的。
我想返回单元格中的内容,我认为它是指向另一个对象的 void 指针,返回部分位于不知道索引的不同函数中。取而代之的是 void * item,它指向包含 void 指针的单元格
别忘了检查 malloc 是否真的有效。分配后,您应该检查以下内容:if(array == NULL) return;
【参考方案3】:
您使用 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*
,所以你可以在那里放置指向任何东西的指针,只是不要忘记在使用它之前将其转换为原始类型;)
【讨论】:
您不必强制转换 malloc() 的返回值。 C 标准明确规定 void * 与 any 指针类型兼容。一些受人尊敬的 C 程序员(例如 Linus Torvalds)和 GNU 等企业反对这种转换,并称其为不好的做法,因为它降低了可读性。 另外,指针运算与整数不同。 AFAIK GCC 假定 void * 是一个字节 ptr,例如,在 32 位系统上, int 是 4 个字节,因此 (int *)ptr + 1 将给出与 (void *)ptr 不同的内存地址+ 1 会。 抱歉,即使我用 C 编写代码,我也习惯使用 Microsoft Visual Studio。编译器不允许我编写 malloc 而不强制转换它的返回值...我编辑了我的答案 @user529758 我说bigthink.com/videos/why-the-programming-language-c-is-obsolete【参考方案4】:关于指针的一个快速提示:如果你正在转换它,你可能做错了什么。
至于你的问题。我不确定你的问题是什么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];
在第二部分中,您不会取消引用指针(for + 选项),或者获取数组结果的地址,因为它会自动取消引用它。
编辑: 我想我现在知道你想要什么了。您的功能类似于我上面的第二个功能,但它是:
void *get_item_cell(Thing *c, int index)
return (void *)(c->array + index);
您想取消引用从此函数返回的值,并访问该对象。在这种情况下,您只能安全地使用选项 4。由于您没有索引,因此您无法移动到任何其他单元格(您不知道您是在数组的末尾还是在开头 - 所以没有加法或减法)。只能修正上述函数的错误:强制转换为void **
,然后取消引用:*(void **)item
。这会给你一个void *
。如果要访问从此单元格指向的对象,还需要将其转换为正确的类型:some_object_ptr *obj = *(void**)item
。
【讨论】:
哦,所以返回部分在不同的函数中,它不知道索引和 void * item 指向单元格数组 只有我对你想做的事情的理解。如果您有指针的地址(数组中的一个对象),并且想要返回数组的索引或单元格,则必须循环遍历每个单元格,检查指针对象是否与你想要的,然后返回相关信息。如果这是您想要的,我可以将其添加到我的答案中。以上是关于如何正确使用 void ** 指针?的主要内容,如果未能解决你的问题,请参考以下文章
C中结构中的指针-如何将给定的void指针的值分配给结构中的指针[关闭]