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

时间:2019-01-23 20:21:10

标签: c struct malloc

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

我有以下代码:

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

3 个答案:

答案 0 :(得分:1)

您的代码存在各种问题(在注释和其他答案中指出)。您缺少的一件事是您没有跟踪分配区域的大小。 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()的调用,因此在这里可以正常工作。

答案 1 :(得分:0)

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

rle_pointer = &rle+1;

not 不会为您提供指向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上,我可以执行相同的操作。

答案 2 :(得分:0)

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