简体   繁体   English

在C中遍历二叉树

[英]Traversing a binary tree in C

I'm trying to traverse a binary tree in C. My tree contains an AST node (abstract syntax tree node for compiler). 我正在尝试遍历C中的二叉树。我的树包含一个AST节点(编译器的抽象语法树节点)。 ASTnode reserves nodetype which specifies given node's type (ie INT OP or CHAR and TYPE we don't need to concern other types), the other members are left and right pointers, and finally we store. ASTnode保留nodetype,它指定给定节点的类型(即INT OP或CHAR和TYPE,我们不需要关注其他类型),其他成员是左右指针,最后我们存储。

Here is code for traversing: 这是遍历的代码:

    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;
        }
    }

Also we can't assign left or right values to CONSTANT nodes because in AST, constant values don't contain any extra values. 此外,我们不能将左值或右值分配给CONSTANT节点,因为在AST中,常量值不包含任何额外值。

Updated: 更新:

The problem is in my main call: 问题出在我的主要电话中:

    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);
    }

If we delete node5 (which is marked by !!) the code works very well otherwise it gives a segmentation fault. 如果我们删除node5(标记为!!),代码工作得很好,否则会产生分段错误。

Functions that operate on makenode : makenode上运行的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;
    }

Your mallocs are wrong 你的mallocs错了

 struct decl *d = (struct decl*) malloc(sizeof(struct decl*));
 struct decl *d2 = (struct decl*) malloc(sizeof(struct decl*));

need to be 需要

 struct decl *d = (struct decl*) malloc(sizeof(struct decl));
 struct decl *d2 = (struct decl*) malloc(sizeof(struct decl));

(or use sizeof *d instead of sizeof(struct decl)). (或使用sizeof * d而不是sizeof(struct decl))。 In C you don't need to cast the return value of malloc , btw. 在C中,您不需要转换malloc,btw的返回值。

Also, make sure you're setting members to NULL or another default value before you access them. 此外,在访问成员之前,请确保将成员设置为NULL或其他默认值。 malloc will not set them to 0/NULL for you. malloc不会为你设置它们为0 / NULL。

All I can see is that maybe you'd want to check root->value et al before passing to printf. 我只能看到,在传递给printf之前,你可能想要检查root->value等。

Also, though this shouldn't cause a bug, you might want to change 此外,虽然这不应该导致错误,但您可能想要更改

if(root != NULL && root->nodeType == CHAR)

to

else if(root != NULL && root->nodeType == CHAR)

Edit: wait, here's something - when you pass root->left to traverse, is that the value itself or a pointer? 编辑:等等,这是什么 - 当你传递root->left to traverse时,是值本身还是指针? The function expects a pointer. 该函数需要一个指针。

You're not checking to see if 'root' is NULL in your first 'if' block. 您没有检查第一个'if'块中的'root'是否为NULL。 I think the easiest thing to do is to wrap 我认为最简单的事情就是包装

if(root != NULL)

around the whole thing (except the final return), and get rid of the separate 'root != NULL' checks when printing the INT and CHAR nodes. 围绕整个事物(最终返回除外),并在打印INT和CHAR节点时摆脱单独的'root!= NULL'检查。

Share and enjoy. 分享和享受。

EDIT: here's what I mean: 编辑:这就是我的意思:

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); 
      }
    } 
  }

Also changed to use a switch instead of a bunch of if's. 也改为使用开关而不是一堆if。

Please excuse any syntax errors: this is off the top of my head with no compiler handy. 请原谅任何语法错误:这是我的头脑,没有编译器方便。

The makeNode function needs to initialize all members of the structure. makeNode函数需要初始化结构的所有成员。 Is it perhaps not setting one of the left/right pointers to NULL? 是否可能没有将左/右指针之一设置为NULL? The malloc() call does not zero the memory. malloc()调用不会将内存归零。

Ack - I'm blind. Ack - 我是瞎子。 The answer by nos is the correct one. nos的答案是正确的。 Incorrect malloc call. malloc调用不正确。 I was just adding to the noise. 我只是加入了噪音。

Your code will segfault at the first NULL node passed into traverse(). 您的代码将在传递给traverse()的第一个NULL节点处发生段错误。

You take care to check root != NULL within your else block, but by then you have already dereferenced it. 你需要注意检查你的else块中的root != NULL ,但那时你已经取消引用了它。 If you try to dereference a NULL pointer, you'll segfault. 如果您尝试取消引用NULL指针,则会出现段错误。

Try adding 尝试添加

if (!root) return;  

as your first line. 作为你的第一线。

You show code allocating ' struct decl ' pointers; 你展示了分配' struct decl '指针的代码; you don't show the code initializing them. 你没有显示初始化它们的代码。 It is not clear why makeNode() would initialize its second argument, or how it would do so. 目前尚不清楚为什么makeNode()会初始化它的第二个参数,或者它将如何进行初始化。 It is also not clear what the 3 means. 目前还不清楚这意味着什么。 Nor is it clear how the ' struct decl ' integrates into the ASTnode. 也不清楚' struct decl '如何集成到ASTnode中。

You can simplify traverse() by dealing with exceptional cases early: 您可以通过尽早处理异常情况来简化遍历():

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);
}

This also deals with the impossible case - an unrecognized node type. 这也涉及不可能的情况 - 一种无法识别的节点类型。 It also does not crash and burn if a null pointer is passed in. 如果传入空指针,它也不会崩溃和刻录。

However, this does not yet explain why your code crashes and doesn't crash depending on the extra ASTnode...I'm not convinced we have enough code to be sure of why that happens. 但是,这还没有解释为什么你的代码崩溃并且不会崩溃,这取决于额外的ASTnode ...我不相信我们有足够的代码来确定为什么会发生这种情况。 Have you tried traversing all the nodes (node1, node2, node3, node10)? 您是否尝试遍历所有节点(node1,node2,node3,node10)? These should be fine assuming the makeCharNode() and makeINTNode() functions work sanely, but such rudimentary checks can save your bacon. 假设makeCharNode()和makeINTNode()函数工作正常,这些应该没问题,但是这样的基本检查可以节省你的培根。 It might be helpful to see what the makeNode() function does; 查看makeNode()函数的作用可能会有所帮助; does it ensure all parts of the node are properly initialized. 它确保节点的所有部分都已正确初始化。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM