【问题标题】:Binary tree insertion, help me to read valgrinds information二叉树插入,帮我看valgrinds资料
【发布时间】:2018-02-10 10:51:15
【问题描述】:

在一些基本的二叉树插入实现之后,我得到了一个内存错误。如果您能告诉我未来的学习过程,我将非常感激,在哪里可以找到 valgrind 的问题。我正在使用我在其他线程中阅读的内容或通过在线研究-v--leak-check=full 以及--show-leak-kinds=all 来查找有关内存泄漏的更多信息。

这是我的代码:

#include <stdio.h>
#include <stdlib.h>
#include <string.h>


typedef int bool;
#define true 1
#define false 0

typedef struct _bstNode
{
    int data;
    struct _bstNode *left;
    struct _bstNode *right;
} bstNode;

bstNode *getNewNode(int number)
{
    bstNode *newNode = malloc(sizeof(bstNode));
    newNode->data = number;
    newNode->left = NULL;
    newNode->right = NULL;

    return newNode;
}

bstNode *insert(bstNode *root, int number)
{
    if(root == NULL)
    {
        root = getNewNode(number);
    }else if(root->data <= number)
    {
        root->left = insert(root, number);
    }else if(root->data > number)
    {
        root->right = insert(root, number);
    }else
    {
        printf("Error inserting number.\n");
    }
    return root;
}

/*bool search(bstNode *root, int toSearch)
{
    if(root == NULL)
    {
        return false;
    }
    if(root->data == toSearch)
    {
        return true;
    } else if(root->data <= toSearch)
    {
        return search(root->left, toSearch);
    } else if(root->data > toSearch)
    {
        return search(root->right, toSearch);
    }else
    {
        printf("Error searching for number\n");
        return false;
    }
}*/

void destroy_tree(bstNode *n)
{
    if(n->left)
    {
        destroy_tree(n->left);
    }
    if(n->right)
    {
        destroy_tree(n->right);
    }
    free(n);
}

int main()
{
    bstNode *root = NULL;

    root = insert(root, 8);
    root = insert(root, 12);
    root = insert(root, 43);
    root = insert(root, 22);
    root = insert(root, 2);
    root = insert(root, 8);

    /*if(search(root, 9) == true)
    {
        printf("Found\n");
    }else
    {
        printf("Number not found\n");
    }

    if(search(root, 22) == true)
    {
        printf("Found\n");
    }else
    {
        printf("Number not found\n");
    }*/

    destroy_tree(root);
    return 0;
}
==3990== Memcheck, a memory error detector
==3990== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==3990== Using Valgrind-3.11.0 and LibVEX; rerun with -h for copyright info
==3990== Command: ./test
==3990== 
==3990== Stack overflow in thread #1: can't grow stack to 0xffe801000
==3990== 
==3990== Process terminating with default action of signal 11 (SIGSEGV)
==3990==  Access not within mapped region at address 0xFFE801FF8
==3990== Stack overflow in thread #1: can't grow stack to 0xffe801000
==3990==    at 0x400633: insert (in /home/richie/Dokumente/learningc/test)
==3990==  If you believe this happened as a result of a stack
==3990==  overflow in your program's main thread (unlikely but
==3990==  possible), you can try to increase the size of the
==3990==  main thread stack using the --main-stacksize= flag.
==3990==  The main thread stack size used in this run was 8388608.
==3990== Stack overflow in thread #1: can't grow stack to 0xffe801000
==3990== 
==3990== Process terminating with default action of signal 11 (SIGSEGV)
==3990==  Access not within mapped region at address 0xFFE801FF0
==3990== Stack overflow in thread #1: can't grow stack to 0xffe801000
==3990==    at 0x4A28680: _vgnU_freeres (in /usr/lib/valgrind/vgpreload_core-amd64-linux.so)
==3990==  If you believe this happened as a result of a stack
==3990==  overflow in your program's main thread (unlikely but
==3990==  possible), you can try to increase the size of the
==3990==  main thread stack using the --main-stacksize= flag.
==3990==  The main thread stack size used in this run was 8388608.
==3990== 
==3990== HEAP SUMMARY:
==3990==     in use at exit: 24 bytes in 1 blocks
==3990==   total heap usage: 1 allocs, 0 frees, 24 bytes allocated
==3990== 
==3990== 24 bytes in 1 blocks are still reachable in loss record 1 of 1
==3990==    at 0x4C2DB8F: malloc (in /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
==3990==    by 0x4005CA: getNewNode (in /home/richie/Dokumente/learningc/test)
==3990==    by 0x400615: insert (in /home/richie/Dokumente/learningc/test)
==3990==    by 0x4006F3: main (in /home/richie/Dokumente/learningc/test)
==3990== 
==3990== LEAK SUMMARY:
==3990==    definitely lost: 0 bytes in 0 blocks
==3990==    indirectly lost: 0 bytes in 0 blocks
==3990==      possibly lost: 0 bytes in 0 blocks
==3990==    still reachable: 24 bytes in 1 blocks
==3990==         suppressed: 0 bytes in 0 blocks
==3990== 
==3990== For counts of detected and suppressed errors, rerun with: -v
==3990== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)
Speicherzugriffsfehler (Speicherabzug geschrieben)

