我的程序从文件中读取行并使用它构建树。从我的main
我调用函数loadFromFile
,它完成所有工作。此函数调用insert
方法,该方法又调用函数来比较字符串。这是使用的结构:
typedef struct Node {
char *key;
int count;
struct Node *left, *right;
} node;
这是loadFromFile
函数,它有两个参数,第一个是读取数据所需的文件地址,第二个是比较字符串的模式。正如您将注意到的,我使用printf
稍后向您显示输出:
node * loadFromFile(char * address, int mode){
FILE * file;
char * line_readed;
size_t len = 0;
ssize_t read;
node * new_node;
node * tmp = NULL;
file = fopen(address, "r");
if (file == NULL){
printf("File \"%s\" doesn't exist.\n", address);
exit(EXIT_FAILURE);
}
while ((read = getline(&line_readed, &len, file)) != -1) {
new_node = get_node();
line_readed[strlen(line_readed)-1] = 0;
new_node->key = line_readed;
printf("line readed: %s\n", line_readed);
if(tmp != NULL){
printf("- tmp->key: %s \n", tmp->key);
tmp = insert(tmp, new_node, mode);
}else{
tmp = new_node;
printf("- tmp->key: %s \n", tmp->key);
}
}
fclose(file);
printBST(tmp);
return tmp;
}
要创建新节点,使用函数get_node()
,其代码为:
node * get_node() {
node *temp;
temp = (node *) malloc(sizeof(node));
temp -> left = NULL;
temp -> right = NULL;
temp -> count = 1;
return temp;
}
插入的代码就是这个:
node * insert(node *root, node *new_node, int mode) {
int comparison;
if(mode){
comparison = my_strcmp(new_node->key, root->key);
if (comparison == -1){
if (root->left == NULL){
root->left = new_node;
}else
insert(root->left, new_node, mode);
}
else if (comparison == 1)
if (root->right == NULL){
root->right = new_node;
}else
insert(root->right, new_node, mode);
else{
root->count++;
}
}else{
comparison = my_strignorecasecmp(new_node->key, root->key);
if (comparison == -1){
if (root->left == NULL){
root->left = new_node;
}else
insert(root->left, new_node, mode);
}
else if (comparison == 1)
if (root->right == NULL){
root->right = new_node;
}else
insert(root->right, new_node, mode);
else{
root->count++;
}
}
return root;
}
最后但并非最不重要的是,打印BST的代码:
void printBST(node * root){
if(root != NULL){
printBST(root->left);
printf("%s\n",root->key);
printBST(root->right);
}
}
输出如下:
line readed: asddassdfgsdfgdfghx
- tmp->key: asddassdfgsdfgdfghx
line readed: bb
- tmp->key: bb
line readed: adassss
- tmp->key: adassss
line readed: zasx
- tmp->key: zasx
line readed: www
- tmp->key: www
www
我独立检查了比较字符串函数,它们工作得很好,所以我假设问题与指针有关,但是我无法看到它在哪里,或者如何解决它。应该是根的变量tmp
正在读取我阅读的行的所有值,我不明白为什么;也许是因为我来自JAVA这些东西对我来说有点不同。我不认为问题出在insert
或printBST
。
答案 0 :(得分:3)
您的问题归结为您使用getline()
:
getline()
查看传入的双指针并检查该地址是否有足够的空间(由len
参数指示)来存储下一行。如果传入NULL
指针的地址(或者当前缓冲区没有足够的空间用于下一行),它会自动尝试分配(更多)内存。
但是,在您的代码中,永远不会为line_readed
分配值:
char *line_readed;
此时line_readed
是一个未定义的指针,它可能指向任何地方。使用此指针的值是未定义的行为。
现在你在这个指针上调用getline()
。 getline()
将(可能,我们不知道)非NULL未定义line_readed
解释为指向剩余零容量的malloc()
内存的指针(自len == 0
起)。
因此它在未定义的指针上调用realloc()
。
所有投注都是从这里开始的。你在UB国家。
然而,可能发生的是getline()
为line_readed
分配新内存(然后释放旧指针,导致未定义的行为)。
值得注意的是,如果有足够的空间,getline()
首先会尝试写入您传入的地址。由于您的第一个密钥很长,因此缓冲区可能永远不需要在初始({1}}之后调整大小。
如果仔细观察,这也意味着,所有realloc()
引用都只会指向相同的内存位置,这也会被新数据重复覆盖。
如果在循环中打印node->key
的地址,它可能会在第一次迭代时发生变化,之后就不会发生变化。
您可以尝试使用
line_readed
将字符串从new_node->key = strdup(line_readed);
复制到新的内存位置,并将新地址填入line_readed
。
您还需要初始化
new_node->key
在创建每个节点后,也可以重置char *line_readed = NULL;
和len = 0;
,这几乎完全相同,但避免了字符串副本。
此外:不要忘记您需要显式和手动释放每个已分配的内存块。没有垃圾收集。这包括最后的line_readed = NULL;
,释放每个节点和每个节点的密钥(如果已分配)。