c - 从结构的动态数组中删除元素时的未定义行为
问题描述
我有一个动态分配的 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 但用于缩小)
在不改变数组结构的情况下,我所要求的是否可行?
解决方案
删除 element 时i
,将memmove
所有数据从i+1
toi
到数组末尾,然后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;
}
推荐阅读
- python - 每当我想运行烧瓶时,即使没有打开任何浏览器,也会显示以下错误
- c# - 使用 GraphQL.EntityFramework 公开多对多关系
- c# - 获取 ToolBar Button 以触发所选 TreeView 项的方法
- ipv4 - 为什么 IPv4 只有 4 个数字
- linux - 如何在 shell 脚本中并行运行多个实例以提高时间效率
- spring-data-jpa - Spring存储库注入不起作用
- java - WindowBuilder如何使用不同的按钮来显示一个计数器
- laravel - 雄辩的查询以获取所有查看次数超过 0 的帖子,但不排除在过去 24 小时内创建的帖子?
- html - 右侧的 Flex 列文本不正确
- python - 为什么 BGR 图像显示为灰度?