You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

从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 _

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.13 03:35:19