C 语言 ctype.h
更新时间:2026-08-26。本文是
languages/c/主题入门层第 69 篇。判断一个字符是不是数字、是不是字母、是不是空白——ctype.h提供一组"字符体检"函数。虽然每个函数就一行逻辑,但手写if (c >= '0' && c <= '9')不如isdigit(c)干净,而且后者对 locale 更安全。分类、转换、加上一个防坑细节,这篇讲完。
本文要回答的问题
- 字符分类函数有哪些?分别判断什么?
- 大小写转换怎么写?
- 为什么参数要转成
unsigned char?
一、字符分类函数
| 函数 | 判断 | 例子 |
|---|---|---|
isalpha(c) | 字母 a-z / A-Z | isalpha('A') → 1 |
isdigit(c) | 数字 0-9 | isdigit('5') → 1 |
isalnum(c) | 字母或数字 | |
isspace(c) | 空白(空格/制表/换行) | isspace(' ') → 1 |
isupper(c) | 大写字母 | |
islower(c) | 小写字母 | |
ispunct(c) | 标点符号 | ispunct('.') → 1 |
isxdigit(c) | 十六进制数字 | isxdigit('F') → 1 |
c
#include <ctype.h>
if (isalpha(c)) printf("字母\n");
else if (isdigit(c)) printf("数字\n");
else if (isspace(c)) printf("空白\n");
else printf("其他\n");返回非 0 表示真(不一定是 1),判断时 if (isdigit(c)) 直接当布尔用。
二、大小写转换
c
char up = toupper('a'); // 'A'
char low = tolower('B'); // 'b'注意:toupper 对已经是数字/符号的字符原样返回,不会出错;toupper('5') 还是 '5'。做"忽略大小写"比较时的标配:
c
int eq_ignore_case(char a, char b) {
return toupper(a) == toupper(b);
}三、必须转 unsigned char:经典坑
c
char c = -1; // 例如从 fgetc 流里读的 0xFF
// isalpha(c) // ❌ 参数 -1 不是合法值!行为未定义
// isalpha((unsigned char)c) // ✅原因:ctype 函数用参数做数组下标查表,负的 char 值会导致越界访问——未定义行为。所以:
- 从
fgetc读到的int直接传给 ctype 函数是安全的(已经是unsigned char或EOF); - 但
char变量(可能带符号)传给 ctype 函数前,先(unsigned char)转换。
四、实战:统计文本中的字符类型
c
#include <ctype.h>
int letters = 0, digits = 0, spaces = 0, others = 0;
int c;
while ((c = getchar()) != EOF) {
if (isalpha(c)) letters++;
else if (isdigit(c)) digits++;
else if (isspace(c)) spaces++;
else others++;
}
printf("letters=%d digits=%d spaces=%d others=%d\n",
letters, digits, spaces, others);这就是文本统计工具的核心逻辑。
五、常见坑对照
| 坑 | 现象 | 对策 |
|---|---|---|
| char 直接传 ctype | 越界 UB | 转 unsigned char |
| 以为返回 1 | == 1 判断失效 | 非 0 即真 |
| 手写范围判断 | 忽略 locale/易错 | 用 ctype 函数 |
| toupper 当会转换所有 | 数字原样返回 | 已知如此 |
| 与 ascii 码混淆 | 逻辑错 | 函数语义记清 |
六、与本站主线衔接
一句话总结
ctype.h 提供字符分类(isalpha/isdigit/isspace 等,返回非 0 即真)与转换(toupper/tolower),比手写范围判断更规范安全——唯一大坑是参数必须转 unsigned char,否则查表越界是未定义行为——字符的"体检报告"找 ctype,别自己数 ASCII 码。