【问题标题】:Dynamic array of structs in c (malloc, realloc)c中结构的动态数组(malloc,realloc)
【发布时间】:2019-01-23 20:21:09
【问题描述】:

我正在尝试创建一个结构元素数组并在需要新元素时重新分配。该数组必须是一个指针,因为我想从函数中返回它。

我有以下代码:

   #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;
  }

【问题讨论】:

  • 你忘了问问题。
  • 不工作是什么意思?它应该做什么以及实际发生了什么?
  • 当我运行上面的代码时,它会在第一行打印 10,在第二行打印“Segmentation fault”。
  • sizeof(struct rle_element*) 是指针的大小(可能是 4 或 8 个字节,具体取决于您的硬件)。你想要sizeof(struct rle_element)
  • 我试过了,但我得到了同样的错误信息。

标签: c struct malloc


【解决方案1】:

您的代码存在各种问题(在 cmets 和其他答案中指出)。您缺少的一件关键事情是您没有跟踪分配区域的大小。 sizeof() 在编译时评估(除非您使用 C99 VLA)。因此,sizeof(rle) 不会评估您的数组正在使用的字节数。您必须单独存储。这是一个有效的实现,它使用 struct rle_parent 结构跟踪大小,其中包含 cmets 以帮助您理解:

#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() 的调用,所以它在这里运行良好。

【讨论】:

    【解决方案2】:

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

    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 上我也可以这样做。

    【讨论】:

    • 我正在尝试将 rle 用作数组。
    • 你不应该需要一个 rle_pointer 。我在最后更新了一点来解释下一个问题,afaik 它正在读取和写入未分配的内存,导致 UB 碰巧解决了。
    【解决方案3】:

    malloc 和 realloc 需要在内存中保留(分配)空间的大小,所以如果你想创建一个数组,你必须分配 1 个元素的大小乘以数组中的元素个数,我建议你创建一个变量来保存数组的大小。 顺便说一句,据我所知,“分段错误”意味着您正在使用未分配的空间。

    【讨论】:

      猜你喜欢
      • 2012-09-19
      • 2018-07-13
      • 1970-01-01
      • 2021-01-15
      • 1970-01-01
      • 2017-06-08
      • 1970-01-01
      • 2018-11-30
      • 2015-02-13
      相关资源
      最近更新 更多