从void **数组返回数据

时间:2014-08-24 23:10:26

标签: c arrays pointers

假设我们有以下内容:

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*指针数组单元格。所以我们需要以某种方式取消引用该项目,以便我们可以删除数组单元格。

有什么想法吗?

2 个答案:

答案 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指向以下每个有效内存,*xx[0]引用内存x指向; x+1指向x,sizeof(int)*(x+1)引用该位置后的位置x[1]个字节; x+2指向x之后的位置sizeof(int)*2个字节,依此类推。

void不是对象的类型;所以void*是指向内存的指针,但不是指向某事物的指针。鉴于void* y*yy[0]y+1*(y+1)等等,根本没有意义。

void* 一种对象 - 它是指向内存的指针。给定void** z指向以下每个有效内存,*zz[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函数,或者只是自己分配每个元素的内存(或者只是自己处理它,如果你想让它们指向非堆对象;它实际上取决于你想做什么;如果你让他们有指向非堆对象的项目,你可能不想删除它)。您的代码可以轻松删除项目。如何从这个集合中删除项目是另一个实现细节 - 取决于你想要做什么。