5、输入与输出:printf格式化输出、scanf格式化输入、getchar/putchar、缓冲区问题
说实话,C语言的输入输出,是每个初学者最先接触,却最容易踩坑的地方。我见过太多人,代码逻辑写得没问题,偏偏卡在输入输出上,调试半天找不到原因。今天咱们就把这块彻底捋清楚。
5.1 printf格式化输出——你写对了吗?
printf 这玩意儿,看着简单,其实门道不少。我刚开始学的时候,以为就是 printf("hello") 完事了。后来才发现,格式化输出才是它的精髓。
基本格式长这样:
printf("格式控制字符串", 参数列表);
格式控制字符串里,%d、%f、%c 这些叫格式占位符。它们告诉编译器:嘿,这里要放一个整数、浮点数或者字符。
| 占位符 | 含义 | 示例 |
|---|---|---|
| %d | 有符号十进制整数 | printf("%d", 10); |
| %f | 浮点数(默认6位小数) | printf("%.2f", 3.14159); |
| %c | 单个字符 | printf("%c", 'A'); |
| %s | 字符串 | printf("%s", "hello"); |
| %x | 十六进制(小写) | printf("%x", 255); |
| %p | 指针地址 | printf("%p", &a); |
%.nf,比如 %.2f 保留两位小数。我在项目中经常用这个来格式化金额输出,避免出现 0.100000 这种尴尬情况。
5.2 scanf格式化输入——小心这个坑
scanf 是 printf 的孪生兄弟,但脾气可差多了。它的基本用法:
scanf("格式控制字符串", &变量1, &变量2, ...);
注意那个 & 符号!很多人漏掉它,结果程序直接崩溃。为什么?因为 scanf 需要知道变量的地址,才能把值写进去。
scanf 的格式字符串里加多余的换行符或空格!比如 scanf("%d\n", &n); 这种写法会让你多输入一次。我曾经被这个坑过,调试了半小时才发现是多了一个 \n。
来看个完整例子:
#include <stdio.h>
int main() {
int age;
float salary;
char name[50];
printf("请输入姓名、年龄和薪资:");
scanf("%s %d %f", name, &age, &salary);
printf("姓名:%s,年龄:%d,薪资:%.2f\n", name, age, salary);
return 0;
}
这里有个细节:name 是数组名,本身代表地址,所以不需要加 &。而 age 和 salary 是普通变量,必须加 &。
5.3 getchar和putchar——字符级操作
这两个函数,说白了就是专门处理单个字符的。我个人的习惯是,当只需要读取一个字符时,优先用 getchar 而不是 scanf。
#include <stdio.h>
int main() {
char ch;
printf("请输入一个字符:");
ch = getchar(); // 从键盘读取一个字符
printf("你输入的是:");
putchar(ch); // 输出一个字符
putchar('\n');
return 0;
}
getchar 返回的是 int 类型,不是 char。为什么?因为它要能返回 EOF(文件结束标志),而 EOF 通常是 -1,用 char 存不下。嗯,这里要注意。
5.4 缓冲区问题——最隐蔽的敌人
缓冲区,这是C语言输入输出里最让人头疼的问题。你想想看,为什么有时候 scanf 会跳过输入?为什么 getchar 会读到换行符?
说白了,标准输入是有缓冲的。你敲键盘的时候,字符先存到缓冲区里,等按下回车,程序才一次性读取。
scanf 读取完数据后,缓冲区里可能还残留着换行符 \n。下一个 getchar 或 scanf("%c") 会直接读到这个换行符,导致程序行为异常。
来看个经典例子:
#include <stdio.h>
int main() {
int num;
char ch;
printf("请输入一个整数:");
scanf("%d", &num);
printf("请输入一个字符:");
ch = getchar(); // 这里会直接读到缓冲区里的换行符!
printf("整数:%d,字符:%c\n", num, ch);
return 0;
}
运行结果会让你抓狂——程序根本没等你输入字符,就直接结束了。为什么?因为 scanf("%d") 读取完数字后,缓冲区里还留着 \n,getchar 直接把它读走了。
怎么解决?我常用的方法有两个:
- 用
getchar()吃掉多余的换行符 - 用
scanf(" %c")加一个空格(空格会跳过空白字符)
// 方法一:手动吃掉换行符
scanf("%d", &num);
getchar(); // 吃掉换行符
ch = getchar();
// 方法二:scanf加空格
scanf("%d", &num);
scanf(" %c", &ch); // 注意%c前面有个空格
fgets 配合 sscanf 来替代 scanf。这样能完全避免缓冲区残留问题,而且更安全。比如:fgets(buf, sizeof(buf), stdin); sscanf(buf, "%d", &num);
5.5 知识体系总览
下面这张图,帮你把本章的知识点串起来:
这张图把本章的四个核心知识点串在了一起。你看,printf 和 scanf 是格式化输入输出的主力,getchar 和 putchar 负责字符级操作,而缓冲区问题则是贯穿始终的暗线。
我个人觉得,理解缓冲区是掌握C语言输入输出的关键。很多看似奇怪的问题,追根溯源都是缓冲区在作怪。记住一句话:缓冲区里的换行符,是你最需要警惕的敌人。
- printf 用格式占位符控制输出格式,精度控制用
%.nf - scanf 必须加
&取地址,数组名除外 - getchar 返回 int 类型,可以检测 EOF
- 缓冲区残留的换行符会导致输入跳过,用
getchar()或scanf(" %c")解决
好了,输入输出这块就聊到这儿。记住这些要点,你在写代码时就能少踩很多坑。下一章咱们聊聊数组和指针——嗯,那才是真正考验功底的地方。