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

从链表构建BST时程序崩溃,求问题排查帮助

问题分析与修复方案

咱们一步步拆解你代码里导致崩溃的核心问题,还有一些潜在的逻辑漏洞:

1. 全局root未被正确初始化(直接触发崩溃)

你的TransferToBST函数参数里的root是局部变量,函数内部对它的修改不会影响全局的root变量。初始全局root是NULL,执行TransferToBST(root,head)后,全局root依然是NULL,之后main里访问root->right就会触发空指针引用,直接导致程序崩溃。

修复方式:
让TransferToBST返回修改后的root,再赋值给全局变量:

BSTnode* TransferToBST(node* head) {
    BSTnode* root = NULL;
    while (head != NULL) {  // 遍历所有节点,包括最后一个
        root = BSTinsert(root, head);
        head = head->next;
    }
    return root;
}

然后在main里更新调用逻辑:

root = TransferToBST(head);

2. TransferToBST循环条件错误,漏掉最后一个节点

原来的while (head->next!=NULL)只会处理到倒数第二个节点,最后一个节点会被跳过。改成while (head != NULL)才能遍历链表中所有节点。

3. BSTinsert未处理重复单词,且未利用head2存储文件路径

你的BSTnode里的head2设计是用来存储同一个单词的所有文件路径,但当前BSTinsert只会新建节点,不会判断单词是否已存在。如果遇到重复单词,应该把文件路径添加到head2链表中,而不是新建BST节点,否则会导致BST结构混乱。

修复后的BSTinsert:

BSTnode* BSTinsert(BSTnode* root, node* data) {
    if(root == NULL) {
        BSTnode* new_node = (BSTnode*)malloc(sizeof(BSTnode));
        strcpy(new_node->word, data->word);
        new_node->left = NULL;
        new_node->right = NULL;
        // 初始化head2链表,存入当前文件路径
        new_node->head2 = (node*)malloc(sizeof(node));
        strcpy(new_node->head2->FileName, data->FileName);
        new_node->head2->next = NULL;
        return new_node;
    } 
    int cmp_result = strcmp(data->word, root->word);
    if (cmp_result > 0) {
        root->right = BSTinsert(root->right, data);
    } else if (cmp_result < 0) {
        root->left = BSTinsert(root->left, data);
    } else {
        // 单词已存在,将文件路径追加到head2链表
        node* new_file_node = (node*)malloc(sizeof(node));
        strcpy(new_file_node->FileName, data->FileName);
        new_file_node->next = root->head2;
        root->head2 = new_file_node;
    }
    return root;
}

4. insert函数存在内存泄漏

原insert函数中额外malloc的temp只是用来遍历链表,最后未释放,造成内存泄漏。同时初始化头节点时无需额外malloc,直接复用已创建的节点即可:

void insert(char string[], char* file1) {
    node* a = (node*)malloc(sizeof(node));
    strcpy(a->word, string);
    strcpy(a->FileName, file1);
    a->next = NULL;

    if (head == NULL) {
        head = a; // 直接用a作为头节点,避免多余malloc
    } else {
        node* temp = head;
        while (temp->next != NULL) {
            temp = temp->next;
        }
        temp->next = a;
    }
}

5. linebyline中feof使用错误

feof(ptr)只有在读取到文件末尾后才会返回真,原逻辑会导致fgets读取失败后仍执行i++,产生无效的空行。同时别忘了检查文件是否打开成功,以及读取完成后关闭文件:

void linebyline(char* file1) {
    int i = 0;
    char sample[1000][1000];
    FILE* ptr = fopen(file1, "r");
    if (ptr == NULL) { // 检查文件是否打开成功
        printf("Failed to open file: %s\n", file1);
        return;
    }
    // 用fgets的返回值判断读取是否成功
    while (fgets(sample[i], 1000, ptr) != NULL) {
        i++;
    }
    for (int j = 0; j < i; j++) {
        word(sample[j], file1);
    }
    fclose(ptr); // 关闭文件,避免资源泄漏
}

6. word函数的逻辑漏洞

原函数未处理字符串末尾的单词,且没有统一单词大小写(会导致Hello和hello被视为不同单词),优化后的版本:

void word(char s1[], char* file1) {
    char a[100];
    int i, j = 0;
    int length = strlen(s1);
    for (i = 0; i < length; i++) {
        if (!((s1[i] >= 'a' && s1[i] <= 'z') || (s1[i] >= 'A' && s1[i] <= 'Z'))) {
            if (j > 0) { // 仅当a中有有效字符时才插入
                a[j] = '\0';
                // 统一转小写,消除大小写差异
                for (int k = 0; a[k] != '\0'; k++) {
                    if (a[k] >= 'A' && a[k] <= 'Z') {
                        a[k] += 32;
                    }
                }
                insert(a, file1);
                j = 0;
            }
        } else {
            a[j] = s1[i];
            j++;
            if (j >= 99) { // 防止数组越界
                a[j] = '\0';
                insert(a, file1);
                j = 0;
            }
        }
    }
    // 处理字符串末尾的剩余单词
    if (j > 0) {
        a[j] = '\0';
        for (int k = 0; a[k] != '\0'; k++) {
            if (a[k] >= 'A' && a[k] <= 'Z') {
                a[k] += 32;
            }
        }
        insert(a, file1);
    }
}

最后修复后的main函数

int main() {
    readAllFiles("m");
    root = TransferToBST(head);
    // 先检查root是否非空,避免空指针访问
    if (root != NULL) {
        // 示例:遍历右子树测试
        BSTnode* temp = root;
        while (temp != NULL) {
            printf("%s\n", temp->word);
            temp = temp->right;
        }
    } else {
        printf("BST is empty!\n");
    }
    // 可选:添加内存释放逻辑,避免长期运行内存泄漏
    // freeLinkedList(head);
    // freeBST(root);
    return 0;
}

把这些问题逐一修复后,程序应该就能正常运行且逻辑更完整了。

内容的提问来源于stack exchange,提问作者Mahdi Ghajary

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.15 08:46:09