C-realloc中的动态数组

C-realloc中的动态数组,c,C,在我开始之前 我搜索了“标题类似的问题”,虽然我找到了一些非常有用的信息,但似乎无法让它对我有用 这与家庭作业有关。虽然,这不是实际的项目本身。我已经完成了,我只是把它从java移植到C,这样我就可以用我的单元测试框架进行测试了 好的,动态分配的数组。我知道如何建造它们,但不知道如何种植它们 例如,我有以下接口 void insertVertex( vertex p1, vertex out[], int *size); 此方法获取顶点并将其存储到out数组中。存储顶点后,我会增加长度计数,以

在我开始之前

  • 我搜索了“标题类似的问题”,虽然我找到了一些非常有用的信息,但似乎无法让它对我有用

  • 这与家庭作业有关。虽然,这不是实际的项目本身。我已经完成了,我只是把它从java移植到C,这样我就可以用我的单元测试框架进行测试了

  • 好的,动态分配的数组。我知道如何建造它们,但不知道如何种植它们

    例如,我有以下接口

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