【问题标题】:Traversing a binary tree in C在 C 中遍历二叉树
【发布时间】:2010-12-30 03:19:21
【问题描述】:

我正在尝试遍历 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;
    }

【问题讨论】:

  • 在哪一行出现段错误?使用-g 选项编译,并使用核心文件启动gdbgdb prog core,运行命令bt - 它会打印回溯并告诉您程序段错误的确切位置。
  • 启动程序:/home/nazmi/Desktop/symbol table/xx/new/ast OP left - INT - INT: 19 程序收到信号 SIGSEGV,分段错误。 0x08048891 in traverse99 (root=0x11) at ast.c:154 154 if (root->nodeType == OP)
  • 所以它在第 154 行失败,取消引用 root。在取消引用之前,您需要确保 root 不是 NULL

标签: c search binary-tree tree-traversal


【解决方案1】:

makeNode 函数需要初始化结构的所有成员。是否可能没有将左/右指针之一设置为 NULL? malloc() 调用不会将内存归零。

Ack - 我瞎了。否的答案是正确的。不正确的 malloc 调用。我只是增加了噪音。

【讨论】:

    【解决方案2】:

    您显示分配“struct decl”指针的代码;您没有显示初始化它们的代码。不清楚为什么 makeNode() 会初始化它的第二个参数,或者它是如何这样做的。也不清楚 3 是什么意思。也不清楚“struct decl”是如何集成到 ASTnode 中的。

    您可以通过及早处理异常情况来简化 traverse():

    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() 函数的作用可能会有所帮助;它是否确保节点的所有部分都正确初始化。

    【讨论】:

      【解决方案3】:

      您没有在第一个“if”块中检查“root”是否为 NULL。我认为最简单的方法是包装

      if(root != NULL)
      

      围绕整个事情(最终返回除外),并在打印 INT 和 CHAR 节点时摆脱单独的“根!= 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。

      请原谅任何语法错误:这是我的想法,没有手头的编译器。

      【讨论】:

      • 你的代码工作正常,但问题是由我认为的主要部分引起的,它仍然给出分段错误
      【解决方案4】:

      你的 malloc 错误

       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 的返回值,顺便说一句。

      此外,请确保在访问成员之前将其设置为 NULL 或其他默认值。 malloc 不会为您将它们设置为 0/NULL。

      【讨论】:

      • 是的,它解决了我从我的代码中删除所有 * 的问题 thx :))
      • 很好,@nos...避免该问题的一种方法是使用:struct decl *d = (struct decl *)malloc(sizeof(*d));。即使d 的类型发生变化,这也是正确的——这个问题就是为什么它是一个好主意的一个例子。
      【解决方案5】:

      您的代码将在传递给 traverse() 的第一个 NULL 节点处发生段错误。

      您注意在 else 块中检查 root != NULL,但到那时您已经取消引用它。如果您尝试取消引用 NULL 指针,则会出现段错误。

      尝试添加

      if (!root) return;  
      

      作为你的第一行。

      【讨论】:

        【解决方案6】:

        我只能看到,在传递给 printf 之前,您可能想检查 root->value 等。

        此外,虽然这不会导致错误,但您可能需要更改

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

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

        编辑:等等,这里有一些东西——当你传递root->left 进行遍历时,是值本身还是指针?该函数需要一个指针。

        【讨论】:

          猜你喜欢
          • 2012-01-01
          • 2022-11-11
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多