C 二叉搜索树中的分段错误(核心转储)

C 二叉搜索树中的分段错误(核心转储),c,tree,binary,segmentation-fault,binary-search-tree,C,Tree,Binary,Segmentation Fault,Binary Search Tree,我正在尝试实现一个r&b树,但首先我想要一个简单的二叉树(它不在叶子上保存内容),然后实现r&b属性。问题是我犯了无法解释的错误 计划如下: #include <stdio.h> #include <stdlib.h> #include <math.h> #include <string.h> #include <stdbool.h> typedef struct node { unsigned long int val;

我正在尝试实现一个r&b树,但首先我想要一个简单的二叉树(它不在叶子上保存内容),然后实现r&b属性。问题是我犯了无法解释的错误

计划如下:

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

typedef struct node
{
    unsigned long int val;
    bool black;
    struct node* parent;
    struct node* lchild;
    struct node* rchild;
}mynode;

mynode* createNode(unsigned long int ival, mynode* father);
mynode* createLeaf(unsigned long int ival, mynode* father);
mynode* search (unsigned long int ival, mynode *root);
void insert ( unsigned long int ival, mynode *root);


int main()
{
    mynode root;
    mynode *rootptr;
    mynode *leafptr;
    FILE *fp;
    int ch;
    unsigned long long lines=0, i=0;
    unsigned long *myArr;
    unsigned long int ival;

   fp = fopen("integers.txt","r");
   if(fp == NULL)
   {
      printf("Error in opening file.");
      return(-1);
   }

    while(!feof(fp))
    {
    ch = fgetc(fp);
    if(ch == '\n')
    {
        lines++;
    }
    }
    lines++;
    printf("lines = %lu", lines);
    myArr = (unsigned long*)calloc(lines, sizeof(unsigned long));

    fseek(fp, 0, SEEK_SET);
    while(!feof(fp))
    {
          fscanf(fp, "%lu,", &myArr[i] ); // des ta pos k giati tou input.
          i++;
    }
    fclose(fp);

    root.val = myArr[0];
    root.parent = NULL;
    root.lchild = NULL;
    root.rchild = NULL;
    root.black = true;
    rootptr = &root;
    leafptr = createLeaf(rootptr->val, rootptr);
    rootptr->lchild = leafptr;
    leafptr = createLeaf(rootptr->val, rootptr);
    rootptr->rchild = leafptr;
    for(i=1; i<lines; i++)
    {
        ival = myArr[i];
        insert(ival, rootptr);
    }

    return 0;
}

mynode* createNode(unsigned long int ival, mynode* father)
{
  mynode* nodeptr;
  mynode node;
  nodeptr = &node;
  nodeptr->val = ival;
  nodeptr->lchild = NULL;
  nodeptr->rchild = NULL;
  nodeptr->parent = father;
  nodeptr->black = true;
  return nodeptr;
}

mynode* createLeaf(unsigned long int ival, mynode* father)
{
  mynode* nodeptr;
  mynode leaf;
  nodeptr = &leaf;
  nodeptr->val = ival;
  nodeptr->lchild = NULL;
  nodeptr->rchild = NULL;
  nodeptr->parent = father;
  nodeptr->black = true;
  return nodeptr;
}

mynode* search (unsigned long int ival, mynode *rootptr)
{
    mynode* myptr;

    myptr = rootptr;

    while ( ( (myptr->lchild) != NULL) && ( (myptr->rchild) != NULL))
    {
        if ( ival < myptr->val)
        {
            myptr = myptr->lchild;
        }
        else
        {
            myptr = myptr->rchild;
        }
    }
    return myptr;
    }

