如何在C语言中正确统计字符串中不区分大小写的单词出现次数?
C语言统计单词所有大小写组合出现次数的解决方案
需求说明
需要统计字符串中目标单词(如horse)所有大小写组合形式的独立出现次数,例如字符串"horse HORSE HORse HoRsE"中该单词共出现4次,同时要解决以下场景的统计问题:
- 单词连续无空格拼接(如
"horsehorse")需正确统计所有出现 - 单词出现在完整句子(如
"hello horse how are you today")中需正确识别
原代码缺陷分析
你提供的代码存在两处核心问题:
- 数组越界访问:循环条件
i < SL会导致当i > SL-5时,访问str[i+1]至str[i+4]超出字符串范围,读取无效字符可能导致匹配失败或程序异常。 - 无单词边界检查:仅通过连续字符匹配判断,无法区分独立单词与包含该字符序列的长单词(如
"horses"会被误判),同时flag变量未在每次循环前重置,易出现累加错误导致漏统计。 - 匹配后跳转逻辑隐患:
i = i+5的跳转方式在部分场景下可能跳过潜在匹配,且gets函数存在缓冲区溢出风险。
改进后的代码
#include <stdio.h> #include <string.h> #include <ctype.h> // 大小写不敏感检查是否匹配目标单词horse int is_horse(const char *s) { return (tolower(s[0]) == 'h') && (tolower(s[1]) == 'o') && (tolower(s[2]) == 'r') && (tolower(s[3]) == 's') && (tolower(s[4]) == 'e'); } // 检查是否为单词分隔符(可根据需求扩展) int is_word_sep(char c) { return c == ' ' || c == '\t' || c == '\n' || c == '\0' || c == ',' || c == '.' || c == '!' || c == '?'; } int main() { char str[100]; int count = 0; int len; printf("Give string: "); fgets(str, sizeof(str), stdin); // 移除fgets读取的换行符 len = strlen(str); if (len > 0 && str[len-1] == '\n') { str[len-1] = '\0'; len--; } // 循环范围确保不会越界访问 for (int i = 0; i <= len - 5; i++) { if (is_horse(&str[i])) { // 检查前边界:字符串开头或前一个字符是分隔符 int prev_ok = (i == 0) || is_word_sep(str[i-1]); // 检查后边界:字符串结尾或后一个字符是分隔符 int next_ok = (i+5 == len) || is_word_sep(str[i+5]); if (prev_ok && next_ok) { count++; // 跳过当前匹配的单词,避免重复统计(循环会自动i++,所以加4) i += 4; } } } printf("There are %d horse in the string\n", count); return 0; }
改进点说明
- 安全输入处理:用
fgets替代gets,避免缓冲区溢出,同时处理换行符保证字符串格式正确。 - 模块化匹配逻辑:拆分
is_horse和is_word_sep函数,代码更易读且便于扩展(比如修改目标单词或分隔符规则)。 - 避免越界:循环条件改为
i <= len -5,确保每次检查的5个字符都在字符串范围内。 - 独立单词验证:通过前后边界检查,确保统计的是真正的独立单词,而非长单词中的子序列。
- 正确跳转逻辑:
i +=4配合循环的i++,刚好跳过当前匹配的5个字符,既避免重复统计,又能正确处理连续拼接的场景。
内容的提问来源于stack exchange,提问作者jonathan
相关产品推荐
相关产品推荐

