【问题标题】:Binary search tree insertion program is showing segmentation fault二叉搜索树插入程序显示分段错误
【发布时间】:2020-01-31 13:56:01
【问题描述】:

节点插入代码引发分段错误。 当我尝试打印存储在根节点中的数据时,此代码会引发分段错误。

下面是二叉搜索树插入程序的实现。 这个程序使用递归来插入一个给定的节点。

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

struct node
{
  int data;
  struct node *left;
  struct node *right;
};

struct node *make (int);
struct node *insert (struct node *, int);

void
main ()
{
  struct node *root;
  root = NULL;

  insert (root, 2);
  insert (root, 3);
  insert (root, 4);
  insert (root, 5);
  insert (root, 6);
  insert (root, 7);
  printf ("%d", root->data);
}

struct node *
make (int x)
{
  struct node *temp;
  temp = (struct node *) malloc (sizeof (struct node *));
  temp->data = x;
  temp->left = NULL;
  temp->right = NULL;
  return temp;
}

struct node *
insert (struct node *root, int x)
{
  if (root == NULL)
  {
    root = make (x);
  }
  else
  {
    if (x <= root->data)
    {
      root->left = insert (root->left, x);
    }
    else if (x > root->data)
    {
      root->right = insert (root->right, x);
    }
  }
  return root;
}   

【问题讨论】:

  • 你的堆栈跟踪显示了什么?
  • 那么你很幸运!分段错误会将您的调试器带到发生错误的确切行和指令,并向您显示该点的每个变量和内存位置的值。
  • root == NULL - root 是本地指针,它不会修改外部的 root。因此root-&gt;dataprintf里面是NULL-&gt;data
  • 试想一下,你在insert 中使用makeroot 分配内存:main 怎么会看到这个?
  • 谢谢 - 卡米尔库克。我应该声明 root = insert(root,2)。

标签: c malloc binary-search-tree dynamic-memory-allocation


【解决方案1】:

问题是您没有将函数插入的返回值分配给节点根。

root = 插入(root,2);

//...

另一个问题是你分配的内存不正确

temp = (struct node *) malloc (sizeof (struct node *));
                                       ^^^^^^^^^^^^^

应该有

temp = (struct node *) malloc (sizeof (struct node ));
                                       ^^^^^^^^^^^^^

同样在函数内插入内部 if 语句应该是这样的

if (x < root->data)
{
    root->left = insert (root->left, x);
}
else
{
    root->right = insert (root->right, x);
}

注意,根据C标准,没有参数的函数main应该声明为

int main( void )

【讨论】:

  • malloc() 返回类型转换是否无用,如stackoverflow.com/questions/605845/… 所述
  • @EsmaeelE 有时它是无用的,有时它使代码自我记录并允许避免错误。
  • 能否请您解释一下malloc()的真实使用方式,尤其是我们不能强制转换其返回值以及何时强制转换的情况。
  • @EsmaeelE 例如你能说这段代码是否有效 p = malloc( sizeof( int[M][N] ) ); 吗?或者您对语句 p = malloc( sizeof( *p ) ) 中分配的内存类型有什么看法?在这个语句和 p 的声明之间可以有几十个屏幕。是不是要前后滚动源代码才能知道p的声明是什么?
  • 我在两种情况下发现了 malloc 返回类型的显式类型转换,即:p =(cast to type of p) malloc( sizeof( *p ) ) 有助于使代码清晰,从这一点我们知道 p 指向的是哪种类型的内存而不是搜索for p 在其他地方声明。
【解决方案2】:

不要忽略insert的返回值:

void main(){
  struct node* root;
  root = NULL;

  root = insert(root,2);
  insert(root,3);
  insert(root,4);
  insert(root,5);
  insert(root,6);
  insert(root,7);

  printf("%d",root->data);
}

您可能需要考虑的其他要点:

  • 我不推荐使用void main():主要是因为这是非标准的。使用 int main(void) 并返回 0。
  • 使用printf("%p", root);进行验证:如果值为0x0,则您的指针为NULL。
  • 在子函数中执行内存分配时,应始终检查分配是否成功。
struct node *
make (int x)
{
  struct node *temp;
  if ((temp = (struct node *) malloc (sizeof (struct node))) == NULL)
      return (NULL);
  temp->data = x;
  temp->left = NULL;
  temp->right = NULL;
  return temp;
}

【讨论】:

  • 在任何其他路径上,insert 只返回原始根目录不变。因此,将调用者root 变量重新分配给返回值总是好的。
  • 如果 insert 在失败的情况下返回 NULL,你将丢失 root 指针。
  • 真的!但它现在的编写方式表明它打算让调用者保存返回值,而调用者并没有这样做。无论如何,当前代码将在分配失败时进入 SEGV - 它需要重新设计才能生存。
  • 也是真的!我的解决方案绝对不完美:虽然我想用最少的代码修改来回答 OP 的问题和具体问题,但我并没有解决所有内存处理问题。
  • 在子函数中执行内存分配时,应始终检查分配是否成功。 如果您在 *nix 操作系统上运行,则应该也尝试分配给它,因为实际的内存分配被延迟并且malloc()总是返回True(太有趣了)stackoverflow.com/q/48585079/4022608可能有用
猜你喜欢
  • 1970-01-01
  • 2016-12-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多