C 二叉搜索树中的分段错误(核心转储)
我正在尝试实现一个r&b树,但首先我想要一个简单的二叉树(它不在叶子上保存内容),然后实现r&b属性。问题是我犯了无法解释的错误 计划如下: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;
#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=">" ];
}