一些指针算术遇到了相当大的麻烦。我认为我得到了概念(指针变量指向内存地址,正常变量指向数据)但我相信我的问题是语法(*, &, (*), *(),
等)。
我想要做的是构建自定义结构的动态数组(即指向堆结构的指针数组),并且我的接口提供了两个方法,“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的答案,了解原因。
答案 0 :(得分:8)
根据你的描述,你开始没错,所以当你复制东西时,你所做的一切都不会有效。
现在,您已将new_array
(可能是array
)定义为指向obj
的指针。结果如下:
在这种情况下,您有一个指向动态分配的对象数组的指针。当/如果扩展分配时,您需要自己复制所有对象。
根据你的描述:“(即指向堆结构的指针数组)”,你想要的是一个指针数组。如果要自动分配该指针数组,您的定义将如下所示:
obj *array[NUMBER];
我的猜测是,这不是你想要的。据推测,您也希望动态分配该数组。这看起来像这样:
在这种情况下,new_array
和array
都需要定义为指向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]
做你需要的。
答案 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结构的指针)。当我们添加新元素时,我们只需将现有数组扩展为一个地方,并在那个地方放置新的结构对象。不需要返回值,因为我们操作对象的指针,所有更改都在实际对象上完成,而不是在副本上完成。