C语言isalnum()函数使用错误 非字母数字字符被误计数
问题描述
代码预期实现功能为接收用户输入的短语,统计所有输入的总字符数,同时统计其中字母、数字类字符的总个数。实际测试时输入+等非字母数字字符,字母数字计数器仍会累加,统计结果不符合预期。
问题复现代码:
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> #define MAXR 100 #define MAXC 10 #define TERMINATOR "END" int main() { char phrase[MAXR]; char text[MAXC][MAXR]; int i; int countalnum = 0; int countchar = 0; for (i = 0; i < MAXC; i++) { fgets(phrase, MAXR, stdin); phrase[strlen(phrase) - 1] = '\0'; for (int j = 0; j < strlen(phrase); j++) { countchar++; if (isalnum(phrase[i]) == 0) countalnum++; } if (strcmp(phrase, TERMINATOR) == 0) { exit(0); } strcpy(text[i], phrase); } ... }
错误原因
代码存在两处直接导致计数错误的核心问题,还有两处潜在隐患:
- 数组索引使用错误:内层循环遍历当前输入字符串时,循环变量是
j(代表当前遍历到的字符串内字符位置),但调用isalnum时传入的是phrase[i],i是外层循环的行计数变量,根本不是当前遍历到的字符位置,取到的字符和当前遍历位置完全不对应,计数自然错误。 - 判断逻辑写反:
isalnum()函数的返回规则是:传入字符为字母或数字时返回非0值,传入非字母数字字符时返回0。现有代码写的判断条件是isalnum(...) == 0时给字母数字计数器加1,相当于遇到非字母数字字符才计数,完全颠倒了判断逻辑。 - 换行处理逻辑不安全:直接用
phrase[strlen(phrase) - 1] = '\0'删除fgets读入的换行符的写法有风险,如果输入行长度超过缓冲区限制、或输入流读到EOF时没有换行符,这行代码会误删最后一个有效输入字符。 - 标准库调用存在未定义行为风险:
isalnum要求传入的参数要么是EOF,要么是可转换为unsigned char类型的值,如果编译环境下char为有符号类型,遇到值为负的字符时直接传入会触发未定义行为。
修正方案
将核心换行处理、计数逻辑替换为以下写法即可:
// 替换原有直接截断最后一个字符的换行处理逻辑 fgets(phrase, MAXR, stdin); char *newline_pos = strchr(phrase, '\n'); if (newline_pos != NULL) { *newline_pos = '\0'; } // 替换原有内层计数循环 for (int j = 0; j < strlen(phrase); j++) { countchar++; // 修正索引为j,修正判断逻辑,强转unsigned char规避未定义行为 if (isalnum((unsigned char)phrase[j]) != 0) { countalnum++; } }
内容的提问来源于stack exchange,提问作者Poinsaett
相关产品推荐
相关产品推荐

