C - realloc中的动态数组

Fre*_*ddy 7 c

在我开始之前

  1. 我搜索了"类似标题的问题",虽然我发现了一些非常有用的信息,但我似乎无法让它为我工作.

  2. 这与家庭作业有关.虽然,不是实际的项目本身.我已经完成了我只是将它从java移植到C所以我可以测试我的教授单元测试框架.

好的,动态分配的数组.我知道如何构建它们,但不知道如何构建它们.

例如我有以下界面..

void insertVertex( vertex p1, vertex out[], int *size);
Run Code Online (Sandbox Code Playgroud)

此方法采用顶点并将其存储到out数组中.存储顶点后,我增加了未来调用的长度计数.

p1 - 是我要添加的顶点.

out [] - 是我需要存储的数组(总是满的)

length - 当前长度

顶点定义为..

typedef struct Vertex{
int x;
int y;
} Vertex;
Run Code Online (Sandbox Code Playgroud)

这就是我在java中使用的..

Vertex tempOut = new Vertex[size +1];
//Code to deep copy each object over
tempOut[size] = p1;
out = tempOut;
Run Code Online (Sandbox Code Playgroud)

这是我认为我可以用于...

out = realloc(out, (*size + 1) * sizeof(Vertex));
out[(*size)] = p1;
Run Code Online (Sandbox Code Playgroud)

但是,我继续收到一条错误消息,指出该对象未动态分配.

我发现了一个可以解决这个问题的解决方案.我没有使用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;
Run Code Online (Sandbox Code Playgroud)

但是,无论我做什么,当我测试这两个后返回的数组都没有改变.

任何帮助表示赞赏.

更新 - 请求的信息

out - 被定义为Vertex数组(Vertex out [])

它最初是用我的多边形中的顶点数构建的.例如.

out =(Vertex*)malloc(vertexInPolygon*sizeof(Vertex))

其中vertexInPolygon是多边形中顶点数的整数.

长度是应该是大小的拼写错误.

Size是一个整数指针

int *size = 0;
Run Code Online (Sandbox Code Playgroud)

每次顶点在剪切平面中时,我们将它添加到顶点数组并将大小增加一.

更新

谢谢大家的帮助.为了更好地解释自己,我想出了一个简短的程序来展示我正在尝试做的事情.

#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);
    }

}
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 5

一个长期的问题是您没有从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;
}
Run Code Online (Sandbox Code Playgroud)

重新分配空间时,它可以移动到新位置,因此from的返回值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;
}
Run Code Online (Sandbox Code Playgroud)

和调用:

out = addPointerToArray(vertexToAdd, out, size);
Run Code Online (Sandbox Code Playgroud)

另外,您可以传递一个指向数组的指针:

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;
}
Run Code Online (Sandbox Code Playgroud)

和调用:

out = addPointerToArray(vertexToAdd, &out, size);
Run Code Online (Sandbox Code Playgroud)

这些重写都不能解决微妙的内存泄漏。问题是,如果您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!...
Run Code Online (Sandbox Code Playgroud)

请注意,realloc()一次添加一个新项目会导致(可能导致)二次行为。您最好分配一大块内存-例如,将分配的空间加倍:

int newSize = *size * 2;
Run Code Online (Sandbox Code Playgroud)

如果您担心过度分配,请在读取循环结束时使用realloc(),将分配的空间缩小到数组的确切大小。但是,要做更多的簿记工作。您需要输入以下值:分配给数组的顶点数,以及实际使用的顶点数。

最后,至少现在至少要注意,您确实应该保持一致,并使用addPointerToArray()前三个条目添加到数组中。我可能会使用类似于以下(未经测试)的代码:

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;
}
Run Code Online (Sandbox Code Playgroud)

如果传入的指针为null realloc(),则使用会违反直觉的属性malloc()。您可以改为进行检查,array->list == 0然后使用malloc()then和realloc()其他方式。

您可能会注意到,这种结构也简化了调用代码。您不再需要处理int *size;主程序中的单独文件(及其内存分配);尺寸有效地捆绑为VertexList结构num_inuse。现在,主程序可能会启动:

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;
}
Run Code Online (Sandbox Code Playgroud)

(碰巧的是,此序列仅会调用一次内存分配,因为新大小(old_size + 2) * 2是在第一次为数组分配4个元素时。通过添加新点或将公式细化为或,很容易进行重新分配(old_size + 1) * 2。 ..

如果您打算从内存分配失败中恢复(而不是从发生这种情况时退出),那么您应该进行修改addPointerToArray()以返回一个状态(成功,但不成功)。

此外,函数名可能应该addPointToArray()或者addVertexToArray()甚至addVertexToList()