使用struct与动态内存分配统计文本单词词频的代码问题咨询
代码存在的问题汇总
1. 核心逻辑错误
- 匹配到重复单词后直接
return count,会直接终止整个文件读取流程,仅能处理到第一个重复单词之前的内容,完全不符合统计全文件单词频率的需求。 - 该分支下没有释放临时申请的
lower内存,会直接造成内存泄漏。
2. 输入读取逻辑错误
fscanf读取到文件末尾时返回EOF(值为负,非0),当前while (fscanf(f_in, "%s", word))的判断条件会把文件结束也判定为真,进入死循环,应当改为while (fscanf(f_in, "%s", word) == 1),仅当成功读取到1个字符串时才进入循环。- 没有对
s数组的容量做边界判断,当单词数量超过数组最大长度时会发生数组越界写,触发内存溢出。
3. 未定义行为风险
tolower的入参需要强制转为unsigned char类型,否则遇到负值的扩展ASCII字符会触发未定义行为。- 新单词的
freq初始化直接用++操作,若s数组是栈上申请或malloc申请未初始化,初始值为随机值,统计结果完全错误,应当改为s[count].freq = 1。 - 当前
lower的字符串终止符完全依赖calloc初始化为0的特性,如果后续换成malloc没有手动补'\0',strcmp、strcpy操作都会触发未定义行为。
malloc与calloc的选择、内存释放规则
选型建议
- 如果你申请内存后需要内容默认初始化为0(比如字符串自动带终止符、计数变量初始为0),直接用
calloc更省心,不需要额外手动初始化。 - 如果你申请后会立即覆盖所有内存内容,不需要初始值,用
malloc性能略高(省去了批量清0的开销),本案例中你如果用malloc申请lower,需要在循环转小写后手动加lower[strlen(word)] = '\0'补字符串终止符。
释放时机
- 临时使用的动态内存(比如本案例中的
lower),在当前作用域内所有用到该内存的逻辑都执行完成后即可释放,本案例需要在匹配到重复单词的分支里,s[j].freq++之后先加free(lower),再return,避免泄漏。 - 存储统计结果的动态内存(如果你后续把固定大小的
s数组改成动态扩容、把struct里的固定大小word改成动态申请的char*),需要在整个统计逻辑全部完成、业务侧不再需要统计结果之后,先遍历释放每个struct里的word内存,再释放struct数组本身的内存。
内容的提问来源于stack exchange,提问作者Schopenhauer
相关产品推荐
相关产品推荐

