getchar

计算getchar输入

一、碰见个很烦的题目:

*对输入的行、单词和字符进行计数。我们将单词的定义进行化简,认为单词是不包含空格、制表符\t及换行符的字符序列。例如:“a+b+c”,认为是1个单词,它由5个字符组成。又如:“xy abc”,为2个单词,6个字符。输入ctrl+z结束(提示:用ch!=EOF或ch!=-1作为循环条件)。

**输出格式要求:”Lines=%d\nWords=%d\nChars=%d\n”
程序运行示例如下:
hi~
Good moring!
I’m Julie.

Lines=3
Words=5
Chars=28

二、代码实现:

我根本不会写啊,甚至连运行都运行不了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
#include <stdio.h>

int main()
{
int lines = 0, words = 0, chars = 0;
int ch;
while ((ch = getchar()) != EOF) {
chars++;
if (ch == '\n') {
lines++;
}
if (ch == ' ' || ch == '\t' || ch == '\n') {
words++;
}
}
printf("Lines=%d\nWords=%d\nChars=%d\n", lines, words, chars);
return 0;
}

1,为什么 ch 要定义成 int 类型?我输入的不是字符吗?

你说得对!你输入的确实是「字符」(比如 hi\n),但 getchar() 这个函数的设计很特殊 —— 它返回的不是 char 类型,而是 int 类型。

核心原因:要区分「普通字符」和「结束信号 EOF」

  • 计算机里的所有字符(包括字母、符号、换行符 \n),在底层都会被转换成一个 0~255 之间的整数(ASCII 码)。比如 'a' 对应 97,'\n' 对应 10,空格 ' ' 对应 32。
  • EOF(你之前代码里的结束信号,输入 Ctrl+Z 触发),它的本质是一个 -1(整数),用来告诉程序 “输入已经结束了,别再读了”。

如果 ch 定义成 char 会出什么问题?

char 类型的范围很窄(多数编译器默认是 -128~127),它没法正确处理 EOF

  • char 是「有符号」的:虽然 -1 能存,但有些扩展 ASCII 字符(比如某些特殊符号)的编码也会是负数,可能和 EOF 混淆,导致程序提前退出或一直不退出;
  • char 是「无符号」的:-1 会被强制转换成 255(相当于一个普通字符),程序永远认不出 EOF,循环会无限执行,关都关不掉。

总结:

ch 定义成 int,是为了同时接收两种东西:

  1. 普通字符(本质是 0~255 的整数,存到 int 里完全没问题);
  2. 结束信号 EOF(本质是 -1,只有 int 能正确识别,不会和普通字符混淆)。

你之前第一次写的代码用 char ch,其实是有隐藏 bug 的,只是没触发而已;改成 int ch 才是标准、安全的写法。

2.\t 是啥?

\t 是 C 语言里的「转义字符」,全称是「水平制表符」,作用和你键盘上的 Tab 键 完全一样 —— 就是在输出或输入时,插入一个 “制表位空格”(大概占 4~8 个普通空格的宽度,用来对齐文本)。

举个例子:

输入时:你在键盘上按一下 Tab 键,程序读取到的就是 \t;输出时:printf("姓名\t年龄\t性别\n"); 会打印成:

1
姓名    年龄    性别  (中间的空白就是 \t 对应的制表位)

结合你之前的题目:

题目说 “单词是不包含空格、制表符 \t 及换行符 \n 的字符序列”—— 意思是:\t 和空格、换行符一样,都是「单词的分隔符」。比如输入 hello\tworld(hello 和 world 之间按了 Tab 键),会被统计成 2 个单词,而不是 1 个。

三、EOF 和 -1 是什么鬼东西?

1. EOF 是什么?

  • 全称:End Of File(文件结束符);
  • 本质:它不是一个 “字符”,而是一个「信号」—— 告诉程序 “输入已经读完了,没有更多数据了”;
  • 触发方式:在 Windows 系统下,你在控制台输入完内容后,按 Ctrl + Z(然后回车),就会向程序发送 EOF 信号;在 Linux/Mac 下是 Ctrl + D

