繁体   English   中英

c中结构的动态数组(malloc,realloc)

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM