代码之家  ›  专栏  ›  技术社区  ›  tehwalrus

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

  •  2
  • tehwalrus  · 技术社区  · 14 年前

    在某些指针算术方面有相当大的困难。我 认为 我得到了一些概念(指针变量指向内存地址,普通变量指向数据),但我相信我的问题在于语法( *, &, (*), *(), 等)

    我要做的是构建自定义结构的动态数组(即指向堆结构的指针数组),我的接口提供了两种方法:“ad_to_obj_array”(需要添加对象,数组可以为空)和“obj_array_dustbin”(只需要处理数组,还需要处理内容,即堆obj)。前者在下面呈现。

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

    #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个元素的地址,但是当数组的元素是指向结构的指针时,如何分配给新数组的第i个元素呢?

    编辑-请注意,上面的宏num eu elem不起作用;它将始终返回1。有关原因,请参阅下面的@merlyn morgan graham's answer。

    4 回复  |  直到 14 年前
        1
  •  8
  •   jweyrich    14 年前

    根据你的描述,你开始犯错了,所以当你开始复制东西时,你所能做的一切都很可能是有效的。

    现在,您已经将 new_array(和,大概, array )定义为指向 obj的指针。结果如下:

    在本例中,您有一个指向动态分配的对象数组的指针。当/如果展开分配时,您将需要复制所有对象本身。

    根据您的描述:“(即指向堆结构的指针数组)”,您需要的是指针数组。如果要自动分配该指针数组,则定义如下:

    obj*array[number];
    < /代码> 
    
    

    我猜那不是你想要的。大概,您也希望动态地分配这个数组。看起来像这样:

    在这种情况下,new_arrayandarraywill each need to be defined as a pointer to pointer toobj.>code>。然后,您将分配一个指针数组(即指针到任意多个objs,如您所需),并使每个点位于一个obj:。

    obj**new_array;
    
    //分配一个具有空间的指针数组以指向更多项:
    new_array=malloc(sizeof(obj*)*new_元素);
    
    //将指向当前项的指针复制到新数组:
    对于(i=0;i<current_elements;i++)
    new_array[i]=数组[i];
    < /代码> 
    
    

    这样做的好处是,在进行复制时,只复制指针,而不复制对象本身。尤其是对于大型对象,这可以节省大量的工作。权衡的是,使用一个元素要经历两个级别的间接集成,因此引用可能会变慢(尽管很少muchslower,尤其是在性能相对较高的处理器上)。

    正如@rerun已经指出的那样,无论哪种情况,您都可能希望使用realloc。特别是,此可能会扩展分配“in place”,并避免经常复制数据。当然,这是不保证的,但至少你给了它一个机会;如果你每次malloc和copy,你甚至消除了优化的可能性。

    当你开始复制东西的时候,你所能做的一切都不可能工作。

    现在,你已经定义了new_array(而且,大概,array)作为指向obj. 结果如下:

    alt text

    在本例中,您有一个指向动态分配的对象数组的指针。当/如果展开分配,则需要复制所有对象本身。

    根据您的描述:“(即指向堆结构的指针数组)”,您需要的是指针数组。如果要自动分配该指针数组,则定义如下:

    obj *array[NUMBER];
    

    我猜那不是你想要的。大概,您也希望动态地分配这个数组。就像这样:

    alt text

    在这种情况下,纽阵数组每个都需要定义为指向OBJ. 然后,您将分配一个指针数组(即指针到尽可能多的OBJs)并使每个点位于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];
    

    这样做的好处是,当你复制时,你只复制指针,而不是对象本身。尤其是对于大型对象,这可以节省大量的工作。权衡的是,使用一个元素要经过一个元素的两个间接智能层,因此引用速度可能较慢(尽管很少许多的速度较慢,尤其是在性能相对较高的处理器上)。

    正如@rerun已经指出的那样,无论哪种情况,您都可能希望使用realloc. 尤其是这个可以能够“就地”扩展分配,避免经常复制数据。当然,这并不能保证,但至少你是在给它一个机会;如果你malloc每次都复制,甚至消除了优化的可能性。

        2
  •  1
  •   rerun    14 年前

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

    • 你看过吗 realloc 作为可能的解决方案。
        3
  •  0
  •   Merlyn Morgan-Graham    14 年前

    只需将这些值分配给各个。 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 函数的参数。

        4
  •  0
  •   Mujo Osmanovic    14 年前

    在您的代码中,数组元素不是结构上的指针,而是结构对象。这个数组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结构的指针上)。当我们添加新元素时,只需将现有数组扩展到一个位置,然后在该位置上放置新的结构对象。不需要返回值,因为我们对对象的指针进行操作,并且所有更改都是在实际对象上完成的,而不是在它们的副本上。