目录
[2. 为什么要有缓冲区?](#2. 为什么要有缓冲区?)
[3. 缓冲区的类型](#3. 缓冲区的类型)
[1. scanf()](#1. scanf())
[2. getchar()](#2. getchar())
[3. gets()(已废弃,不推荐使用)](#3. gets()(已废弃,不推荐使用))
[4. fgets()](#4. fgets())
[5. putchar()](#5. putchar())
[问题 1:scanf 连续读取](#问题 1:scanf 连续读取)
[问题 2:循环读取时残留数据](#问题 2:循环读取时残留数据)
[3:混合使用 scanf 和 fgets 时,先清空缓冲区:](#3:混合使用 scanf 和 fgets 时,先清空缓冲区:)
一:为什么要谈及输入方法
在 C 语言中,我们经常需要从键盘读取数据,比如:
cpp
int a;
scanf("%d", &a);
但很多初学者会遇到 "程序好像卡住了"、"输入一次却输出两次"、"跳过了输入步骤" 等奇怪问题。
这些现象大多与输入缓冲区(Buffer) 的工作机制有关。
二、缓冲区(Buffer)是什么?
1:定义
缓冲区是一块临时存储数据的内存区域。当你从键盘输入时,数据并不会立刻被程序读取,而是先存到缓冲区里,等满足一定条件时,程序才会去读取。
2. 为什么要有缓冲区?
- 减少 I/O 次数:直接每次读取键盘会很慢,缓冲区可以攒一批数据一次性给程序。
- 方便用户编辑:在按回车前,你可以用退格键修改输入。
3. 缓冲区的类型
- **全缓冲(Full Buffering)**缓冲区满了才会被刷新(交给程序)。常见于文件操作。
- 行缓冲(Line Buffering) 遇到换行符
\n
才会刷新。键盘输入通常是行缓冲。 - 无缓冲(No Buffering) 输入立即被读取,不经过缓冲区。如
getch()
(非标准 C)。
三、常见输入函数详解
1. scanf()
功能:格式化输入函数,按指定格式读取数据。
cpp
int a;
scanf("%d", &a);
特点:
- 会跳过前导空白字符(空格、制表符、换行符)。
- 读到不符合格式的字符时停止。
- 未读取的字符会留在缓冲区。
陷阱:
cpp
int a;
char c;
scanf("%d", &a); // 输入: 123abc
scanf("%c", &c); // 会直接读取到 'a',而不是等待新输入
2. getchar()
功能:读取单个字符(包括空格、换行符)。
cpp
char c = getchar();
特点:
- 每次只读取一个字符。
- 会读取任何字符 ,包括
\n
。 - 常用来 "吃掉" 缓冲区里的多余字符。
示例:清空缓冲区
cpp
while (getchar() != '\n');
3.gets()
(已废弃,不推荐使用)
功能:读取一整行字符串,直到遇到换行符
cpp
char str[100];
gets(str); // 危险!
问题:
- 不检查缓冲区大小,容易导致缓冲区溢出。
- C11 标准已正式移除
gets()
。 - 建议用
fgets()
代替。
4. fgets()
功能:从文件流读取字符串,可以指定最大长度。
cpp
char str[100];
fgets(str, 100, stdin); // 从标准输入读取
优点:
- 安全,因为限制了读取长度。
- 会保留换行符
\n
在字符串末尾。
cpp
// 去掉末尾的换行符
str[strcspn(str, "\n")] = '\0';
5. putchar()
功能:输出单个字符。
cpp
#include <stdio.h>
int main()
{
putchar('A'); // 输出字符 'A'
putchar('\n'); // 输出换行符
return 0;
}
cpp
//循环输出字符串
/*putchar 输出的字符通常会先进入输出缓冲区,并不是立即显示在屏幕上。常见情况:
行缓冲模式(大多数终端是行缓冲)
遇到 \n 会立即刷新缓冲区,把内容显示出来。
如果没有 \n,程序可能在结束或缓冲区满时才显示。*/
#include <stdio.h>
int main()
{
char str[] = "Hello";
for (int i = 0; str[i] != '\0'; i++)
{
putchar(str[i]);
}
putchar('\n');
return 0;
}
四、缓冲区的影响与常见问题
问题 1:scanf
连续读取
cpp
int a;
char c;
scanf("%d", &a);
scanf("%c", &c); // 会直接读取缓冲区中的 '\n'
解决方法:
cpp
scanf("%d", &a);
getchar(); // 吃掉换行符
scanf("%c", &c);
问题 2:循环读取时残留数据
cpp
char str[10];
while (1)
{
printf("输入: ");
scanf("%s", str); // 如果输入过长,多余字符会留在缓冲区
}
解决方法:
cpp
while (getchar() != '\n'); // 清空缓冲区
五、各种输入方法对比

六、实用技巧
1:清空缓冲区:
cpp
while (getchar() != '\n');
2:安全读取字符串:
cpp
char str[100];
fgets(str, 100, stdin);
str[strcspn(str, "\n")] = '\0'; // 去掉换行符
3:混合使用 scanf
和 fgets
时,先清空缓冲区:
cpp
int a;
scanf("%d", &a);
while (getchar() != '\n'); // 清空
fgets(str, 100, stdin);
七、总结
- 缓冲区是关键:理解缓冲区的工作原理能帮你避免 90% 的输入问题。
- 选择合适的函数 :数值用
scanf
,整行字符串用fgets
,单个字符用getchar
。 - 注意安全 :永远不要使用
gets()
,它是危险的。 - 处理好换行符:混合输入时,记得清空缓冲区。