使用C

时间:2016-09-12 02:28:17

标签: c string data-structures binary-search-tree strcmp

这是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;
}

1 个答案:

答案 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