我正在尝试遍历C中的二叉树。我的树包含一个AST节点(编译器的抽象语法树节点)。 ASTnode保留nodetype,它指定给定节点的类型(即INT OP或CHAR和TYPE,我们不需要关注其他类型),其他成员是左右指针,最后我们存储。
以下是遍历的代码:
void traverse(struct ASTNode *root)
{
if(root->nodeType == OP){
printf("OP \n");
if(root->left != NULL){
printf("left - ");
traverse(root->left);
}
if(root->right != NULL){
printf("right - ");
traverse(root->right);
}
return;
}
else{
if(root != NULL && root->nodeType == INT)
{
printf("INT - ");
printf("INT: %d\n",root->value);
}
if(root != NULL && root->nodeType == CHAR)
{
printf("CHAR - ");
printf("CHAR: %c\n",root->chValue);
}
return;
}
}
此外,我们无法为CONSTANT节点指定左侧或右侧值,因为在AST中,常量值不包含任何额外值。
更新:
问题出在我的主要电话中:
int main()
{
struct ASTNode *node1 = makeCharNode('a');
struct ASTNode *node2 = makeCharNode('b');
struct ASTNode *node10 = makeCharNode('c');
struct ASTNode *node3 = makeINTNode(19);
struct decl *d = (struct decl*) malloc(sizeof(struct decl*));
struct decl *d2 = (struct decl*) malloc(sizeof(struct decl*));
struct ASTNode *node4 = makeNode(3,d,node3,node2);
struct ASTNode *node5 = makeNode(3,d2,node4,node1); !!
traverse(node4);
}
如果删除node5(标记为!!),代码效果很好,否则会产生分段错误。
对makenode
:
struct ASTNode *makeNode(int opType,struct decl *resultType,struct ASTNode *left,struct ASTNode *right)
{
struct ASTNode *node= (struct ASTNode *) malloc(sizeof(struct ASTNode *));
node->nodeType = opType;
node->resultType = resultType;
node->left = left;
node->right = right;
return node;
}
struct ASTNode *makeINTNode(int value)
{
struct ASTNode *intnode= (struct ASTNode *) malloc(sizeof(struct ASTNode *));
intnode->nodeType = INT;
intnode->value = value;
return intnode;
}
struct ASTNode *makeCharNode(char chValue)
{
struct ASTNode *charNode = (struct ASTNode *) malloc(sizeof(struct ASTNode *));
charNode->nodeType = CHAR;
charNode->chValue = chValue;
return charNode;
}
答案 0 :(得分:11)
你的mallocs错了
struct decl *d = (struct decl*) malloc(sizeof(struct decl*));
struct decl *d2 = (struct decl*) malloc(sizeof(struct decl*));
需要
struct decl *d = (struct decl*) malloc(sizeof(struct decl));
struct decl *d2 = (struct decl*) malloc(sizeof(struct decl));
(或使用sizeof * d而不是sizeof(struct decl))。在C中,您不需要转换malloc,btw。
的返回值此外,在访问成员之前,请确保将成员设置为NULL或其他默认值。 malloc不会为你设置为0 / NULL。
答案 1 :(得分:1)
我只能看到,在传递给printf之前,你可能想要检查一下root->value
等。
此外,虽然这不会导致错误,但您可能想要更改
if(root != NULL && root->nodeType == CHAR)
到
else if(root != NULL && root->nodeType == CHAR)
编辑:等等,这是什么 - 当你将root->left
传递给遍历时,是值本身还是指针?该函数需要一个指针。
答案 2 :(得分:1)
你没有检查你的第一个'if'块中的'root'是否为NULL。我认为最简单的事情是包装
if(root != NULL)
围绕整个事情(最终返回除外),并在打印INT和CHAR节点时去掉单独的'root!= NULL'检查。
分享并享受。
编辑:这就是我的意思:void traverse(struct ASTNode *root)
{
if(root != NULL)
{
switch(root->nodeType)
{
case OP:
printf("OP \n");
if(root->left != NULL)
{
printf("left - ");
traverse(root->left);
}
if(root->right != NULL)
{
printf("right - ");
traverse(root->right);
}
break;
case INT:
printf("INT - ");
printf("INT: %d\n",root->value);
break;
case CHAR:
printf("CHAR - ");
printf("CHAR: %c\n",root->chValue);
}
}
}
也改为使用开关而不是一堆if。
请原谅任何语法错误:这是我的头脑,没有编译器方便。
答案 3 :(得分:1)
makeNode函数需要初始化结构的所有成员。是否可能没有将左/右指针之一设置为NULL? malloc()调用不会将内存归零。
Ack - 我是瞎子。 nos的答案是正确的。 malloc调用不正确。我只是加入了噪音。
答案 4 :(得分:1)
您的代码将在传递给traverse()的第一个NULL节点处发生段错误。
您需要注意检查其他区域中的root != NULL
,但到那时您已经取消引用它。如果您尝试取消引用NULL指针,则会发生段错误。
尝试添加
if (!root) return;
作为你的第一行。
答案 5 :(得分:1)
您显示分配“struct decl
”指针的代码;你没有显示初始化它们的代码。目前尚不清楚为什么makeNode()会初始化它的第二个参数,或者它将如何进行初始化。目前还不清楚这意味着什么。也不清楚“struct decl
”如何整合到ASTnode中。
您可以通过尽早处理异常情况来简化遍历():
void traverse(struct ASTNode *root)
{
if (root == NULL) // Or: assert(root != NULL);
return;
if (root->nodeType == OP)
{
printf("OP \n");
if (root->left != NULL)
{
printf("left - ");
traverse(root->left);
}
if (root->right != NULL)
{
printf("right - ");
traverse(root->right);
}
}
else if (root->nodeType == INT)
{
printf("INT - ");
printf("INT: %d\n", root->value);
}
else if (root->nodeType == CHAR)
{
printf("CHAR - ");
printf("CHAR: %c\n", root->chValue);
}
else
assert("Unrecognized nodeType" == 0);
}
这也涉及不可能的情况 - 一种无法识别的节点类型。如果传入空指针,它也不会崩溃和刻录。
然而,这还没有解释为什么你的代码崩溃并且不会崩溃,这取决于额外的ASTnode ...我不相信我们有足够的代码来确定为什么会发生这种情况。您是否尝试遍历所有节点(node1,node2,node3,node10)?假设makeCharNode()和makeINTNode()函数工作正常,这些应该没问题,但是这样的基本检查可以节省你的培根。查看makeNode()函数的作用可能会有所帮助;它确保节点的所有部分都已正确初始化。