[英]Dynamic array of structs in c (malloc, realloc)
我正在尝试创建一个结构元素数组,并在需要新元素时重新分配。 数组必须是一个指针,因为我想从函数中返回它。
我有以下代码:
#include <stdio.h>
#include <stdlib.h>
struct rle_element {
int length;
char character;
};
void get_rle() {
struct rle_element *rle = malloc(sizeof(struct rle_element*));
struct rle_element **rle_pointer = &rle;
rle = realloc(rle, sizeof(rle) + sizeof(struct rle_element*));
(*rle_pointer)->length = 10;
printf("%d\n", (*rle_pointer)->length);
rle_pointer = &rle+1;
(*rle_pointer)->length = 20;
printf("%d\n", (*rle_pointer)->length);
}
int main() {
get_rle();
return EXIT_SUCCESS;
}
但是这段代码并没有真正起作用。 我认为重新分配是不对的。
现在我有以下代码可以正常工作。 但我也可以使用 rle[2] 或 rle[3] 而无需分配。 我认为我的程序只为两个项目分配空间。
#include <stdio.h>
#include <stdlib.h>
struct rle_element {
int length;
char character;
};
void get_rle() {
struct rle_element *rle = malloc(sizeof(struct rle_element));
struct rle_element **rle_pointer = &rle;
rle = realloc(rle, sizeof(rle) + sizeof(struct rle_element));
rle[0].length = 10;
printf("%d\n", rle[0].length);
rle[1].length = 20;
printf("%d\n", rle[1].length);
}
int main() {
get_rle();
return EXIT_SUCCESS;
}
您的代码存在各种问题(在评论和其他答案中指出)。 您缺少的一件重要事情是您没有跟踪分配区域的大小。 sizeof()
在编译时进行评估(除非您使用的是 C99 VLA)。 所以做sizeof(rle)
不会评估你的数组正在使用的字节数。 您必须将其单独存储。 这是一个使用struct rle_parent
结构跟踪大小的工作实现,其中包含注释以帮助您理解:
#include <stdio.h>
#include <stdlib.h>
struct rle_element {
int length;
char character;
};
struct rle_parent {
struct rle_element *arr;
size_t count;
};
static void get_rle(struct rle_parent *p, int length, char character) {
struct rle_element *e;
/* Allocate enough space for the current number of elements plus 1 */
e = realloc(p->arr, (p->count + 1) * sizeof(struct rle_element));
if (!e) {
/* TODO: (Re)allocation failed, we should handle this */
return;
}
/* Update the parent to point to the reallocated array */
p->arr = e;
/* Update our newly added element */
e = &p->arr[p->count];
e->length = length;
e->character = character;
/* Bump the count so we know how many we have */
p->count++;
}
int main() {
struct rle_parent p;
size_t i;
/* Initialize */
p.arr = NULL;
p.count = 0;
get_rle(&p, 10, 'a');
get_rle(&p, 20, 'b');
get_rle(&p, 30, 'c');
/* Print out our array */
for (i = 0; i < p.count; i++) {
struct rle_element *e = &p.arr[i];
printf("%d -- %c\n", e->length, e->character);
}
return 0;
}
或者,如果您不想维护计数,您可以向struct rle_element
添加另一个字段,指示它是数组中的最后一个元素。 每次添加新元素时都必须更新它(在“当前”最后一个元素上清除它并将其设置在“新”最后一个元素上),但在这种情况下你可以摆脱struct rle_parent
。
此外,将NULL
作为第一个参数传递给realloc()
,使其表现得像对malloc()
的调用,因此它在这里工作得很好。
虽然已经提到您正在分配指针的空间而不是结构本身,但还有另一个问题。
rle_pointer = &rle+1;
不会让你一个指针的地址RLE [1]。
提出其他更改后,您仍然会遇到段错误,但是如果您也尝试
rle[1].length=20;
printf("%d\n", rle[1].length);
代替
(*rle_pointer)->length = 20;
printf("%d\n", (*rle_pointer)->length);
您将使代码成功运行。 这将表明您的 realloc() 已成功运行。
为了更好地解释,双指针实际上是指向指针的指针。 &rle+1 处没有指针。 您的代码试图取消引用一个不存在的指针。
代替
rle_pointer = &rle+1;
你只能说
rle += 1;
如果你坚持这样做。 否则,我建议坚持使用 rle 作为数组并避免使用双指针。
对于更新:它正在写入和读取未分配的内存(导致 UB)afaik。
您可以通过释放 rle 并尝试执行相同的行为来验证这一点,在 gcc 7.4.0 上我也可以这样做。
malloc 和 realloc 需要在内存中预留(分配)空间的大小,所以如果你想做一个数组,你必须分配 1 个元素的大小乘以数组中的元素数,我建议你做一个变量保存数组的大小。 顺便说一句,据我所知,“分段错误”意味着您正在使用未分配的空间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.