基于链表实现文本词频统计的C语言代码问题求助
问题描述
需求:读取文本文件,不区分大小写统计每个单词的出现次数(如tall、TALL、tAlL视为同一单词),需用链表实现。现有代码基于链表实现时出现重复单词统计错误,具体情况如下:
- 实现思路:用大小为100的
char buffer[N]逐词读取文件,检查单词是否已存在于链表中:存在则计数+1,不存在则添加新节点并将计数设为1。 - 测试文本内容:
Mi illumino di immenso Illumino di immenso Di immenso IMMENSO
- 当前错误输出:
Mi->1 illumino->2 di->3 immenso->3 immenso->13435072
- 期望输出(不要求排序):
immenso 4 di 3 illumino 2 Mi 1
代码问题排查
原代码存在以下核心错误:
- 链表遍历遗漏最后一个节点:原代码
while(p->next != NULL)的循环条件,导致遍历到链表最后一个节点时直接退出,无法检查该节点的单词是否匹配,这是重复单词出现的主要原因。 - 节点
instance未初始化:创建新节点tmp时仅分配内存,未给instance赋值,导致未初始化节点出现垃圾数值(如输出中的13435072)。 - 匹配成功后未释放冗余内存:每次循环一开始就为
tmp分配内存,若找到已有单词,新分配的节点未被释放,造成内存泄漏。 - 新增节点逻辑错误:原代码在新增节点时错误修改
p->instance,应给新节点tmp->instance赋值为1,再将tmp挂载到链表末尾。 - 文件打开逻辑冗余:
createlist函数接收FILE*参数但内部重新打开固定文件名的文件,且main函数传入的file是未初始化指针,逻辑混乱。
修复后的完整代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #define N 100 typedef struct node { char *str; int instance; struct node* next; } node; node *createlist(const char *filename) { node *tmp = NULL; node *head = NULL; node* p = NULL; char buffer[N+3]; int found; FILE *file = fopen(filename, "r"); if(file == NULL) { printf("Error opening file\n"); exit(1); } while(fscanf(file, "%s", buffer) != EOF) { found = 0; // 先遍历链表检查单词是否存在 p = head; while(p != NULL) { if(strcasecmp(p->str, buffer) == 0) { p->instance++; found = 1; break; } p = p->next; } if(found == 1) { continue; // 存在则跳过创建新节点 } // 不存在则创建新节点 tmp = malloc(sizeof(node)); if(tmp == NULL) { printf("Allocation error\n"); exit(1); } tmp->str = malloc((strlen(buffer)+1)*sizeof(char)); if(tmp->str == NULL) { printf("Allocation error\n"); free(tmp); // 释放已分配的节点内存 exit(2); } strcpy(tmp->str, buffer); tmp->instance = 1; // 初始化计数为1 tmp->next = NULL; // 将新节点添加到链表末尾 if(head == NULL) { head = tmp; } else { p = head; while(p->next != NULL) { p = p->next; } p->next = tmp; } } fclose(file); return head; } void printlist(node *head) { node* tmp = head; while(tmp != NULL) { printf("%s -> %d\n", tmp->str, tmp->instance); tmp = tmp->next; } } // 新增:释放链表内存,避免泄漏 void freelist(node *head) { node *tmp; while(head != NULL) { tmp = head; head = head->next; free(tmp->str); free(tmp); } } int main() { node *head = NULL; head = createlist("file"); printlist(head); freelist(head); // 释放内存 return 0; }
修复说明
- 调整遍历逻辑:改为
while(p != NULL),确保所有节点都被检查到。 - 调整节点创建时机:先检查链表,确认不存在后再创建新节点,避免不必要的内存分配。
- 初始化
instance:新节点创建时明确设置tmp->instance = 1。 - 修复文件打开逻辑:
createlist接收文件名参数,由内部打开并关闭文件,避免指针混乱。 - 新增内存释放函数:避免程序退出时的内存泄漏。
内容的提问来源于stack exchange,提问作者Severjan Lici
相关产品推荐
相关产品推荐

