scanf 的返回值
要理解 while(scanf(...)),关键在于明白 scanf 函数除了读取数据,还会返回一个整数值。

(图片来源网络,侵删)
这个返回值代表了: 成功匹配并读取的参数个数。
- 成功读取:
scanf能够按照格式字符串%d,%f,%s等成功读取到对应类型的输入项,它就会返回成功读取的项数。 - 读取失败(遇到文件结尾 EOF 或不匹配的字符):
- 当输入流(比如键盘输入)结束时,
scanf会返回EOF(End of File),这是一个在stdio.h中定义的宏,通常是-1。 - 当输入的格式与格式字符串不匹配时(你期望一个整数
%d,但用户输入了 "hello"),scanf也会立即返回,并返回已经成功读取的项数(在这种情况下是0)。
- 当输入流(比如键盘输入)结束时,
while 循环的条件判断
在 C 语言中,while 循环的条件判断是基于“真”和“假”的:
- 0 代表 假。
- 非 0 代表 真。
结合 scanf 的返回值,我们就可以得到 while(scanf(...)) 的逻辑:
- 循环开始:程序执行
scanf尝试读取输入。 - 判断条件:
scanf成功读取了至少一个数据项(你用%d读取了一个整数),它会返回1(或其他正数)。1是非零值,所以条件为真,while循环体内的代码被执行。scanf读取失败(遇到了不匹配的输入或文件结尾EOF),它会返回0或EOF(通常是-1)。0和-1都是零值,所以条件为假,while循环终止。
常见用法示例
示例 1:读取不定数量的整数
这是最经典的用法,常用于处理未知数量的数据,比如读取一系列数字直到用户输入非数字内容。

(图片来源网络,侵删)
#include <stdio.h>
int main() {
int num;
int count = 0;
printf("请输入一系列整数,按 Ctrl+D (Linux/macOS) 或 Ctrl+Z (Windows) 结束输入:\n");
// 循环会一直执行,直到 scanf 读取失败
while (scanf("%d", &num) == 1) { // 最好写成 == 1,更清晰
printf("你输入的整数是: %d\n", num);
count++;
}
printf("\n输入结束,总共读取了 %d 个整数,\n", count);
return 0;
}
代码解释:
while (scanf("%d", &num) == 1):这个写法比while(scanf("%d", &num))更严谨,它明确表示“只要scanf成功读取一个整数(返回值为1),就继续循环”。- 如何结束输入?
- 在 Linux 或 macOS 上,按下
Ctrl+D会向程序发送EOF信号。 - 在 Windows 上,按下
Ctrl+Z然后按回车,会发送EOF信号。 - 你也可以输入一个非数字字符,"abc",然后按回车。
scanf会尝试读取一个整数但失败,返回0,循环结束。
- 在 Linux 或 macOS 上,按下
示例 2:读取不定数量的浮点数
逻辑与读取整数完全相同,只需要将格式字符串和变量类型改为 float 或 double。
#include <stdio.h>
int main() {
double score;
int student_count = 0;
printf("请输入学生成绩(输入任意非数字字符结束):\n");
// 只要成功读取一个 double 类型的数据,循环就继续
while (scanf("%lf", &score) == 1) {
printf("成绩录入: %.2f\n", score);
student_count++;
}
printf("\n所有成绩录入完毕,共 %d 名学生,\n", student_count);
return 0;
}
示例 3:混合读取(高级用法)
scanf 的格式字符串可以更复杂,比如一次读取多个不同类型的数据。
#include <stdio.h>
int main() {
int id;
char name[50]; // 定义一个字符数组来存储名字
printf("请输入ID和名字( 101 张三),输入 q 退出:\n");
// 格式字符串 "%d %49s" 表示:读取一个整数,然后读取一个最多49个字符的字符串(留1位给字符串结束符'\0')
while (scanf("%d %49s", &id, name) == 2) {
printf("ID: %d, 姓名: %s\n", id, name);
}
printf("输入结束,\n");
return 0;
}
代码解释:

(图片来源网络,侵删)
scanf("%d %49s", &id, name) == 2:这个循环会一直执行,只要用户能一次性成功输入一个整数和一个字符串(用空格隔开)。- 如果用户只输入了
102然后按回车,scanf会读取id但无法读取name,它会返回1,循环条件1 == 2为假,循环终止。 - 如果用户输入
103 李四,scanf成功读取两个数据,返回2,循环条件为真,执行循环体。
重要注意事项和最佳实践
-
scanf的缓冲区问题 当scanf读取数据时,如果输入和格式不匹配,错误的输入会残留在输入缓冲区中,这会导致下一次scanf调用时直接读取到这个错误的输入,造成无限循环。错误示范:
int a, b; while (scanf("%d", &a) == 1) { printf("请输入第二个数: "); scanf("%d", &b); // 如果用户输入 "hello",这里会失败,且 "hello" 留在缓冲区 printf("结果是: %d\n", a + b); } // 程序会卡死,因为下一次循环开始,scanf("%d", &a) 会再次尝试读取 "hello" -
如何解决缓冲区问题?
- 最佳实践:避免在循环中使用
scanf读取非结构化数据。 对于交互式输入,fgets+sscanf是更健壮、更安全的选择。 - 如果必须用
scanf,可以在每次读取失败后清空输入缓冲区,这通常通过一个循环和getchar()函数来实现。
改进后的代码(清空缓冲区):
#include <stdio.h> #include <ctype.h> // 用于 is 函数 int main() { int a, b; int c; while (scanf("%d", &a) == 1) { printf("请输入第二个数: "); if (scanf("%d", &b) != 1) { printf("输入无效,请输入一个整数!\n"); // 清空输入缓冲区,直到遇到换行符或文件结尾 while ((c = getchar()) != '\n' && c != EOF); continue; // 跳过本次循环的剩余部分,重新开始 } printf("结果是: %d\n", a + b); } return 0; } - 最佳实践:避免在循环中使用
| 特性 | 描述 |
|---|---|
| 核心原理 | 利用 scanf 函数的返回值(成功读取的项数)作为 while 循环的条件。 |
| 循环条件 | while(scanf(...) == N),N 是你期望成功读取的数据项个数。N 是 1 或 2。 |
| 终止条件 | 当 scanf 读取失败(返回 0 或 EOF)时,循环终止。 |
| 主要用途 | 处理来自标准输入(键盘)的、数量未知的数据流,例如读取一系列数字、点坐标等。 |
| 优点 | 代码简洁,功能强大。 |
| 缺点 | 容易因输入缓冲区问题导致逻辑错误或死循环,不够健壮。 |
| 最佳实践 | 对于需要严格用户交互的场景,推荐使用 fgets 读取整行,再用 sscanf 从字符串中解析数据,这样可以更好地控制输入流。 |
