我正在创建一个编译器,并开始创建我的解析树结构。
我有一个'节点',它可以包含或不包含子节点。
typedef struct Node {
int node_type;
union {
char* string;
int number;
struct Node* nodes;
} node_data;
} Node;
这些功能组装/打印
Node* MakeNodeFromString(char* mystring) {
Node* mynode = (Node*) malloc(sizeof(Node));
mynode->node_data.string = strdup(mystring);
mynode->node_type = 0; // @TODO not 3
return mynode;
}
Node* MakeTwoBranchNode(int nodetype, Node* a, Node* b) {
Node* mynode = (Node*) malloc(sizeof(Node));
mynode->node_type = 2; // @TODO not 3
mynode->node_data.nodes = malloc(2 * sizeof(Node*));
mynode->node_data.nodes[0] = *a; mynode->node_data.nodes[1] = *b;
return mynode;
}
void printtree (Node *n, int level) {
if (!n) return;
printf ("start %d\n", n->node_type);
switch (n->node_type) {
case 2:
printf ("%*c2\n", level, ' ');
printtree (&n->node_data.nodes[0], level+1);
printtree (&n->node_data.nodes[1], level+1);
break;
case 0:
printf ("%*c%s\n", level, ' ', n->node_data.string);
break;
}
printf ("end %d\n", n->node_type);
}
每当我组装一棵树时,我会得到段错误,无论是printf'ing还是strlen'ing我的字符串。我已经尝试过strdup,strcpy等等。我很确定它的MakeTwoBranchNode没有失败,因为我可以创建大型数字树(不包含代码)。但我不确定。
这是一个代码示例,它在我的机器上执行 - 并且不会 - 段错误
int main() {
// Works
printtree(
MakeTwoBranchNode(3,
MakeNodeFromString("first string"),
MakeNodeFromString("second string")
),
1
);
// Fails
printtree(
MakeTwoBranchNode(3,
MakeTwoBranchNode(3,
MakeNodeFromString("first string"),
MakeNodeFromString("second string")
),
MakeNodeFromString("third string")
),
1
);
}
如果你运行这个例子(并且可以理解它的神秘输出),你会在printf(n-> node_data.string)中看到它的段错误。
答案 0 :(得分:3)
你在下面分配了sizeof-a-pointer,而不是sizeof-a-node:
Node* MakeTwoBranchNode(int nodetype, Node* a, Node* b) {
Node* mynode = malloc(sizeof(Node));
mynode->node_type = 2; // @TODO not 3
mynode->node_data.nodes = malloc(2 * sizeof(Node*)); // HERE
mynode->node_data.nodes[0] = *a; mynode->node_data.nodes[1] = *b;
return mynode;
}
您可以将上面的注释行更改为:
mynode->node_data.nodes = malloc(2 * sizeof(Node));
但是,将您的测试程序写成内存泄漏。您为传递到MakeTwoBranchNode()
的节点分配的内存会发生什么变化?这不是我认为你真正想要的。首先使用指针数组会更好。
typedef struct Node {
int node_type;
union {
char* string;
int number;
struct Node *nodes[2];
} node_data;
} Node;
然后保存传递给MakeTwoBranchNode
的实际指针。在这样做时,您将这些节点的所有权传递给双分支节点(因此您还应确保何时释放它以正确清理其子节点):
Node* MakeTwoBranchNode(int nodetype, Node* a, Node* b) {
Node* mynode = malloc(sizeof(Node));
mynode->node_type = 2; // @TODO not 3
mynode->node_data.nodes[0] = a;
mynode->node_data.nodes[1] = b;
return mynode;
}
现在没有内存泄漏,除非你在销毁双分支节点时free()
和nodes[0]
中没有nodes[1]
指针。
答案 1 :(得分:2)
typedef struct Node {
int node_type;
union {
char *string;
int number;
struct Node **nodes; // <-- here
} node_data;
} Node;
Node *MakeNodeFromString(char *mystring) {
Node *mynode = malloc(sizeof *mynode);
mynode->node_data.string = strdup(mystring);
mynode->node_type = 0; // @TODO not 3
return mynode;
}
Node *MakeTwoBranchNode(int nodetype, Node *a, Node *b) {
Node *mynode = malloc(sizeof *mynode);
mynode->node_type = 2; // @TODO not 3
mynode->node_data.nodes = malloc(2 * sizeof *mynode->node_data.nodes ); // <- here
mynode->node_data.nodes[0] = *a; mynode->node_data.nodes[1] = *b;
return mynode;
}
void printtree (Node *n, int level) {
if (!n) return;
printf ("start %d\n", n->node_type);
switch (n->node_type) {
case 2:
printf ("%*c2\n", level, ' ');
printtree (n->node_data.nodes[0], level+1); // <-- here
printtree (n->node_data.nodes[1], level+1); // <- and here
break;
case 0:
printf ("%*c%s\n", level, ' ', n->node_data.string);
break;
}
printf ("end %d\n", n->node_type);
}