从TXT加载数据到二叉搜索树:打印异常及清空后段错误问题
二叉搜索树加载与内存管理问题解决
问题1:加载文件后打印仅显示一行数据
原因
loadAccountDat函数中只为email和password分配了单次内存空间,循环读取文件时,每次sscanf都会将新数据写入同一块内存,导致所有树节点的email和password指针都指向这两块重复内存。同时,插入节点时strcmp比较的是当前内存中的最新字符串内容,若后续行的email与树中节点的email内容判断为相等,不会创建新节点,最终树中仅保留最后一次插入的节点,打印时只显示一行。
解决方法
每次读取文件行时,为当前行的email和password单独分配内存并复制字符串内容,避免所有节点共享同一块内存:
- 使用
strdup(或手动malloc+strcpy)为每个节点的字段分配独立内存。
问题2:清空树后打印触发段错误
原因
clearAccount仅释放了树中节点的内存,但全局变量accountRoot未被置为NULL。打印时程序仍尝试访问已释放的内存(野指针),从而触发段错误。
解决方法
修改clearAccount为接收指针的指针,直接将根指针置空;或者在调用clearAccount后手动将accountRoot设为NULL。
修正后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct account { char *email; char *password; struct account *left; struct account *right; } account; account *insertAccount(account *root, char *email, char *password); account *createAccountNode(char *email, char *password); account *loadAccountDat(void); void clearAccount(account **root); void printAccountTree(account *root); // 补充实现原代码缺失的checkAccountFile函数 int checkAccountFile(void) { FILE *f = fopen("account.txt", "r"); if (!f) return 1; fclose(f); return 0; } // Account bintree account *accountRoot = NULL; int main(void) { accountRoot = loadAccountDat(); printAccountTree(accountRoot); clearAccount(&accountRoot); printAccountTree(accountRoot); // 此时root为NULL,不会触发错误 } account *createAccountNode(char *email, char *password) { account *newNode = (account *) malloc(sizeof(account)); // 为每个节点的email和password分配独立内存并复制内容 newNode->email = strdup(email); newNode->password = strdup(password); newNode->left = NULL; newNode->right = NULL; return newNode; } account *insertAccount(account *root, char *email, char *password) { if(root == NULL) { return createAccountNode(email, password); } int cmp = strcmp(email, root->email); if(cmp < 0) { root->left = insertAccount(root->left, email, password); } else if(cmp > 0) { root->right = insertAccount(root->right, email, password); } // 若email已存在,默认跳过插入 return root; } // 修改为接收指针的指针,直接将根指针置空 void clearAccount(account **root) { if(*root == NULL) { return; } clearAccount(&(*root)->left); clearAccount(&(*root)->right); // 先释放节点内的字符串内存,再释放节点本身 free((*root)->email); free((*root)->password); free(*root); *root = NULL; // 将根指针置空 } // For testing void printAccountTree(account *root) { if(root == NULL) { return; } printAccountTree(root->left); printf("%s || %s\n", root->email, root->password); printAccountTree(root->right); } account *loadAccountDat(void) { if(checkAccountFile() == 1) { return NULL; } account *root = NULL; FILE *f = fopen("account.txt", "r"); char buffer[255]; // Scan every line in file and put into binary tree while(fgets(buffer, 255, f)) { char email[25], password[25]; // 使用栈上缓冲区临时存储数据,避免重复malloc sscanf(buffer, "%[^;];%[^\n]", email, password); root = insertAccount(root, email, password); } fclose(f); return root; }
内容的提问来源于stack exchange,提问作者Darryl _
相关产品推荐
相关产品推荐