2. EOF-1 的关系?

  • EOF 是 C 语言标准库(stdio.h)里定义的一个「宏」(可以理解成一个 “常量别名”);
  • 它的底层定义就是 #define EOF (-1)—— 所以 EOF 本质上就是整数 -1
  • 程序里写 ch != EOFch != -1 效果完全一样,但写 EOF 更规范、更容易看懂(别人一看就知道是 “判断输入是否结束”)。

3. 为什么要用 EOF

比如你之前的题目,要求 “输入 Ctrl+Z 结束”—— 程序怎么知道你按下了 Ctrl+Z?就是通过 EOF 信号。getchar() 读取到 EOF 后,会返回 -1(也就是 EOF),循环条件 (ch=getchar())!=EOF 就会不成立,循环退出,程序结束统计。


判断getchar

又碰见一个:

编写一个程序,判断输入的一行字符是否构成一个合法的C标识符(以下划线_或字母开头,由下划线、字母和数字组成视为合法的C标识符)。(假设输入的字符串非关键字且最大长度为32)
**输入格式要求:getchar()
**输出格式要求:”is\n” “is not\n”
程序运行示例1如下:
$223
is not
程序运行示例2如下:
hello world
is not
程序运行示例3如下:
hello
is
程序运行示例4如下:
a.net
is not
程序运行示例5如下:
123
is not

代码实现:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#include <stdio.h>

int judge(int, int);

int main()
{
int content[31] = { 0 };
int i = 0;
content[0] = getchar();
do {
if (judge(content[i], i)) {
printf("is not");
return 0;
}
i++;
content[i] = getchar();
} while (judge(content[i], i) == 0);
printf("is\n");

return 0;
}

int judge(int temp, int i) {
char content[32];
content[i] = temp;
if (content[0] == '_' || (content[0] > 'a' && content[0] < 'z') || (content[0] > 'A' && content[0] < 'Z')) {
return 0;
}
else if (content[i] == '_' || (content[i] > 'a' && content[i] < 'z') || (content[i] > 'A' && content[i] < 'Z') || (content[i] >= 0 && content[i] <= 9)) {
return 0;
}
else {
return 1;
}
}

看看AI写的:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
#include <stdio.h>

int main() {
char str[100]; // 定义字符数组
int i = 0;
char c;
int is_valid = 1; // 1代表合法(is),0代表不合法(is not)

// 1. 读取输入 (题目要求用 getchar)
while ((c = getchar()) != '\n' && c != EOF) {
if (i < 32) { // 限制长度,防止溢出
str[i] = c;
i++;
}
}
str[i] = '\0'; // 别忘了给字符串加结束符

// 2. 如果输入为空,直接算不合法
if (i == 0) {
is_valid = 0;
} else {
// 3. 检查第一个字符:必须是 字母 或 下划线
// 不能是数字!
char first = str[0];
if ( !((first >= 'a' && first <= 'z') ||
(first >= 'A' && first <= 'Z') ||
first == '_') ) {
is_valid = 0;
}
else {
// 4. 检查剩下的字符:必须是 字母、数字 或 下划线
for (int j = 1; j < i; j++) {
char current = str[j];
// 如果 它不是小写字母 且 不是大写字母 且 不是数字 且 不是下划线
// 那么它就是非法字符
if ( !((current >= 'a' && current <= 'z') ||
(current >= 'A' && current <= 'Z') ||
(current >= '0' && current <= '9') ||
current == '_') ) {
is_valid = 0;
break; // 发现一个错的就不用看后面了
}
}
}
}

// 5. 输出结果
if (is_valid == 1) {
printf("is\n");
} else {
printf("is not\n");
}

return 0;
}

总结:

可以用数组储存getchar得到的东西


getchar
http://example.com/2025/11/29/getchar/
作者
王柏森
发布于
2025年11月29日
许可协议