getchar() 是什么?
getchar() 是 C 标准库中的一个函数,定义在头文件 <stdio.h> 中。

它的作用是:从标准输入流(通常是键盘)中读取一个字符,并将其作为无符号字符 unsigned char 类型转换为 int 类型返回。
关键点:
- 返回类型是
int,而不是char:这是一个非常重要的设计。int类型通常是 32 位,而char是 8 位,多出来的这 24 位(或 16 位,取决于系统)用来存储一个特殊的值——EOF。 - 工作方式:
getchar()会等待用户输入,直到用户按下回车键,它会返回输入流中的第一个字符,之后再次调用getchar(),它会返回第二个字符,以此类推,直到遇到换行符\n(表示本次输入结束)。
EOF 是什么?
EOF 是 "End Of File" 的缩写,意思是“文件结束符”。
它是一个在 <stdio.h> 中定义的宏,通常是一个负整数(-1)。getchar() 在正常情况下返回一个在 0 到 255 之间的值(代表字符的 ASCII 码),当它读取到“文件结束”这个信号时,它就会返回 EOF。

在从键盘输入时,如何产生 EOF 呢?
这取决于你的操作系统:
- 在 Windows / MS-DOS 系统中:按下
Ctrl + Z组合键,然后按回车,系统会发送一个“文件结束”信号。 - 在 Linux / macOS / Unix-like 系统中:按下
Ctrl + D组合键,系统会立即发送一个“文件结束”信号,无需回车。
为什么 getchar() 的返回值是 int?
就是为了能够区分“有效的字符”和“文件结束符 EOF”,如果返回值是 char,它只能表示 0-255 的值,就无法用 0-255 之外的值(如 -1)来表示 EOF 了。int 类型保证了有足够的空间来存放这个特殊的标志。
经典用法:读取所有输入直到 EOF
最常见的 getchar() 用法就是读取用户输入的所有字符,直到遇到 EOF 为止。

