假设我们有以下内容:
struct container
{
void** array;
function_pointer_typedef fp_t;
int length;
};
void* get_data(const void* item){
return item; //unsure. also produced warning.
}
void delete_element(container* c, void* item)
{
/* 1. delete the array element pointed at by "item"
2. reposition remaining array elements
*/
}
void* find_item(container* c, void* item)
{
int i;
for(i = 0; i < c->length; i++){
if(c->fp_t(item, c->array[i]) == 0){
return c->array[i];
}
}
}
进一步假设如果比较的两个事物彼此相等,则fp_t
返回0(函数指针的其他返回值现在不重要)。为了使事情变得更容易,我还假设find_item
的第二个参数中的项将始终位于数组中。
我想我无法理解void**
的工作原理。在get_data
函数中,我们作为参数提供了一个指向数组单元的void*
指针,该数组单元是指向某个数据对象的void*
指针。那么我们如何获得该数据对象呢?我知道用户必须将其强制转换为有用,但我仍然不知道我应该返回什么。我也知道你不能取消引用void*
,所以做return *item;
之类的事情(在我看来似乎就是我们想要做的事情 - 只需要void*
指针数组单元格),编译警告/错误。
我猜delete_element
给我带来了同样的困惑。我们提供了一个void*
指针item
,它指向指向实际数据的void*
指针数组单元格。所以我们需要以某种方式取消引用该项目,以便我们可以删除数组单元格。
有什么想法吗?
答案 0 :(得分:4)
void *
和void **
很容易让人感到困惑。 void *
是任何指向对象的指针的通用容器。任何对象指针都可以转换为void *
并再次返回原始值。 (请注意,void *
无法保证能够保存函数指针)。这些函数正在处理的对象是什么类型并不重要。他们正在存储和检索对象(恰好有类型void *
)。
struct container { void** array; function_pointer_typedef fp_t; int length; };
您的array
成员只是指向对象数组的指针。
void* get_data(const void* item){ return item; //unsure. also produced warning. }
我不知道这个函数应该返回什么,但是你从这里得到警告的原因是你删除 const
限定词。您正在将(指向)只读对象转换为可写对象。在C中不允许这样做。为了避免这种情况,你必须抛弃const
限定词。 (return (void *)item;
)。
如果item
确实是指向数组单元格的指针(转换为void *
),则必须先将其强制转换为原始类型,然后才能取消引用它物体。 (return *(void **)item;
)。但我真的不知道这个函数应该做什么。问你的老师。
void delete_element(container* c, void* item) { /* 1. delete the array element pointed at by "item" 2. reposition remaining array elements */ }
您应该浏览array
个对象,直到找到一个比较等于item
的对象,通过移动以下对象来填充该插槽,从阵列中删除它,并且然后调整length
。您必须取消引用的唯一内容是array
指针,而不是存储的对象。
void* find_item(container* c, void* item) { int i; for(i = 0; i < c->length; i++){ if(c->fp_t(item, c->array[i]) == 0){ return c->array[i]; } } }
如果找不到NULL
,此函数可能应该返回item
。在关闭大括号的函数之前只需return NULL;
。
答案 1 :(得分:1)
int*
是指向int的指针。给定int* x
指向以下每个有效内存,*x
和x[0]
引用内存x指向; x+1
指向x,sizeof(int)
或*(x+1)
引用该位置后的位置x[1]
个字节; x+2
指向x之后的位置sizeof(int)*2
个字节,依此类推。
void
不是对象的类型;所以void*
是指向内存的指针,但不是指向某事物的指针。鉴于void* y
,*y
,y[0]
,y+1
,*(y+1)
等等,根本没有意义。
void*
是一种对象 - 它是指向内存的指针。给定void** z
指向以下每个有效内存,*z
和z[0]
引用内存z指向; z+1
指向z之后的位置sizeof(void*)
个字节,依此类推。
如果有帮助,假装&#34;无效*&#34;是拼写&#34;指针&#34; (就像你使用的是typedef void* pointer
),并且与#34; int&#34;相同。所以,如果我有int q和指针p,我就不能*q
,因为q不是指向某个东西的指针,我也不能*p
因为p不是&#39; ta指向某事的指针(严格来说这是真的)。但是你可以将int分配给其他int,并将指针指定给其他指针;您可以为int*
分配内存,就像为pointer*
分配内存一样,并且可以像使用int *一样取消引用类型为对象*的对象。
这足以回答你的问题,但做你想做的事情一般取决于一些实施细节。如果您要将内存存储为void*
的数组{aka,void**
或#34;指针*&#39; s&#34; ;),你需要要求你的用户传递一个create函数,或者只是自己分配每个元素的内存(或者只是自己处理它,如果你想让它们指向非堆对象;它实际上取决于你想做什么;如果你让他们有指向非堆对象的项目,你可能不想删除它)。您的代码可以轻松删除项目。如何从这个集合中删除项目是另一个实现细节 - 取决于你想要做什么。