C-realloc中的动态数组
在我开始之前C-realloc中的动态数组,c,C,在我开始之前 我搜索了“标题类似的问题”,虽然我找到了一些非常有用的信息,但似乎无法让它对我有用 这与家庭作业有关。虽然,这不是实际的项目本身。我已经完成了,我只是把它从java移植到C,这样我就可以用我的单元测试框架进行测试了 好的,动态分配的数组。我知道如何建造它们,但不知道如何种植它们 例如,我有以下接口 void insertVertex( vertex p1, vertex out[], int *size); 此方法获取顶点并将其存储到out数组中。存储顶点后,我会增加长度计数,以
void insertVertex( vertex p1, vertex out[], int *size);
此方法获取顶点并将其存储到out数组中。存储顶点后,我会增加长度计数,以备将来调用
p1-是我要添加的顶点
out[]-是我需要存储它的数组(总是满的)
长度-当前长度
顶点定义为
typedef struct Vertex{
int x;
int y;
} Vertex;
这就是我在java中使用的
Vertex tempOut = new Vertex[size +1];
//Code to deep copy each object over
tempOut[size] = p1;
out = tempOut;
这就是我认为我可以在c中使用的
out = realloc(out, (*size + 1) * sizeof(Vertex));
out[(*size)] = p1;
但是,我一直收到一条错误消息,表示对象没有动态分配
我找到了解决这个问题的办法。。我没有使用Vertex*而是切换到Vertex**并存储指针和Vertex。然而,在切换所有内容之后,我发现我忽略了一个事实,即单元测试将为我提供一个顶点out[],所有内容都必须存储在其中
我也尝试过以下方法,但没有成功
Vertex* temp = (Vertex *)malloc((*size + 1) * sizeof(Vertex));
for(int i = 0; i < (*size); i++)
{
temp[i] = out[i];
}
out = temp;
每次一个顶点在剪切平面中,我们都将其添加到顶点数组中,并将其大小增加一
更新
谢谢大家的帮助。为了更好地解释我自己,我想出了一个简短的节目来展示我正在尝试做什么
#include <stdio.h>
#include <stdlib.h>
typedef struct Vertex {
int x, y;
} Vertex;
void addPointerToArray(Vertex v1, Vertex out[], int *size);
void addPointerToArray(Vertex v1, Vertex out[], int *size)
{
int newSize = *size;
newSize++;
out = realloc(out, newSize * sizeof(Vertex));
out[(*size)] = v1;
// Update Size
*size = newSize;
}
int main (int argc, const char * argv[])
{
// This would normally be provided by the polygon
int *size = malloc(sizeof(int)); *size = 3;
// Build and add initial vertex
Vertex *out = (Vertex *)malloc((*size) * sizeof(Vertex));
Vertex v1; v1.x = 1; v1.y =1;
Vertex v2; v2.x = 2; v2.y =2;
Vertex v3; v3.x = 3; v3.y =3;
out[0] = v1;
out[1] = v2;
out[2] = v3;
// Add vertex
// This should add the vertex to the last position of out
// Should also increase the size by 1;
Vertex vertexToAdd; vertexToAdd.x = 9; vertexToAdd.y = 9;
addPointerToArray(vertexToAdd, out, size);
for(int i =0; i < (*size); i++)
{
printf("Vertx: (%i, %i) Location: %i\n", out[i].x, out[i].y, i);
}
}
#包括
#包括
typedef结构顶点{
int x,y;
}顶点;
void addPointerToArray(顶点v1,顶点向外[],整数*大小);
void addPointerToArray(顶点v1,顶点向外[],整数*大小)
{
int newSize=*大小;
newSize++;
out=realloc(out,newSize*sizeof(顶点));
输出[(*大小)]=v1;
//更新大小
*大小=新闻大小;
}
int main(int argc,const char*argv[]
{
//这通常由多边形提供
int*size=malloc(sizeof(int));*size=3;
//构建并添加初始顶点
顶点*out=(顶点*)malloc((*大小)*大小(顶点));
顶点v1;v1.x=1;v1.y=1;
顶点v2;v2.x=2;v2.y=2;
顶点v3;v3.x=3;v3.y=3;
out[0]=v1;
out[1]=v2;
out[2]=v3;
//添加顶点
//这会将顶点添加到out的最后一个位置
//还应将尺寸增加1;
顶点顶点顶点添加;顶点添加.x=9;顶点添加.y=9;
addPointerToArray(顶点添加、输出、大小);
对于(int i=0;i<(*大小);i++)
{
printf(“顶点:(%i,%i)位置:%i\n”,out[i].x,out[i].y,i);
}
}
您的示例程序对我来说运行良好。我在Linux上使用GCC4.1.1
然而,如果您的实际程序与示例程序类似,那么它的效率相当低
例如,您的程序大量复制内存:结构复制-初始化out
,将顶点传递到addPointerToArray()
,通过realloc()复制内存
通过指针而不是复制来传递结构
如果需要大量增加列表类型的大小,最好使用链表、树或其他结构(取决于以后需要的访问类型)
如果您只需要有一个向量类型,那么实现动态大小向量的标准方法是分配一块内存(比如,16个顶点的空间),并在每次空间用完时将其大小加倍。这将限制所需realloc的数量。我有一些建议供您考虑:
1. 在使用realloc
时不要使用相同的输入和输出参数,因为在内存分配失败和前面指出的内存泄漏的情况下,它可能返回NULL
realloc
可能会返回新的内存块(感谢@Jonathan Leffler指出,我错过了这一点)。您可以将代码更改为以下内容:
Vertex * new_out = realloc(out, newSize * sizeof(Vertex));
if( NULL != new_out )
{
out = new_out;
out[(*size)] = v1;
}
else
{
//Error handling & freeing memory
}
二,。添加NULL
检查malloc
调用并在内存出现故障时处理错误。
3.呼叫free
丢失。
4.将addPointerToArray()
的返回类型从void
更改为bool
,以指示添加是否成功。在realloc
失败的情况下,您可以返回failure,比如false,否则您可以返回success,比如true。
@MatthewD已经指出了与过量拷贝等相关的其他观察结果。
乔纳森·莱夫勒(Jonathan Leffler)也没有什么好的观察结果:
希望这有帮助!一个长期的问题是,您没有从addPointerToArray()
函数返回更新的数组指针:
void addPointerToArray(Vertex v1, Vertex out[], int *size)
{
int newSize = *size;
newSize++;
out = realloc(out, newSize * sizeof(Vertex));
out[(*size)] = v1;
// Update Size
*size = newSize;
}
当您重新分配空间时,它可以移动到新位置,因此realloc()
的返回值不必与输入指针相同。这可能会在您添加到数组时没有其他内存分配的情况下起作用,因为realloc()
将在有空间的情况下扩展现有的分配,但一旦您在读取顶点时开始分配其他数据,它就会失败。有几种方法可以解决此问题:
Vertex *addPointerToArray(Vertex v1, Vertex out[], int *size)
{
int newSize = *size;
newSize++;
out = realloc(out, newSize * sizeof(Vertex));
out[(*size)] = v1;
// Update Size
*size = newSize;
return out;
}
和调用:
out = addPointerToArray(vertexToAdd, out, size);
out = addPointerToArray(vertexToAdd, &out, size);
或者,您可以传入指向数组的指针:
void addPointerToArray(Vertex v1, Vertex **out, int *size)
{
int newSize = *size;
newSize++;
*out = realloc(*out, newSize * sizeof(Vertex));
(*out)[(*size)] = v1;
// Update Size
*size = newSize;
}
和调用:
out = addPointerToArray(vertexToAdd, out, size);
out = addPointerToArray(vertexToAdd, &out, size);
这两种重写都不能解决细微的内存泄漏问题。问题是,如果用返回值覆盖传递给realloc()
的值,但realloc()
失败,则会丢失指向(仍然)分配的数组的指针-内存泄漏。使用realloc()
时,请使用以下习惯用法:
Vertex *new_space = realloc(out, newSize * sizeof(Vertex));
if (new_space != 0)
out = new_space;
else
...deal with error...but out has not been destroyed!...
请注意,使用realloc()
一次添加一个新项会导致(可能导致)二次行为。您最好分配一大块内存,例如doub
struct VertexList
{
size_t num_alloc;
size_t num_inuse;
Vertex *list;
};
void initVertexList(VertexList *array)
{
// C99: *array = (VertexList){ 0, 0, 0 };
// Verbose C99: *array = (VertexList){ .num_inuse = 0, .num_alloc = 0, .list = 0 };
array->num_inuse = 0;
array->num_alloc = 0;
array->list = 0;
}
void addPointerToArray(Vertex v1, VertexList *array)
{
if (array->num_inuse >= array->num_alloc)
{
assert(array->num_inuse == array->num_alloc);
size_t new_size = (array->num_alloc + 2) * 2;
Vertex *new_list = realloc(array->list, new_size * sizeof(Vertex));
if (new_list == 0)
...deal with out of memory condition...
array->num_alloc = new_size;
array->list = new_list;
}
array->list[array->num_inuse++] = v1;
}
int main(void)
{
VertexList array;
initVertexList(&array);
addPointerToArray((Vertex){ 1, 1 }, &array); // C99 compound literal
addPointerToArray((Vertex){ 2, 2 }, &array);
addPointerToArray((Vertex){ 3, 3 }, &array);
addPointerToArray((Vertex){ 9, 9 }, &array);
for (int i = 0; i < array->num_inuse; i++)
printf("Vertex %d: (%d, %d)\n", i, array->list[i].x, array->list[i].y, i);
return 0;
}
void addPointerToArray(Vertex v1, Vertex (*out)[], int *size)
{
int newSize = *size;
newSize++;
*out = realloc(out, newSize * sizeof(Vertex));
*out[(*size)] = v1;
// Update Size
*size = newSize;
}
addPointerToArray(vertexToAdd, &out, size);