示例代码 1:统计输入的字符数
这是一个非常经典的 C 语言入门示例。
#include <stdio.h>
int main() {
int c; // 必须是 int 类型,才能接收 EOF
long count = 0;
printf("请输入一些字符,然后按 Ctrl+D (Linux/macOS) 或 Ctrl+Z (Windows) 结束输入:\n");
// 循环读取字符,直到 getchar() 返回 EOF
while ((c = getchar()) != EOF) {
count++;
}
printf("\n总共输入了 %ld 个字符,\n", count);
return 0;
}
代码解析:
int c;:声明一个int变量c用来存储getchar()的返回值。while ((c = getchar()) != EOF):这是一个核心的while循环。c = getchar():调用getchar()读取一个字符,并将其赋值给c,这个表达式的值就是被读取的字符本身。!= EOF:检查刚刚读取的字符是否不等于EOF。- 整个循环会一直执行,只要
getchar()返回的不是EOF,一旦用户输入了EOF信号,条件变为假,循环结束。
count++:每成功读取一个字符,计数器count就加一。
常见陷阱与注意事项
陷阱 1:c 的类型必须是 int
错误示范:
// 错误的写法
char c;
while ((c = getchar()) != EOF) { // ... }
问题所在:
c 是 char 类型,它只能存储 0-255 的值,当 getchar() 遇到 EOF(-1)时,这个 -1 会被赋值给 char 类型的 c,在赋值过程中,-1 会被“截断”成一个 8 位的无符号数(unsigned char),结果变成了 255(二进制 11111111)。c 的值永远不会等于 EOF,循环将变成一个死循环。
正确做法:
始终使用 int 类型来接收 getchar() 的返回值。
// 正确的写法
int c;
while ((c = getchar()) != EOF) { // ... }
陷阱 2:EOF 不是字符,是一个信号
初学者常常会混淆 EOF 和键盘上的某个特定字符(ESC 键)。
EOF不是一个可以输入的字符,它是一个信号,由操作系统在特定按键组合(Ctrl+D/Ctrl+Z)下发送给程序,表示“输入源已经结束了”。getchar()只有在真的收到这个信号时才会返回EOF,它不会因为输入流中“没有字符可读”而返回EOF(除非你明确地发送了信号)。
陷阱 3:getchar() 会读取换行符 \n
当你从键盘输入一行文本并按回车时,回车符 \n 也会被输入到缓冲区中。getchar() 会把它当作一个普通的字符来读取。
示例代码 2:打印每个字符及其 ASCII 码
#include <stdio.h>
int main() {
int c;
printf("请输入一行文字:\n");
// 在 Windows 上,输入一行后按回车,然后按 Ctrl+Z
// 在 Linux/macOS 上,输入一行后按回车,然后按 Ctrl+D
while ((c = getchar()) != EOF) {
// 打印字符本身(如果是可打印字符)和它的 ASCII 码
if (c == '\n') {
printf("\\n (newline) -> %d\n", c);
} else if (c == '\t') {
printf("\\t (tab) -> %d\n", c);
} else if (c == ' ') {
printf("' ' (space) -> %d\n", c);
} else {
printf("'%c' -> %d\n", c, c);
}
}
printf("EOF detected.\n");
return 0;
}
如果你输入 hello 然后发送 EOF 信号,程序输出会是:
'h' -> 104
'e' -> 101
'l' -> 108
'l' -> 108
'o' -> 111
\n (newline) -> 10
EOF detected.
注意,换行符 \n 也被读取和打印了。
getchar() 与 scanf("%c", ...) 的区别
scanf 也可以用来读取字符,但它们的行为有细微但重要的差别,尤其是在处理空白字符(空格、制表符、换行符)时。
| 特性 | getchar() |
scanf("%c", &c) |
|---|---|---|
| 功能 | 读取标准输入流的下一个字符,包括空白字符。 | 读取标准输入流的下一个字符,包括空白字符。 |
| 输入缓冲区 | 总是从缓冲区中取出一个字符。 | 如果缓冲区为空,它会等待输入,但如果缓冲区中有字符(比如前一个 scanf留下的换行符),它会直接读取那个字符,而不会等待新的输入。 |
| 主要区别 | 行为简单直接,只关心“下一个字符”。 | 行为受格式字符串影响,容易因前一个输入的残留(如 \n)而产生非预期行为。 |
示例:scanf 的陷阱
#include <stdio.h>
int main() {
int age;
char initial;
printf("请输入你的年龄: ");
scanf("%d", &age); // 用户输入 25 并回车
// 输入缓冲区中剩下 "25\n"
// %d 读取了 "25",但 "\n" 还留在缓冲区里
printf("请输入你的名字的首字母: ");
// %c 会直接读取缓冲区中剩下的那个 '\n',而不会等待用户输入!
scanf("%c", &initial);
printf("你输入的字母是: %c\n", initial); // 输出会是换行符
return 0;
}
如何修正 scanf 的问题?
可以在读取 %c 之前,先用 getchar() 清空输入缓冲区。
// ...
scanf("%d", &age);
// 清空输入缓冲区,直到遇到换行符或文件结束
while (getchar() != '\n');
printf("请输入你的名字的首字母: ");
scanf("%c", &initial);
// ...
| 概念 | 关键点 |
|---|---|
getchar() |
从标准输入读取一个字符,返回 int 类型。 |
EOF |
一个宏,值为 -1,表示“文件结束”。 |
| 核心循环 | while ((c = getchar()) != EOF) |
c 的类型 |
必须是 int,以正确处理 EOF,避免死循环。 |
如何输入 EOF |
Ctrl + D (Linux/macOS) 或 Ctrl + Z (Windows)。 |
| 优点 | 简单、可靠,能处理所有字符,包括空白符。 |
与 scanf 的区别 |
getchar() 行为更纯粹,不易受残留字符影响。 |
理解 getchar() 和 EOF 是掌握 C 语言输入输出的基础,也是理解文件操作(如 fgetc)的关键,务必记住 int c 这个看似简单却至关重要的细节。
