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格式化输入——小心这个坑

scanfprintf 的孪生兄弟,但脾气可差多了。它的基本用法:

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 是数组名,本身代表地址,所以不需要加 &。而 agesalary 是普通变量,必须加 &

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。下一个 getcharscanf("%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") 读取完数字后,缓冲区里还留着 \ngetchar 直接把它读走了。

怎么解决?我常用的方法有两个:

  1. getchar() 吃掉多余的换行符
  2. 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 知识体系总览

下面这张图,帮你把本章的知识点串起来:

C语言输入输出知识体系 输入与输出 printf 格式化输出 scanf 格式化输入 getchar / putchar 缓冲区问题 %d %f %c %s %x 精度控制 %.nf 必须加 & 符号 数组名不加 & 返回 int 类型 可检测 EOF 换行符残留问题 getchar() 吃掉换行 scanf(" %c") 加空格 核心:理解缓冲区机制,避免输入残留

这张图把本章的四个核心知识点串在了一起。你看,printfscanf 是格式化输入输出的主力,getcharputchar 负责字符级操作,而缓冲区问题则是贯穿始终的暗线。

我个人觉得,理解缓冲区是掌握C语言输入输出的关键。很多看似奇怪的问题,追根溯源都是缓冲区在作怪。记住一句话:缓冲区里的换行符,是你最需要警惕的敌人

本章要点回顾:
  • printf 用格式占位符控制输出格式,精度控制用 %.nf
  • scanf 必须加 & 取地址,数组名除外
  • getchar 返回 int 类型,可以检测 EOF
  • 缓冲区残留的换行符会导致输入跳过,用 getchar()scanf(" %c") 解决

好了,输入输出这块就聊到这儿。记住这些要点,你在写代码时就能少踩很多坑。下一章咱们聊聊数组和指针——嗯,那才是真正考验功底的地方。

专注资料整理