【问题标题】:What is the appropriate way to dynamically allocate struct properties?动态分配结构属性的适当方法是什么?
【发布时间】:2014-04-25 03:23:06
【问题描述】:

在我开始之前,我应该说这与直接问题无关,而是出于好奇和我无法找到与我所追求的确切相关的东西。我目前正在自学 C,我有其他几种语言的经验,所以除了确切地如何执行某些事情之外,这并不是什么新鲜事。

我想在 C 中做一个挑战,比如构建一个可以根据需要增长一定数量的 Stack,我选择为此使用结构:

#define INITIAL_STACK_SIZE 10

typedef struct Stack {
  int max_size;
  int cur_top;
  int *elements;
} Stack;

我将元素保留为空点,因此可以根据需要对其进行扩展,这使得构建堆栈的函数如下:

Stack *Stack_make() {
  Stack *stack = malloc(sizeof(Stack)); // This is ultimately where I become confused
  stack->max_size = INITIAL_STACK_SIZE;
  stack->cur_top = -1;
  stack->elements = malloc(sizeof(int) * INITIAL_STACK_SIZE);

  return stack;
}

正如我所指出的,我的困惑在于结构的 malloc。我知道 C 会在内存中对齐结构数据元素,所以我很好奇如果元素指针稍后或次要分配给结构本身,它会如何做到这一点。这是不好的做法吗?有更好的方法吗?

为了完整起见,这就是我要扩展堆栈的内容:

// Relevant bits only
int new_size = stack->max_size + INITIAL_STACK_SIZE;
int *elements = malloc(sizeof(int) * new_size));
if (elements != NULL) {
  memcpy(elements, stack->elements, sizeof(int) * stack->max_size);
  free(stack->elements);
  stack->elements = elements;
}

我知道这不是“代码审查”的最佳场所,但如果您有改进建议以及没有的建议,我们将不胜感激。 实际问题:在 C 中是否有更好的方法来做到这一点,我是否有任何陷阱?

【问题讨论】:

  • sizeof(Stack) 会处理编译器在结构中添加的任何填充。

标签: c struct malloc


【解决方案1】:

我知道 C 会在内存中对齐 struct 数据元素,所以我很好奇如果元素指针稍后或次要分配给 struct 本身,它会如何做到这一点。

指针将与结构的其余部分位于同一连续内存中,但指针指向的malloc'ed 内存将位于malloc 放置的任何位置。 (毕竟,你可以拥有多个指向同一个内存的结构体;显然,它不能与所有结构体对齐。)

这是不好的做法吗?

这取决于“这个”是什么。如果“this”在结构中有一个指向动态分配内存的指针,那么不,这不是坏习惯。

也就是说,您的特定算法并不好,因为它涉及每次都复制所有内容。

有更好的方法吗?

是的,realloc

realloc,如果可能,将扩展之前为该指针分配的内存。如果那不可能,那么它将为您移动内存块(并释放已使用的内存块)。返回值是一个指向内存的指针,可能是同一个指针,也可能是新的。

因此您的代码(或至少您共享的代码)变为:

int new_size = stack->max_size + INITIAL_STACK_SIZE;
int *elements = realloc(stack->elements, sizeof(int) * new_size);
if(elements != NULL) {
    stack->elements = elements;
}

仅供参考,flexible array members(在 C99 中)具有可变长度,但为结构本身分配了 included in the memory。它们在这里不符合您的需求,但鉴于您对内存对齐的问题,您可能有兴趣了解它们。

【讨论】:

  • 啊,感谢您对realloc 的引用,这绝对是一个更好的方法。
  • 聚合!你掉进了realloc 的陷阱。如果realloc 返回NULL,你只是泄露了区块!!!
  • 啊,“this”指的是在结构中拥有这种类型的未调整大小的指针,并与结构本身分开分配。
  • @pat,关于灵活的数组成员在这里不是正确的解决方案是正确的(我从未说过它们是正确的)。但是,它们是如何将可变数量的数据包含在结构内存中的示例。
  • @Prakash 使用灵活的成员,您将无法拥有像 int stack_push(Stack *stack, int element) 这样的 API,因为当堆栈已满时,整个 Stack 结构将需要为 realloc' d,可能会更改其地址(因为元素与Stack 本身连续存储),因此任何指向Stack 的指针现在都将无效。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2021-10-02
  • 2017-10-01
  • 1970-01-01
  • 2012-10-30
  • 2023-01-24
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多