结构内固定大小数组的内存分配

Memory allocation of fixed size array inside a struct

我有以下树节点结构,其中包含指向其他树节点的指针:

struct node {
    // ...
    struct node* children[20];
}

我的想法是,我想检查 children 和 based 中是否有 node* 并且更深入到树中。因此,当我分配 node 时,我希望 children 具有 20 个 NULL 值。 目前我不做

  1. 我应该如何分配此数组才能避免出现 Conditional jump or move depends on uninitialised value(s) (Valgrind) 之类的错误?
  2. 每次分配新节点时使用struct node** children并分配固定大小会更好吗?

编辑: Valgrind 抱怨的地方示例:

for(int i=0;i<20;i++)
  if(node->children[i] != NULL)
    do_something_with_the_node(node->children[i]);

您的结构定义是有效的(尽管在没有更多上下文的情况下很难判断它是否符合您的要求)。

Valgrind 不会抱怨您的结构定义,它可能会抱怨您如何实例化该类型的变量。确保所有数组成员都已初始化,投诉很可能会消失。

问题是您在 if 条件下使用了未初始化的值。

当你实例化一个struct node时,它的成员struct node* children[20];是一个包含20个struct node *的数组,所有这些都是未初始化的。

和这个没什么区别:

char *x;

if (x == NULL) {
    /* Stuff */
}

在这一点上,x可能实际上具有任何价值。在您的示例中,数组的任何元素都可以具有任何值。

要解决此问题,您需要在使用数组元素之前对其进行初始化,例如:

for (int i = 0; i < 20; ++i) {
    node->children[i] = NULL;
}

或更短:

memset(node->children, 0, 20);

如果您按照您的建议将成员更改为 node **children,情况不会有太大不同 - 您仍然需要初始化所有成员,包括数组的元素。您可以使用 calloc 来缩短它,这会将所有字节初始化为 0;话又说回来,您将需要一些代码来正确解除分配(并记住这样做),所以我认为权衡是不值得的。

分配 struct node 的新实例时,必须将包含的指针设置为 NULL 以将它们标记为 "not pointing anywhere"。这将使 Valgrind 警告消失,因为指针将不再未初始化。

像这样:

struct node * node_new(void)
{
  struct node *n = malloc(sizeof *n);
  if(n != NULL)
  {
    for(size_t i = 0; i < sizeof n->children / sizeof *n->children; ++i)
      n->children[i] = NULL;
  }
  return n;
}

不能n->childrencalloc()上便携使用memset(),因为那些会给你 "all bits zero" 这与 "pointer NULL".

不同