在C中为结构指针数组成员分配地址

时间:2010-10-16 21:24:22

标签: c arrays pointers variable-assignment struct

一些指针算术遇到了相当大的麻烦。我认为我得到了概念(指针变量指向内存地址,正常变量指向数据)但我相信我的问题是语法(*, &, (*), *(),等)。

我想要做的是构建自定义结构的动态数组(即指向堆结构的指针数组),并且我的接口提供了两个方法,“ad_to_obj_array”(它接受要添加的对象和可以为null的数组) for empty)和“obj_array_dustbin”(它只需要处理数组,同时处理内容,堆objs)。前者在下面呈现。

对象的细节并不重要(并且结构已被重命名)但我对下面的一般问题的解决方案如下,如果您能发现错误,我将不胜感激。编译器抱怨无效的左值,我尝试将RHS上的指针中的地址分配给堆结构指针数组中的指针值:

#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))

obj* add_to_obj_array(obj* new_obj, obj* array)
{
  int number_of_elements = 0;
  if (array != NULL)
  {
    number_of_elements = NUM_ELEM(array);
  }

  obj* new_array = NULL;

  /* note: I am expecting sizeof(new_obj) to return the size of an obj* 
     to go into the array of pointers. */
  if ( NULL ==
       (new_array = (obj*)malloc((number_of_elements + 1)* sizeof(new_obj))) )
  {
    /* memory request refused :( */
    return NULL;
  }

  /* copy the old array pointers into the new array's pointer slots: */
  int i;
  for (i = 0; i < number_of_elements; i++)
  {
    &(new_array[i]) = &(array[i]);
  }

  /* add the new item to the end (assign pointer value directly): */
  new_array[number_of_elements] = new_obj;

  if (number_of_elements > 0)
  {
    free(&array);
  }

  return new_array;
}

现在,我尝试了以下对违规行的排列:

  &(new_array[i]) = &(array[i]);
  *(new_array[i]) = &(array[i]);
  new_array[i] = &(array[i]);

并且都会给出一种或另一种编译器错误。我很确定右侧是旧数组的第i个元素的地址,但是当数组的元素是指向结构的指针时,如何分配给new的第i个元素?

编辑 - 请注意,上面的宏NUM_ELEM不起作用;它将永远返回1.请参阅@Merlyn Morgan-Graham的答案,了解原因。

4 个答案:

答案 0 :(得分:8)

根据你的描述,你开始没错,所以当你复制东西时,你所做的一切都不会有效。

现在,您已将new_array(可能是array)定义为指向obj的指针。结果如下:

alt text

在这种情况下,您有一个指向动态分配的对象数组的指针。当/如果扩展分配时,您需要自己复制所有对象。

根据你的描述:“(即指向堆结构的指针数组)”,你想要的是一个指针数组。如果要自动分配该指针数组,您的定义将如下所示:

obj *array[NUMBER];

我的猜测是,这不是你想要的。据推测,您也希望动态分配该数组。这看起来像这样:

alt text

在这种情况下,new_arrayarray都需要定义为指向obj指针的指针。然后,您可以根据需要分配一个指针数组(即指向尽可能多的obj个指针)并将每个点指向obj

obj **new_array;

// allocate an array of pointers with space to point at more items:    
new_array = malloc(sizeof(obj *) * new_elements);

// copy the pointers to the current items to the new array:
for (i=0; i<current_elements; i++)
    new_array[i] = array[i];

这样做的好处是,当您进行复制时,只复制指针,而不是复制对象本身。特别是对于大型物体,这可以节省大量的精力。权衡是使用一个元素经过两个级别的间接intead为1,因此引用可能会更慢(尽管很少很多更慢,特别是在相对高性能的处理器上)。

正如@rerun已经指出的那样,在任何一种情况下你都可能想要使用realloc。特别是,此可能能够“就地”扩展分配,并避免经常复制数据。当然,这不是保证,但至少你给它一个机会;如果你malloc并且每次都复制,你甚至可以消除优化的可能性。

答案 1 :(得分:1)

你有两个阵列没有new_array[i] = array[i]做你需要的。

  • 您是否将realloc视为可能的解决方案。

答案 2 :(得分:0)

只需分配值即可。 new_array[i] = array[i]

您可能遇到的问题是,obj*实际上是指针数组obj本身必须是指针类型:

typedef struct
{
  int value1;
} obj_pool;

typedef obj_pool* obj;

int main(int argc, char* argv[])
{
  obj_pool pool1;
  pool1.value1 = 5;
  obj array[] = { &pool1 };
  array[0]->value1 = 16;
  return 0;
}

进行此编译后,您将遇到的另一个问题是sizeof(array) == sizeof(obj*)NUM_ELEM(array)始终返回相同的值。这意味着您必须将size_t array_size参数传递给您的函数。

答案 3 :(得分:0)

在数组的代码元素中不是结构上的指针,它们是结构对象。这个数组obj **数组的元素是结构obj的指针。

#define NUM_ELEM(x) (sizeof (x) / sizeof (*(x)))

void add_to_obj_array(obj* new_obj, obj** array)
{
  int number_of_elements = 0;
  if (array != NULL)
  {
    number_of_elements = NUM_ELEM(array);
  }

  // expand array with one more item
  array = (obj**)realloc(array, (number_of_elements + 1) * sizeof(new_obj));

  if (array == NULL )
  {
    /* memory request refused :( */
    return;
  }

  // Put new item at the last place on the array
  array[number_of_elements] = new_obj;
}

所以这里我们使用了矩阵(指向obj结构的指针)。当我们添加新元素时,我们只需将现有数组扩展为一个地方,并在那个地方放置新的结构对象。不需要返回值,因为我们操作对象的指针,所有更改都在实际对象上完成,而不是在副本上完成。