C语言文本词频统计出错求助:重复统计单词问题排查
大小写不敏感单词计数程序的错误分析与修复
需求与现状
- 需求:统计文本文件中每个单词的出现次数,大小写不敏感(如"immenso"和"IMMENSO"视为同一单词)
- 输入文本:
Mi illumino di immenso Illumino di immenso Di immenso IMMENSO - 预期输出:
immenso 4 di 3 illumino 2 Mi 1 - 当前错误输出:
Mi 1 illumino 2 di 3 immenso 4 Illumino 1 di 2 immenso 3 Di 1 immenso 2 IMMENSO 1
问题原因分析
原代码的核心逻辑存在三处关键错误:
- 遍历判断逻辑混乱:读取新单词后,遍历已存储单词时,只要遇到一个不匹配的条目就直接将新单词添加到数组末尾,完全忽略后续可能存在的匹配项,导致同一单词被重复添加。
- 未统一大小写基准:直接存储原始单词,仅靠
stricmp做比较,既无法保证输出形式统一,也容易因遍历逻辑错误导致重复统计。 - 无条件递增计数:每次循环后都执行
n++,即使找到匹配项也会新增无效条目,进一步加剧重复统计问题。
解决方法与修正代码
修复要点
- 将所有读取到的单词转换为统一大小写(如全小写),作为存储和比较的基准,彻底解决大小写不敏感问题。
- 遍历已存储单词时,先用标记位记录是否找到匹配项,遍历结束后再决定是计数加1还是新增条目。
- 仅在新增单词条目时递增
n,避免无效计数。 - 可选:添加排序逻辑,让输出顺序与预期一致。
修正后的代码
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define N 100 typedef struct words { int iteration; char word[N]; } word_s; // 将字符串转换为全小写 void to_lower(char *str) { while (*str) { *str = tolower((unsigned char)*str); str++; } } int main() { FILE *file = fopen("file", "r"); if (file == NULL) { printf("Error opening file\n"); exit(1); } word_s v[N]; int n = 0; // 已存储的单词数量 char str[N]; while (fscanf(file, "%s", str) != EOF) { to_lower(str); // 统一转换为全小写 int found = 0; // 遍历查找匹配的单词 for (int i = 0; i < n; i++) { if (strcmp(v[i].word, str) == 0) { v[i].iteration++; found = 1; break; // 找到后立即退出循环,避免无效遍历 } } // 未找到匹配项则新增条目 if (!found) { strcpy(v[n].word, str); v[n].iteration = 1; n++; } } // 按出现次数降序排序,匹配预期输出顺序 for (int i = 0; i < n - 1; i++) { for (int j = i + 1; j < n; j++) { if (v[i].iteration < v[j].iteration) { word_s temp = v[i]; v[i] = v[j]; v[j] = temp; } } } // 输出统计结果 for (int i = 0; i < n; i++) { printf("%s %d\n", v[i].word, v[i].iteration); } fclose(file); return 0; }
代码说明
to_lower函数:统一单词的大小写形式,从根源上避免大小写差异导致的重复统计。- 匹配检查逻辑:用
found标记位确保只有遍历完所有已存储单词后,才决定是否新增条目,彻底解决重复添加问题。 - 排序逻辑:通过冒泡排序按出现次数降序排列结果,与预期输出顺序一致(不需要可删除该部分)。
- 资源释放:添加
fclose(file)避免文件资源泄漏。
内容的提问来源于stack exchange,提问作者Severjan Lici
相关产品推荐
相关产品推荐

