C - 通过函数创建具有多个 children 的节点 - 分段错误

C - Creating node with multiple children by function - segmentation fault

我想创建具有多个 children 的树并创建每个节点都有一个函数。这是我的节点结构:

typedef struct node {
   char *string; // Name of the node

   int number_of_children;

   struct node *children[];
} node;

这是我创建新节点的函数(有四个 children):

node *add_node(char *string, node *left, node *middle_left, node *middle_right, node *right) {
   node *p;
   if ((p = malloc(sizeof(node))) == NULL) yyerror("Memory error");

   p->string = strdup(string);

   p->children[p->number_of_children] = left;
   p->children[p->number_of_children + 1] = middle_left;
   p->children[p->number_of_children + 2] = middle_right;
   p->children[p->number_of_children + 3] = right;

   p->number_of_children = 4;

   return p;
}

当我运行 p->string 下的这个函数值被更改为一些垃圾。当我想设置固定数量的 children(在我将 struct node *children[] 更改为 struct node *children[4] 的结构中)时,出现分段错误。你有什么想法?

你定义结构的方式,你必须事先知道你可以有多少children,因为你必须明确地为最后一个成员分配内存:

node *p = malloc(sizeof(node) + nchildren * sizeof(node));

您可以稍后重新分配以容纳更多节点,但这不是一种可行的方法,因为重新分配的内存的句柄可能会更改,这会破坏树连接。

有更好的方法让节点具有不同数量的 children,例如:

  • 设定一个固定的最大 children 数,也许是 4 个,并使成员数组 children 明确地为 4 个元素长。保留一个数字,告诉您有多少 children 是有效的。
  • 使 children 的列表成为动态分配的数组,以后可以重新分配。这意味着您有一个 two-level 分配:首先是正确的节点,然后是其 children.
  • 的列表
  • 保留 child 个节点的链表。想一想,您可以重新排列树,使每个节点都有一个 child 作为其最旧的 child 节点,并为每个节点的下一个最老的兄弟节点提供一个 sibling 节点。

我不确定你到底想做什么,但第一种方法似乎对你来说是最简单的。

您的代码还有其他几个错误:

  • 您应该只在创建节点时分配内存。显然,您已经将有效的节点句柄传递给您的函数。这些节点已经分配了内存或者它们是NULL。以下:

    p = malloc(sizeof(*p));
    p = pref;
    

    将分配内存并立即失去该内存的唯一句柄,这是内存泄漏。这里不用分配,直接说p = pref.

  • malloc分配的内存未初始化;它包含垃圾。在使用之前初始化所有结构成员。或者,考虑使用 calloc,它分配内存并将其清零。

  • if ((p = malloc(sizeof(node))) == NULL) 中的组合赋值和检查是有效的,但阅读起来很复杂。在我看来,最好将它们分为分配和后续检查。 (毕竟,它只是以一些额外的括号为代价节省了您两次输入 p。)

您按数组传入可变数量的儿童的示例可能如下所示:

typedef struct node {
   char *string;    
   size_t number_of_children;    
   struct node *children[4];
} node;

node *add_node(char *string, node *child[], size_t n) 
{
   node *p  = malloc(sizeof(*p));
   size_t i;

   if (p == NULL) yyerror("Memory error");

   p->string = strdup(string);

   for (i = 0; i < n; i++) p->children[i] = child[i];    
   p->number_of_children = n;

   return p;
}