【问题讨论】:

  • 不要过度使用代码 sn-p。非 JS/HTML/CSS 应使用 Ctrl+K 格式化。
  • 代码执行递归调用(insert() 调用自身)导致“Stack overflow in thread #1”。堆栈溢出意味着所有堆栈空间都已被使用... bang
  • 需要注意的是不要使用_-前缀标识符;它们由 C 标准保留。此外,您可能对&lt;stdbool.h&gt; 感兴趣,它自 1999 年以来就已存在于标准 C 中...说了这么多,也许在询问您不知道的问题的过程中最重要的是告诉我们你知道什么。否则,我们必须假设您一无所知,从头开始重写编程教科书的所有章节……说到这里,您在读哪本书?

标签: c memory-management memory-leaks binary-tree valgrind


【解决方案1】:

声明

    root->left = insert(root, number);

    root->right = insert(root, number);

导致无限递归,因为您不更改传递的根。相反,使用:

    root->left = insert(root->left, number);

    root->right = insert(root->right, number);

注意:您的if(root-&gt;data &lt;= number) 可以创建一个副本。相反,请使用&lt;,然后您的Error 分支会识别出重复项(这可能是也可能不是错误)。

【讨论】:

  • 如 Valgrind 所述,导致无限递归”进而导致“Stack overflow”。
  • 是否有可能从 valgrind 获得输出,该输出说明溢出究竟来自哪一行?
【解决方案2】:

在 valgrind 中哪里可以找到问题。

代码进行递归调用(insert() 调用自身而不是 returning)导致

==3990== Stack overflow in thread #1: can't grow stack to 0xffe801000

堆栈溢出意味着所有堆栈空间都在使用中。并且由于进程的堆栈空间是有限的,这种情况无法通过引发信号来解决该进程

==3990== Process terminating with default action of signal 11 (SIGSEGV)

要解决此问题,请将代码迟早从 insert() 调整为 return

要了解堆栈溢出发生的位置,请使用符号编译(选项 -g 用于 GCC)并在调试器中运行代码,例如 gdb

【讨论】:

    【解决方案3】:

    递归插入函数中的小错误

    bstNode *insert(bstNode *root, int number)
    {
        if(root == NULL)
        {
            root = getNewNode(number);
        }else if(root->data <= number)
        {
            root->left = insert(root->left, number);      // insert(root->left
        }else if(root->data > number)
        {
            root->right = insert(root->right, number);    // insert(root->right
        }else
        {
            printf("Error inserting number.\n");
        }
        return root;
    }
    

    如果root 不为 NULL,则应向下移动到右侧或左侧子树,直到找到 NULL 点来创建新节点。您原来的insert() 只是不断尝试插入root

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-02-13
      • 2019-08-26
      • 1970-01-01
      • 2022-01-14
      • 2016-01-17
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多