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

Patricia/Radix树单词插入功能异常程序崩溃求助

Patricia/Radix树实现崩溃问题排查

项目背景与预期效果

正在完成大学课程项目,用C语言实现Patricia/Radix树,功能为读取文本文件中每行的单词并插入树中。例如读取包含"roman"、"romance"、"romantic"的文件时,预期树结构如下:

(root)
      |
    roman$
   /     \
 ce$      tic$

当前运行异常情况

已添加检查点跟踪程序执行进度,崩溃前输出如下:

checkpoint 1
checkpoint 2
checkpoint 3 roman
checkpoint 4 roman
checkpoint 5
checkpoint 5

检查点1-4对应文件读取和单词验证逻辑,运行正常,之后程序崩溃。

相关代码

结构体定义

typedef struct no no; // 结构体声明

typedef struct no {
    char *str; // 存储字符串的指针
    struct no *child[26]; // 指向所有可能子节点的指针数组
    int isword; // 标记是否为完整单词
    int isroot; // 标记是否为树根节点
} tree;

插入函数

no* InsertWord(no *r, char *str){
    printf("checkpoint 5 %s\n", str);
    // 情况1:当前节点是根节点
    if(r->isroot){
        r->child[r->str[0] - 'a'] = InsertWord(r->str[r->str[0] - 'a'], str);
        return r;
    }
    // 情况2:找到空节点
    if(r->str == NULL){
        strcpy(r->str, str);
        r->isword = 1;
        printf("word %s inserted\n", str);
        return r;
    }
    // 情况3:单词与前缀完全匹配
    if(strcmp(r->str, str)){
        r->isword = 1;
        printf("word %s inserted\n", str);
        return r;
    }
    int i;
    for(i = 0; str[i] == r->str[i]; i++);
    // 情况4:前缀匹配单词的前半部分,单词还有剩余部分需要插入
    if(i == strlen(r->str)){
        r->child[str[i] - 'a'] = InsertWord(r->child[str[i] - 'a'], str + i);
        return r;
    }
    // 情况5:单词匹配前缀的前半部分,前缀还有剩余部分
    if(i == strlen(str)){
        char *aux1;
        char *aux2;
        strncpy(aux1, r->str, i);
        strcpy(aux2, r->str + i);
        no *aux = r;
        for(int j = 0; j < 26; j++){
            free(r->filhos[j]);
        }
        r->child[aux2[0] - 'a'] = aux;
        strcpy(r->str, aux1);
        strcpy(r->child[aux2[0] - 'a'], aux2);
        return r;
    }
    // 情况6:单词和前缀的前半部分匹配,但后续内容不同
    if(i < strlen(str) && i < strlen(r->str)){
        char *aux1;
        char *aux2;
        strncpy(aux1, r->str, i);
        strcpy(aux2, r->str + i);
        no *aux = r;
        for(int j = 0; j < 26; j++){
            free(r->child[j]);
        }
        r->child[aux2[0] - 'a'] = aux;
        strcpy(r->str, aux1);
        strcpy(r->child[aux2[0] - 'a'], aux2);
        r->child[str[i] - 'a'] = InsertWord(r->child[str[i] - 'a'], str + i);
        return r;
    }
}

文件读取与验证函数

no *ValidateWord(no *r, char *str) {
    int i;
    printf("checkpoint 3 %s\n", str);
    for (i = 0; str[i] != '\0'; i++) {
        if (str[i] < 'A' || (str[i] > 'Z' && str[i] < 'a') || str[i] > 'z') {
            return r;
        } else if (str[i] >= 'A' && str[i] <= 'Z') {
            str[i] = str[i] + 32;
        }
    }
    printf("checkpoint 4 %s\n", str);
    return InsertWord(r, str);
}

no *LoadFile(no *r) {
    printf("checkpoint 1");
    printf("Insert the name of the chosen file: ");
    char namefile[100];
    scanf("%s", namefile);
    FILE *fp1;
    fp1 = fopen(namefile, "r");
    if (fp1 == NULL) {
        printf("couldnt open the file.\n");
        return r;
    }
    char str[100];
    while (fgets(str, sizeof(str), fp1)) {
        printf("checkpoint 2 %s\n", str);
        str[strcspn(str, "\n")] = '\0';
        r = ValidateWord(r, str);
    }
    fclose(fp1);
    return r;
}

主函数与菜单

void menu(no* r) {
    int c = 0;
    printf("choose an operation:\n");
    printf("Load File - 1\nCheck Words - 2\nPrint Dictionary - 3\nLoad Stopwords File - 4\nExit - 0\n\n");
    scanf("%d", &c);
    while (c != 0) {
        if (c == 1)
            r = LoadFile(r); // 调用LoadFile函数
        else if (c == 2)
            CheckWords(r); // 调用CheckWords函数
        else if (c == 3)
            PrintDictionary(r); // 调用PrintDictionary函数
        else if (c == 4)
            r = LoadStopwordsFile(r); // 调用LoadStopwordsFile函数
        printf("choose an operation:\n");
        printf("Load File - 1\nCheck Words - 2\nPrint Dictionary - 3\nLoad Stopwords File - 4\nExit - 0\n\n");
        scanf("%d", &c);
    }
}

int main() {
    no* r = (no*) malloc(sizeof(no)); // 为根节点分配内存
    if (r == NULL) {
        printf("Error alocating memory.\n");
        return 1; // 退出程序
    }
    r->isroot = 1; // 设置根节点标记为真
    menu(&r); // 调用菜单函数
    free(r); // 释放根节点内存
    return 0;
}

问题排查请求

已尝试添加动态内存分配但未解决问题,无法确定崩溃原因,请求帮助排查。

内容的提问来源于stack exchange,提问作者Davi Franke

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.18 10:22:02