首页 > 解决方案 > 从结构的动态数组中删除元素时的未定义行为

问题描述

我有一个动态分配的 n 大小的结构数组,并且数组的每个位置也是一个数组,每个位置(数组的数组)具有不同的大小。

我创建了一个函数来删除给定的数组 [索引],但我面临一些未定义的行为,例如:如果数组的大小为 3,如果我删除数组 [0],我无法访问数组 [1]。其他索引组合也会发生这种情况。它完美工作的唯一方法是当我从头到尾删除时。

这是我的代码:结构:

typedef struct point{

    char id[5];
    char type[5];
    char color[10];
    int x;
    int y;
} Point;


typedef struct {

    char lineID[5];
    int nPoints;
    Point *pt;
}railData;

typedef struct railway {
    railData data;
}railway;

数组是这样创建的:

headRail = (railway**)calloc(lineNum,sizeof(railway*));

每个 Rail:headRail[i] = (railway*)calloc(pointsNum,sizeof(railway));

这些是删除轨道的函数:

railway **delRail(railway **headRail, int j)
{
    int nPts = 0;

    if (!headRail)
    {
        puts(ERRORS[NULLPOINTER]);
        return NULL;
    }

    // Number of rail points on jth rail

    nPts = headRail[j]->data.nPoints;

    // Free each rail point from jth rail
    for (int i = 0; i < nPts; ++i)
    {
        free(headRail[j][i].data.pt);
    }

    // Free allocated memory for jth rail 
    free(headRail[j]);

    return headRail;
}

这就是我调用前一个函数的地方:

railway **removeRail(railway **headRail)
{
    char userID[20];
    int index = 0;

    // Quit if no rails 
    if (!headRail)
    {
        backToMenu("No rails available!");
        return NULL;
    }

    // Get user input
    getString("\nRail ID: ",userID,MINLEN,MAXLEN); // MINLEN = 2 MAXLEN = 4



    // get index of the asked rail
    getRailIndex(headRail,userID,&index);

    if (index != NOTFOUND)
    {
        headRail = delRail(headRail, index);
        // Update number of rails in the array (global var)
        NUMOFRAILS--;

        backToMenu("Rail deleted!\n");
    }
    else
        backToMenu("Rail not found!");

    return headRail;
}

所以我的问题是如何修改我的代码,以便当位置 i 被消除时,所有其他索引都向左移动,最后一个为空的位置被丢弃(类似于 realloc 但用于缩小)

在不改变数组结构的情况下,我所要求的是否可行?

标签: carraysstructdynamic-memory-allocation

解决方案


删除 element 时i,将memmove所有数据从i+1toi到数组末尾,然后realloc大小减 1。

请注意,C 中的数组不会以任何方式跟踪它们的大小,因此您需要通过外部方式传递大小。

您的数据抽象很奇怪。我希望它headRail[j][0].data.nPoints用于存储结构内的点数headRail[j][0].data,但您将 headRails 的计数存储在 j 行headRail[j][<this count>]中。我建议重写抽象,有一个“对象”用于铁路,另一个用于处理具有各个方向动态大小的铁路二维数组。

喜欢:

railway **delRail(railway **headRail, int j)
{
    ...

    // this is strange, it's equal to
    // nPts = headRail[j][0].data.nPoints;
    // dunno if you mean that, 
    // or if [j][0].data.nPoints refers to the size of 
    // headRail[j][0].data.pt or to the size of the whole array
    size_t nPts = headRail[j]->data.nPoints;
    for (size_t i = 0; i < nPts; ++i) {
        free(headRail[j][i].data.pt);
    }
    free(headRail[j]);

    // note that arrays in C does not know how many elements are there in the array
    // so you typically pass that along the arguments, like
    // railway **delRail(railway **headRail, size_t railcount, int j);
    size_t headRailCount = lineNum; // some external knowledge of the size
    memmove(&headRail[j], &headRail[j + 1], (headRailCount - j - 1) * sizeof(*headRail));
    void *pnt = realloc(headRail, (headRailCount - 1) * sizeof(*headRail));
    if (pnt == NULL) return NULL; // that would be strange
    headRail = pnt; // note that the previous headRail is no longer valid
    --lineNum; // decrement that object where you store the size of the array

    return headRail;
}

一些封装和更多结构而不是二维数组呢?二维数组对于 C 来说确实有点痛苦,那么:

typedef struct {
    // stores a single row of rail datas
    struct railData_row_s {
        // stores a pointer to an array of rail datas
        railData *data;
        // stores the count of how many datas of rails are stored here
        size_t datacnt;
    // stores a pointer to an array of rows of rail datas
    } *raildatas;
    // stores the size of the pointer of rows of rail datas
    size_t raildatascnt;
} railway;

malloc 的数量将保持不变,但考虑数据会变得更简单。每个指向数据数组的指针都有自己的大小跟踪变量。分配可能如下所示:

railway *rail_new(size_t lineNum, size_t pointsNum) {
   railway *r = calloc(1, sizeof(*r));
   if (!r) { return NULL; }

   // allocate the memory for rows of raildata
   r->raildatascnt = lineNum;
   r->raildatas = calloc(r->raildatascnt, sizeof(*r->raildatas));
   if (!t->raildatas) { /* error hadnling */ free(r); abort(); }

   // for each row of raildata
   for (size_t i = 0; i < r->raildatascnt; ++i) {
        struct railData_row_s * const row = &r->raildatas[i];

        // allocate the memory for the column of raildata
        // hah, looks similar to the above?
        row->datacnt = pointsNum;
        row->data = calloc(row->datacnt, sizeof(*row->data));
        if (!row->data) { /* error ahdnling */ abort(); }

   }

   return r;
}

推荐阅读