这是BST NODE
struct BST_node{
char *name1;
char *data1;
struct BST_node* left;
struct BST_node* right;
};
struct BST_node* Insert(struct BST_node *rootptr, datatype_t *d){
if(rootptr == NULL){
char name[66];
char data[1466];
rootptr = (struct BST_node*)malloc(sizeof(struct BST_node));
rootptr->name1 = d->name;
rootptr->data1 = d->data;
printf("%s 1\n", rootptr->name1);
rootptr->left = rootptr->right = NULL;
}
if(strcmp(rootptr->name1, d->name) < 0){
printf("%s left", rootptr->name1);
rootptr->left = Insert(rootptr -> left, d);
}
else if(strcmp(rootptr->name1, d->name) > 0){
printf("right\n");
rootptr->right = Insert(rootptr -> right, d);
}
else if(strcmp(rootptr->name1, d->name)==0){
printf("duplicate\n");
}
return rootptr;
}
所以我使用文件ptrs扫描CSV文件并从datatype_d读取数据。 示例这是CSV文件中的数据。 “名称,数据。”
这是我在csv文件中读取并从main函数调用Insert函数的方法。
int main(int argc, char** argv)
{
char* eq_csv_file = NULL;
char* eq_csv_file1 = NULL;
char* read_mode="r";
char* write_mode="w+";
struct BST_node* root = NULL;
int index = 0;
if(argv[1]!=NULL && argv[2] != NULL )
{
eq_csv_file=argv[1];
eq_csv_file1 = argv[2];
}
else
{
return EXIT_FAILURE;
}
FILE* Data_input = safe_open_file(eq_csv_file,read_mode);
FILE* Data_output = safe_open_file(eq_csv_file1, write_mode);
datatype_t **earth = (datatype_t**)malloc(MAX_NUM_LINE*sizeof(datatype_t *));
datatype_t *earth_one = read(Data_input);
while((earth_one) != NULL)
{
earth[index] = earth_one;
if(root != NULL){
printf("%s\n", (root->name1));
}
root = Insert(root, earth[index]);
index++;
earth_one= read(Data_input);
}
现在,当我运行此代码以检查其是否正常工作时,它会打印出来自csv文件中除第一个数据之外的所有数据的Duplicate。我根本不知道我在哪里犯了错误并更改了rootptr并使其等于datatype_d,以便在检查strcmp时它的打印重复。
一个例子就是我从CSV文件中读到这个。
所以我想将这些插入到BST中,但由于某种原因,它不能跟踪头节点“Dave”。它永远不会转到左边或右边的子树,而是说当我使用strcmp时它们是重复的。
这是输出:
戴夫1
约翰
复制
分段故障:11
这是我读取的代码,我从main函数调用来读取csv文件。
read(FILE* fp)
{
char name[65];
char data[1465];
if (fscanf(fp, "%[^,] %[^\n]", name, data) == 2) {
datatype_t *d = (datatype_t*)malloc(sizeof(datatype_t));
d->name = name;
d->data = data;
return d;
}
return NULL;
}
答案 0 :(得分:3)
此代码有效。主要更改是确保在设置根节点后立即返回。 (请注意,在您的跟踪中,您会被告知您插入的第一个节点是“重复的” - 因为您没有提前返回。)我使用了{{ 1}}在后续的else
语句中,而不是添加额外的if
,但这也可以。
return rootptr;
示例运行:
#include <assert.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct datatype_t
{
char *name;
char *data;
} datatype_t;
struct BST_node
{
char *name1;
char *data1;
struct BST_node *left;
struct BST_node *right;
};
struct BST_node *Insert(struct BST_node *rootptr, datatype_t *d);
struct BST_node *Insert(struct BST_node *rootptr, datatype_t *d)
{
if (rootptr == NULL)
{
rootptr = (struct BST_node *)malloc(sizeof(struct BST_node));
rootptr->name1 = d->name;
rootptr->data1 = d->data;
printf("%s 1\n", rootptr->name1);
rootptr->left = rootptr->right = NULL;
}
else if (strcmp(rootptr->name1, d->name) < 0)
{
printf("%s left\n", rootptr->name1);
rootptr->left = Insert(rootptr->left, d);
}
else if (strcmp(rootptr->name1, d->name) > 0)
{
printf("right\n");
rootptr->right = Insert(rootptr->right, d);
}
else
{
assert(strcmp(rootptr->name1, d->name) == 0);
printf("duplicate\n");
}
return rootptr;
}
static void BST_print_inorder(const char *tag, struct BST_node *node)
{
if (tag != NULL)
printf("%s:\n", tag);
if (node != NULL)
{
BST_print_inorder(NULL, node->left);
printf("%s (%s)\n", node->name1, node->data1);
BST_print_inorder(NULL, node->right);
}
}
int main(void)
{
datatype_t earth[] =
{
{ "Dave", "Studying at UCLA" },
{ "John", "Works at Google" },
{ "Mike", "School teacher" },
};
enum { NUM_LINES = sizeof(earth) / sizeof(earth[0]) };
struct BST_node *root = NULL;
for (int index = 0; index < NUM_LINES; index++)
{
if (root != NULL)
printf("Root node: %s\n", (root->name1));
root = Insert(root, &earth[index]);
BST_print_inorder("Insert complete", root);
}
return 0;
}
您无法承担打印功能,并且在您知道一切正常工作之前,您无法在插入循环的每次迭代中调用它。
使用valgrind
运行可以为内存访问提供一个干净的健康状况。我没有写过无树功能。
请注意,此代码避免了必须担心如何分配名称和数据值,因为它们是初始化数组的一部分。但是,在你的真实&#39;代码,您需要确保每个名称和数据值都有自己的内存。
如果您在此之后仍然崩溃,那么您需要仔细查看Dave 1
Insert complete:
Dave (Studying at UCLA)
Root node: Dave
Dave left
John 1
Insert complete:
John (Works at Google)
Dave (Studying at UCLA)
Root node: Dave
Dave left
John left
Mike 1
Insert complete:
Mike (School teacher)
John (Works at Google)
Dave (Studying at UCLA)
代码或其他支持代码。
请注意,read()
不是在类Unix系统上使用的好函数名称;还有一个read()
系统调用。链接器将为您排序,以便库代码可以工作,但如果您的任何代码使用read()
期望系统调用,那么获取您的函数将会感到惊讶。
read()
read()
功能已发布为:
read()
您返回一个已分配的数据结构,但结构中包含的两个字符串是指向局部变量datatype_t *read(FILE* fp)
{
char name[65];
char data[1465];
if (fscanf(fp, "%[^,] %[^\n]", name, data) == 2) {
datatype_t *d = (datatype_t*)malloc(sizeof(datatype_t));
d->name = name;
d->data = data;
return d;
}
return NULL;
}
和name
的指针,一旦函数退出,它们就不再有效。你需要复制字符串。
此外,data
格式有点好奇。它没有单独读取逗号,因此逗号被解析为第二个扫描集的一部分。格式中的空白意味着“跳过可选的空白区域”,当然。因此,当第一个扫描集停在逗号处时,空白不会改变任何内容,然后从逗号开始直到换行符的数据被读入fscanf()
。此外,第二个和后续名称以换行符开头。您需要一个格式字符串,如:
data
扫描集," %[^,], %[^\n]"
和%c
转换规范是唯一不会跳过前导空格的规范。
例如:
%n
(注意:用于交互式使用的datatype_t *read(FILE* fp)
{
char name[65];
char data[1465];
if (fscanf(fp, " %[^,], %[^\n]", name, data) == 2) {
datatype_t *d = (datatype_t*)malloc(sizeof(datatype_t));
d->name = strdup(name);
d->data = strdup(data);
return d;
}
return NULL;
}
- 系列格式字符串中的尾随空格是一种可用性灾难 - 永远不会使用它。)
修改主要使用修改后的scanf()
:
read()
int main(void)
{
datatype_t *earth;
struct BST_node *root = NULL;
while ((earth = read(stdin)) != NULL)
{
if (root != NULL)
printf("Root node: %s\n", (root->name1));
root = Insert(root, earth);
BST_print_inorder("Insert complete", root);
}
BST_free(root);
return 0;
}
是:
BST_free()
static void BST_free(struct BST_node *node)
{
if (node != NULL)
{
BST_free(node->left);
BST_free(node->right);
free(node->name1);
free(node->data1);
free(node);
}
}
的上一代码中存在内存泄漏 - 实际上是其中两个。一个是针对每个添加的节点; Insert()
结构在应该没有释放时(但成员仍在使用中;它们已被转移到树中)。另一个是发现重复的时候;那么新的数据成员也需要被释放。
我还修改了datatype_t
以模拟问题代码的作用。
main()
...
struct BST_node *Insert(struct BST_node *rootptr, datatype_t *d)
{
if (rootptr == NULL)
{
rootptr = (struct BST_node *)malloc(sizeof(struct BST_node));
rootptr->name1 = d->name;
rootptr->data1 = d->data;
rootptr->left = rootptr->right = NULL;
printf("%s 1\n", rootptr->name1);
free(d);
}
else if (strcmp(rootptr->name1, d->name) < 0)
{
printf("%s left\n", rootptr->name1);
rootptr->left = Insert(rootptr->left, d);
}
else if (strcmp(rootptr->name1, d->name) > 0)
{
printf("right\n");
rootptr->right = Insert(rootptr->right, d);
}
else
{
assert(strcmp(rootptr->name1, d->name) == 0);
free(d->name);
free(d->data);
free(d);
printf("duplicate\n");
}
return rootptr;
}
使用以下命令在Mac OS X 10.11.6的GCC 6.1.0下完全编译:
int main(void)
{
struct BST_node *root = NULL;
enum { MAX_NUM_LINE = 1000 };
datatype_t **earth = (datatype_t **)malloc(MAX_NUM_LINE * sizeof(datatype_t *));
assert(earth != NULL);
datatype_t *earth_one;
size_t index = 0;
while ((earth_one = read(stdin)) != NULL)
{
earth[index] = earth_one;
if (root != NULL)
printf("Root node: %s\n", (root->name1));
root = Insert(root, earth[index]);
BST_print_inorder("Insert complete", root);
index++;
assert(index < MAX_NUM_LINE);
}
printf("%zu nodes\n", index);
BST_free(root);
free(earth);
return 0;
}
它在valgrind
下完全运行。
我使用了两个数据文件:
$ gcc -O3 -g -std=c11 -Wall -Wextra -Werror -Wmissing-prototypes -Wstrict-prototypes \
> -Wold-style-definition ll23.c -o ll23
$
:
data.1
Dave, Studying at UCLA
John, Works at Google
Mike, School teacher
:
data.2