我正在尝试编写二叉树程序,其中树的节点包含“库存”结构。 程序应该从txt文件中读取并将信息插入树中(按部件号排序)。
我遇到的问题是我无法弄清楚为什么print_inorder函数会导致我的程序崩溃。
这是我的代码:
#include "stdafx.h"
#include "stdafx.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
typedef struct inventory
{
char invName[36];
int invPartNo;
int invQOH;
float invUnitCost;
float invPrice;
}stock;
typedef struct btree {
void *data;
int key_value;
struct btree *left;
struct btree *right;
} tree_t;
//function definitions
struct btree *initTree();
void print_inventory(struct inventory *stuff);
void print_inorder(tree_t *tree);
struct inventory * ReadData(FILE *fptr);
struct btree *search(int key, struct btree *leaf);
struct btree *insert(struct btree *root, int x);
void readFromTxt(FILE *fp, struct btree *head);
int _tmain(int argc, _TCHAR* argv[])
{
//currently in initTree, the first node is empty (doesn't contain an inventory item) and has key_value 1
//need to set key_value to equal product code
struct btree *root;
root = initTree();
FILE *fp = fopen("input.txt", "r");
readFromTxt(fp, root);
print_inorder(root);
return 0;
}
//initialize tree
struct btree *initTree()
{
struct btree *temp = (struct btree*)malloc(sizeof btree);
temp->left = NULL;
temp->right = NULL;
temp->key_value = 1;
return temp;
}
//print inventory
void print_inventory(struct inventory *stuff)
{
printf("Name: %s\n", stuff->invName);
printf("Part Number: %.5d\n", stuff->invPartNo);//printf(“ %.9d”, x)
printf("Quantity on hand: %d\n", stuff->invQOH);
printf("Unit Cost: %0.2f\n", stuff->invUnitCost);
printf("Price %0.2f\n\n", stuff->invPrice);
}
//recursively print tree
void print_inorder(tree_t *tree)
{
if (tree != NULL) { //problem likely here
print_inorder(tree->left);
//printf("%d\n", tree->data);
//printf inventory values
if(tree->key_value != 1) //don''t print root
print_inventory((struct inventory *)tree->data);
print_inorder(tree->right);
}
}
//read user input to produce new leaf with inventory struct
struct inventory * ReadData(FILE *fptr)
{
struct inventory *temp = (struct inventory *)malloc(sizeof inventory);
if(fptr==stdin)
printf("Enter item name: ");
fscanf_s(fptr, "%s", temp->invName);
if(fptr==stdin)
printf("Enter item part number: ");
fscanf_s(fptr, "%d", &temp->invPartNo);
if(fptr==stdin)
printf("Enter item quantity on hand: ");
fscanf_s(fptr, "%d", &temp->invQOH);
if(fptr==stdin)
printf("Enter item unit cost: ");
fscanf_s(fptr, "%f", &temp->invUnitCost);
if(fptr==stdin)
printf("Enter item price: ");
fscanf_s(fptr, "%f", &temp->invPrice);
return temp;
}
//search tree
struct btree *search(int key, struct btree *leaf)
{
if(leaf != 0)
{
if(key == leaf->key_value)
return leaf;
else if(key < leaf->key_value)
return search(key, leaf->left);
else
return search(key, leaf->right);
}
}
//add to tree
struct btree *insert(struct btree *root, int x)
{
if(!root)
{
root=(struct btree*)malloc(sizeof(struct btree));
root->key_value = x;
root->left = NULL;
root->right = NULL;
return(root);
}
if(root->key_value > x)
root->left = insert(root->left,x);
else
{
if(root->key_value < x)
root->right = insert(root->right,x);
}
return(root);
}
void readFromTxt(FILE *fp, struct btree *head)
{
if( fp != NULL)
{
while(!feof(fp))
{
struct btree *tNode = (struct btree*)malloc(sizeof btree);
struct inventory *newNode = (struct inventory*)malloc(sizeof inventory);
fgets(newNode->invName, 100, fp);
fscanf(fp, " %d %d %f %f ", &newNode->invPartNo,&newNode->invQOH,&newNode->invUnitCost,&newNode->invPrice);
tNode->data = newNode;
tNode->key_value = newNode->invPartNo;
head->key_value++;
insert( head, tNode->key_value );
}
}
}
这是我试图读取的txt文件:
1/4 drive socket set
19343
6
38.55
43.25
Claw Hammer
13448
14
3.27
4.89
#2 Flat Blade Screwdriver
12488
24
.70
1.85
#2 Phillips Screwdriver
12455
17
0.81
2.00
#1 Phillips Screwdriver
12456
27
0.67
1.80
#1 Flat Blade Screwdriver
12489
36
.65
1.75
答案 0 :(得分:0)
您的代码中存在许多设计缺陷。
使用1的特殊键将虚拟节点保存为根(或头)。但稍后,您可以增加头部的键以跟踪项目计数。最后,在打印iventory数据时检查1的特殊键。由于密钥不再为1且虚拟头节点的库存数据为NULL
,因此您访问非法内存 - seg错误!
插入新节点时,实际上并未传递节点,只是键值。然后,您使用该ID和在没有库存数据的情况下在现场创建新节点。实际上,data
指针未初始化,甚至不保证为NULL
。
我知道虚拟节点意味着您永远不必更新头部,但这不是一个好的设计。相反,您应该从NULL
头开始,并在插入新节点时更新它。这通常通过将指针传递给指向节点的指针来完成。
请保持您的命名一致。当您旁边有一个新节点(名为newNode
)时,您不应该调用新的广告资源数据tNode
。另外,typedefs
是什么?您只能使用tree_t
一次。最好坚持使用struct btree
。
您阅读数据的方式也容易出错。例如,您读取最多100个字符到newNode->invName
的缓冲区,它只能容纳36个字符。灾难食谱。混合fscanf
和fgets
通常不是一个好主意,请不要使用feof
- 检查其他f
函数的返回值,看看你是否已经到了文件的末尾。
C中的内存不是垃圾回收。这意味着对于每个malloc
,应该有一个相应的free
。轻松分配 - 实际上分配太多 - 并在使用后尝试清理树。