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("%dn", (*rle_pointer)->length);
rle_pointer = &rle+1;
(*rle_pointer)->length = 20;
printf("%dn", (*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("%dn", rle[0].length);
rle[1].length = 20;
printf("%dn", 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 -- %cn", e->length, e->character);
}
return 0;
}

或者,如果不想保留计数,可以向struct rle_element添加另一个字段,指示它是数组中的最后一个元素。每次添加新元素时,您都必须更新它(在"当前"最后一个元素上清除它,并在"新"最后一次元素上设置它),但在这种情况下,您可以去掉struct rle_parent

此外,将NULL作为第一个参数传递给realloc(),使其行为类似于对malloc()的调用,因此它在这里运行得很干净。

虽然已经提到了分配指针的空间而不是结构本身,但还有另一个问题。

rle_pointer = &rle+1;

不会为您获取指向rle[1]的指针的地址。

有了其他的改变,你仍然会得到一个segfault,然而,如果你也尝试

rle[1].length=20;
printf("%dn", rle[1].length);

代替

(*rle_pointer)->length = 20;
printf("%dn", (*rle_pointer)->length);

您将使代码成功工作。这将表明您的realloc()已成功工作。

为了更好地解释,双指针实际上是指向指针的指针。在&rle+1。您的代码试图取消引用一个不存在的指针。

代替

rle_pointer = &rle+1;

你可以说

rle += 1;

如果你坚持这样做。否则,我建议坚持使用rle作为数组,并避免使用双指针。

对于更新:它正在写入和读取未分配的内存(导致UB)afaik。

您可以通过释放rle并尝试执行相同的行为来验证这一点,在gcc 7.4.0上,我也可以执行相同的操作。

malloc和realloc需要在内存中保留(分配)空间的大小,所以如果你想制作一个数组,你必须分配1个元素的大小乘以数组中元素的数量,我建议你制作一个变量来保持数组的大小。BTW"分割错误",据我所知,意味着你正在使用你没有分配的空间。

最新更新