C语言文本统计代码:特殊符号与辅音计数异常问题排查
问题排查:C语言字符统计代码中特殊符号与辅音计数异常
问题描述
以下是用于统计lets.txt文件中元音、辅音、空格、制表符、特殊符号及行数的C语言代码,目前除特殊符号与辅音计数功能外,其余功能正常:
#include<stdio.h> #include<stdlib.h> int main() { FILE * fp; fp = fopen("lets.txt", "r"); int vowels = 0, constants = 0, spaces = 0, tabs = 0, specsym = 0, nolines = 1; int c; while ((c = fgetc(fp)) != EOF) { if (c == 65 || c == 69 || c == 73 || c == 70 || c == 85 || c == 97 || c == 101 || c == 105 || c == 111 || c == 117) { vowels++; } else if (c == 32) { spaces++; } else if ((33 <= c <= 47) || (58 <= c <= 64) || (91 <= c <= 96) || (123 <= c <= 126)) { specsym++; } else if ((65 <= c <= 90) || (97 <= c <= 122)) { constants++; } } rewind(fp); char c1; while ((c1 = fgetc(fp)) != EOF) { if (c1 == '\n') { nolines++; } else if (c1 == '\t') { tabs++; } } printf("The number of vowels are %d , constants %d, spaces %d, tabs %d, special symbols %d and lines %d", vowels, constants, spaces, tabs, specsym, nolines); }
运行时出现异常:特殊符号会被计入辅音;调换特殊符号与辅音的判断顺序后,辅音又会被计入特殊符号。
异常原因
核心问题是连续范围比较的写法不符合C语言语法逻辑:
C语言不支持像数学表达式那样的a <= x <= b连续比较,这种写法会被解析为左结合运算:先计算a <= x,得到布尔值0(假)或1(真),再将这个结果与b比较。由于0和1都小于等于代码中所有的右边界值(47、64、96、126、90、122),所以这些范围判断表达式无论c取何值,结果永远为真。
这直接导致分支判断逻辑完全混乱:所有非元音、非空格的字符会优先进入第一个“永远为真”的分支,调换判断顺序后,就会流入新的优先分支,从而出现你看到的“互相计入”现象。
修复方案
将所有连续范围比较拆分为x >= 下限 && x <= 上限的形式,同时修正代码中的其他小问题:
#include<stdio.h> #include<stdlib.h> int main() { FILE * fp; fp = fopen("lets.txt", "r"); // 增加文件打开失败判断,避免崩溃 if (fp == NULL) { printf("Failed to open file\n"); return 1; } int vowels = 0, consonants = 0, spaces = 0, tabs = 0, specsym = 0, nolines = 1; int c; while ((c = fgetc(fp)) != EOF) { // 用字符字面量代替ASCII码,修正元音判断错误(原代码误将F当成元音) if (c == 'A' || c == 'E' || c == 'I' || c == 'O' || c == 'U' || c == 'a' || c == 'e' || c == 'i' || c == 'o' || c == 'u') { vowels++; } else if (c == ' ') { spaces++; } else if ((c >= 33 && c <= 47) || (c >= 58 && c <= 64) || (c >= 91 && c <= 96) || (c >= 123 && c <= 126)) { specsym++; } else if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z')) { consonants++; } } rewind(fp); // 用int存储fgetc返回值,避免EOF判断错误 int c1; while ((c1 = fgetc(fp)) != EOF) { if (c1 == '\n') { nolines++; } else if (c1 == '\t') { tabs++; } } printf("元音数量:%d,辅音数量:%d,空格数量:%d,制表符数量:%d,特殊符号数量:%d,行数:%d\n", vowels, consonants, spaces, tabs, specsym, nolines); // 关闭文件,释放资源 fclose(fp); return 0; }
额外优化说明:
- 用字符字面量(如
'A')代替ASCII码,提升代码可读性 - 增加文件打开失败的判断逻辑,避免空指针访问崩溃
- 用
int存储fgetc的返回值(fgetc返回int类型,包含EOF的数值),避免字符类型无法正确识别EOF - 修正变量名拼写错误(
constants改为consonants,符合英语拼写规范) - 增加文件关闭操作,避免资源泄漏
内容的提问来源于stack exchange,提问作者Yash Gabra
相关产品推荐
相关产品推荐