void insert (unsigned long int ival, mynode *root)
{
    mynode * current;
    mynode * leafptr;
    mynode * father;
    unsigned long int max, min;
    unsigned long int num;

    current = search(ival, root);
    num = current->val;
    if((current->val) == ival)
    {
        return ;
    }
    else
    {
        if(ival>(current->val))
        {
            max = ival;
            min = current->val;
        }
        else
        {
            max = current->val;
            min = ival;
        }
        father = current->parent;
        current = createNode(min, father);
        if(num == (father->lchild)->val)
        {
            father->lchild = current;
        }
        else
        {
            father->rchild = current;
        }
        leafptr = createLeaf(min, current);
        current->lchild = leafptr;
        leafptr = createLeaf(max, current);
        current->rchild = leafptr;
       return ;
    }
}
#包括
#包括
#包括
#包括
#包括
类型定义结构节点
{
无符号长整数;
布尔黑;
结构节点*父节点;
结构节点*lchild;
结构节点*rchild;
}mynode;
mynode*createNode(无符号长整数,mynode*父节点);
mynode*createLeaf(无符号长整数,mynode*father);
mynode*搜索(无符号长整数,mynode*根);
void insert(无符号长整数,mynode*root);
int main()
{
mynode根;
mynode*rootptr;
mynode*leafptr;
文件*fp;
int-ch;
无符号长线=0,i=0;
无符号长*myArr;
无符号长整数;
fp=fopen(“integers.txt”,“r”);
如果(fp==NULL)
{
printf(“打开文件时出错”);
返回(-1);
}
而(!feof(fp))
{
ch=fgetc(fp);
如果(ch='\n')
{
行++;
}
}
行++;
printf(“行=%lu”,行);
myArr=(无符号长*)calloc(行,sizeof(无符号长));
fseek(fp,0,SEEK_集);
而(!feof(fp))
{
fscanf(fp、%lu、&myArr[i]);///des ta pos k giati tou输入。
i++;
}
fclose(fp);
root.val=myArr[0];
root.parent=NULL;
root.lchild=NULL;
root.rchild=NULL;
root.black=true;
rootptr=&root;
leaftpr=createLeaf(rootptr->val,rootptr);
rootptr->lchild=leaftpr;
leaftpr=createLeaf(rootptr->val,rootptr);
rootptr->rchild=leafptr;
对于(i=1;ival=ival;
nodeptr->lchild=NULL;
nodeptr->rchild=NULL;
nodeptr->parent=父亲;
nodeptr->black=true;
返回nodeptr;
}
mynode*createLeaf(无符号长整数,mynode*father)
{
mynode*nodeptr;
我的节叶;
nodeptr=&leaf;
nodeptr->val=ival;
nodeptr->lchild=NULL;
nodeptr->rchild=NULL;
nodeptr->parent=父亲;
nodeptr->black=true;
返回nodeptr;
}
mynode*搜索(无符号长整数,mynode*rootptr)
{
mynode*myptr;
myptr=rootptr;
而(((myptr->lchild)!=NULL)和((myptr->rchild)!=NULL))
{
如果(ivalval)
{
myptr=myptr->lchild;
}
其他的
{
myptr=myptr->rchild;
}
}
返回myptr;
}
void insert(无符号长整数,mynode*root)
{
mynode*当前;
mynode*leafptr;
我的节点*父亲;
无符号长整型最大值,最小值;
无符号长整数;
当前=搜索(ival,根);
num=当前->值;
如果((当前->值)=ival)
{
返回;
}
其他的
{
如果(ival>(当前->val))
{
max=ival;
最小值=当前值->值;
}
其他的
{
最大值=当前值->值;
min=ival;
}
父项=当前->父项;
当前=创建节点(最小,父节点);
如果(num==(父->子->值)
{
父->lchild=当前;
}
其他的
{
父->rchild=当前;
}
leafptr=createLeaf(最小,当前);
当前->lchild=leafptr;
leafptr=createLeaf(最大,当前);
当前->rchild=leafptr;
返回;
}
}
我打开一个文件。数一数行数,因为我知道每行都有一个数字。使用上述信息创建一个数组。然后创建根和它的两个叶子。然后我将数组的其余部分插入到我的数据结构中(这里我得到了segmentantion fault)。我认为问题在于函数

此处的
节点
位于内存堆栈上,该堆栈将在函数退出时回收。您将返回一个指向您不拥有的内存的指针!您需要使用函数
malloc()
,如下所示:

mynode* nodeptr = malloc(sizeof(mynode));
这将在
nodeptr
将指向的堆上分配内存。在函数退出时不会回收此内存。要回收此内存,您需要调用
free()

此处的
节点
位于内存堆栈上,该堆栈将在函数退出时回收。您将返回一个指向您不拥有的内存的指针!您需要使用函数
malloc()
,如下所示:

mynode* nodeptr = malloc(sizeof(mynode));

这将在堆上分配
nodeptr
将指向的内存。此内存在函数退出时不会被回收。要回收此内存,您需要调用
free()

来彻底解决太多的错误和问题

让我们看一个适当的示例,它带有错误检查,以Graphviz点格式输出生成的二叉搜索树

首先,您希望将指针保持在结构的开头,因为它们是最常用的,并且需要正确对齐。(如果不先放置最大的成员,编译器可能会在结构中插入填充,从而浪费内存。不,编译器不允许在C中对结构成员重新排序,因此它无法为您执行此操作。)

接下来,您需要一个将节点插入树中的函数。树本身只是其根成员的句柄,由于新节点可以是新根,我们需要传递指向根元素指针的指针:

void insert_node(struct node **root, struct node *leaf)
{
    struct node *parent;

    /* Make sure we have a pointer to the root pointer, and a leaf node. */
    if (!root) {
        fprintf(stderr, "insert_node(): root == NULL!\n");
        exit(EXIT_FAILURE);
    }
    if (!leaf) {
        fprintf(stderr, "insert_node(): leaf == NULL!\n");
        exit(EXIT_FAILURE);
    }

    /* Make sure leaf pointers are all NULL. */
    leaf->parent = NULL;
    leaf->left = NULL;
    leaf->right = NULL;
上面的代码只是健全性检查,但我想包含它们以确保完整性。无论如何,如果树为空,则根指针指向空指针,即
*root==NULL
。在这种情况下,
是树中的新(唯一)节点:

    /* Is this a new root node? */
    if (!*root) {
        /* Yes. */
        *root = leaf;
        return;
    }
否则,我们需要下降到树中。我决定left的意思是“小于或等于”,因为这很容易记住。如果我们向左走,父节点的左节点为空,这就是我们放置新叶节点的位置。类似地,如果我们向右走,父节点的右节点为空,我们将叶放在那里。否则我们将
void insert_node(struct node **root, struct node *leaf)
{
    struct node *parent;

    /* Make sure we have a pointer to the root pointer, and a leaf node. */
    if (!root) {
        fprintf(stderr, "insert_node(): root == NULL!\n");
        exit(EXIT_FAILURE);
    }
    if (!leaf) {
        fprintf(stderr, "insert_node(): leaf == NULL!\n");
        exit(EXIT_FAILURE);
    }

    /* Make sure leaf pointers are all NULL. */
    leaf->parent = NULL;
    leaf->left = NULL;
    leaf->right = NULL;
    /* Is this a new root node? */
    if (!*root) {
        /* Yes. */
        *root = leaf;
        return;
    }
    /* Find the parent node where leaf belongs. */
    parent = *root;
    while (1)
        if (parent->value >= leaf->value) {
            if (parent->left) {
                parent = parent->left;
                continue;
            }

            /* This belongs at parent->left. */
            parent->left = leaf;
            leaf->parent = parent;
            return;

        } else {
            if (parent->right) {
                parent = parent->right;
                continue;
            }

            /* This belongs at parent->right. */
            parent->right = leaf;
            leaf->parent = parent;
            return;
        }
}
static void dot_recurse(FILE *out, struct node *one)
{
    fprintf(out, "    \"%p\" [ label=\"%.3f\" ];\n", (void *)one, one->value);

    if (one->parent)
        fprintf(out, "    \"%p\" -> \"%p\";\n", (void *)one, (void *)(one->parent));

    if (one->left) {
        dot_recurse(out, one->left);
        fprintf(out, "    \"%p\" -> \"%p\" [ label=\"≤\" ];\n", (void *)one, (void *)(one->left));
    }

    if (one->right) {
        dot_recurse(out, one->right);
        fprintf(out, "    \"%p\" -> \"%p\" [ label=\">\" ];\n", (void *)one, (void *)(one->right));
    }
}

void dot(FILE *out, struct node *tree)
{
    if (out && tree) {
        fprintf(out, "digraph {\n");
        dot_recurse(out, tree);
        fprintf(out, "}\n");
    }
}
int main(void)
{
    struct node *tree = NULL;
    double       value;

    while (scanf(" %lf", &value) == 1)
        insert_node(&tree, new_node(value));

    /* Dump tree in DOT format. Use Graphviz to visualize the output. */
    dot(stdout, tree);

    return EXIT_SUCCESS;
}
4.695 5.108 3.518 4.698 8.496
7.956 9.435 5.341 0.583 7.074
7.661 5.966 0.557 4.332 1.436
6.170 7.936 4.630 7.694 0.220
digraph {
    "0x13dd020" [ label="4.695" ];
    "0x13dd080" [ label="3.518" ];
    "0x13dd080" -> "0x13dd020";
    "0x13dd1a0" [ label="0.583" ];
    "0x13dd1a0" -> "0x13dd080";
    "0x13dd260" [ label="0.557" ];
    "0x13dd260" -> "0x13dd1a0";
    "0x13dd3b0" [ label="0.220" ];
    "0x13dd3b0" -> "0x13dd260";
    "0x13dd260" -> "0x13dd3b0" [ label="≤" ];
    "0x13dd1a0" -> "0x13dd260" [ label="≤" ];
    "0x13dd2c0" [ label="1.436" ];
    "0x13dd2c0" -> "0x13dd1a0";
    "0x13dd1a0" -> "0x13dd2c0" [ label=">" ];
    "0x13dd080" -> "0x13dd1a0" [ label="≤" ];
    "0x13dd290" [ label="4.332" ];
    "0x13dd290" -> "0x13dd080";
    "0x13dd350" [ label="4.630" ];
    "0x13dd350" -> "0x13dd290";
    "0x13dd290" -> "0x13dd350" [ label=">" ];
    "0x13dd080" -> "0x13dd290" [ label=">" ];
    "0x13dd020" -> "0x13dd080" [ label="≤" ];
    "0x13dd050" [ label="5.108" ];
    "0x13dd050" -> "0x13dd020";
    "0x13dd0b0" [ label="4.698" ];
    "0x13dd0b0" -> "0x13dd050";
    "0x13dd050" -> "0x13dd0b0" [ label="≤" ];
    "0x13dd0e0" [ label="8.496" ];
    "0x13dd0e0" -> "0x13dd050";
    "0x13dd110" [ label="7.956" ];
    "0x13dd110" -> "0x13dd0e0";
    "0x13dd170" [ label="5.341" ];
    "0x13dd170" -> "0x13dd110";
    "0x13dd1d0" [ label="7.074" ];
    "0x13dd1d0" -> "0x13dd170";
    "0x13dd230" [ label="5.966" ];
    "0x13dd230" -> "0x13dd1d0";
    "0x13dd2f0" [ label="6.170" ];
    "0x13dd2f0" -> "0x13dd230";
    "0x13dd230" -> "0x13dd2f0" [ label=">" ];
    "0x13dd1d0" -> "0x13dd230" [ label="≤" ];
    "0x13dd200" [ label="7.661" ];
    "0x13dd200" -> "0x13dd1d0";
    "0x13dd320" [ label="7.936" ];
    "0x13dd320" -> "0x13dd200";
    "0x13dd380" [ label="7.694" ];
    "0x13dd380" -> "0x13dd320";
    "0x13dd320" -> "0x13dd380" [ label="≤" ];
    "0x13dd200" -> "0x13dd320" [ label=">" ];
    "0x13dd1d0" -> "0x13dd200" [ label=">" ];
    "0x13dd170" -> "0x13dd1d0" [ label=">" ];
    "0x13dd110" -> "0x13dd170" [ label="≤" ];
    "0x13dd0e0" -> "0x13dd110" [ label="≤" ];
    "0x13dd140" [ label="9.435" ];
    "0x13dd140" -> "0x13dd0e0";
    "0x13dd0e0" -> "0x13dd140" [ label=">" ];
    "0x13dd050" -> "0x13dd0e0" [ label=">" ];
    "0x13dd020" -> "0x13dd050" [ label=">" ];
}