结构内固定大小数组的内存分配
Memory allocation of fixed size array inside a struct
我有以下树节点结构,其中包含指向其他树节点的指针:
struct node {
// ...
struct node* children[20];
}
我的想法是,我想检查 children
和 based 中是否有 node*
并且更深入到树中。因此,当我分配 node
时,我希望 children
具有 20 个 NULL
值。
目前我不做
- 我应该如何分配此数组才能避免出现
Conditional jump or move depends on uninitialised value(s)
(Valgrind) 之类的错误?
- 每次分配新节点时使用
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->children
或calloc()
上便携使用memset()
,因为那些会给你 "all bits zero" 这与 "pointer NULL
".
不同
我有以下树节点结构,其中包含指向其他树节点的指针:
struct node {
// ...
struct node* children[20];
}
我的想法是,我想检查 children
和 based 中是否有 node*
并且更深入到树中。因此,当我分配 node
时,我希望 children
具有 20 个 NULL
值。
目前我不做
- 我应该如何分配此数组才能避免出现
Conditional jump or move depends on uninitialised value(s)
(Valgrind) 之类的错误? - 每次分配新节点时使用
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->children
或calloc()
上便携使用memset()
,因为那些会给你 "all bits zero" 这与 "pointer NULL
".