Day04-C语言输入输出与格式化陷阱 为什么 scanf(“%d\n”, a) 会卡住一篇讲透 C 语言的输入输出与格式化陷阱一、先讲个真实踩坑经历昨天写作业代码大概是这样的inta;printf(请输入 a 的值);scanf(%d\n,a);printf(a %d\n,a);编译没问题运行也没报错——但敲完数字后程序就像死了一样怎么按回车都不往下走。最后强行 CtrlC 退出百思不得其解。后来才明白scanf的\n不是换行提示而是一个实实在在的匹配指令。这个问题藏在我学过的每一本书里但没有一本当面告诉我。今天就从这个坑开始把 C 语言的输入输出彻底讲清楚。二、C 语言怎么跟世界说话——输入输出的底层逻辑C 语言本身没有输入输出语句。printf、scanf、getchar这些全都是 C 标准库提供的函数。#includestdio.h// 必须包含的头文件整个 I/O 模型可以理解为一个管道键盘 → [输入缓冲] → scanf/getchar → 内存变量 → printf/putchar → [输出缓冲] → 屏幕记住一个关键概念输入缓冲区。你在键盘上敲的所有字符包括空格、回车、Tab都会先进缓冲区scanf再从里面取数据。很多坑都和这个缓冲区有关。三、单字符输入输出getchar 和 putcharintgetchar(void);// 从标准输入读一个字符返回 ASCII 值intputchar(intc);// 向标准输出写一个字符返回输出的 ASCII 值注意返回类型是int不是 char。因为 char 的范围是 0~255但 getchar 需要用一个超出范围的值 EOF-1来表示读取结束所以必须用 int 存。简单示例——读入小写字母转大写charch;chgetchar();// 读入 aputchar(ch^32);// 输出 A异或 32 翻转大小写四、格式化输出 printf——不止是打印变量4.1 原型和基础intprintf(constchar*format,...);// 返回值成功输出的字符数量格式化字符串里有两类内容普通字符原样输出占位符以%开头被替换为对应参数的值4.2 常用占位符速查类型占位符含义整数%d/%u有符号 / 无符号十进制整数%o/%x八进制 / 十六进制%#x显示 0x 前缀浮点%f/%e/%g十进制 / 科学计数法 / 自动选短字符%c/%s单个字符 / 字符串地址%p指针地址4.3 辅助控制符——控制输出的长相这才是 printf 真正强大的地方。以int a 123;为例printf(%6d,a);// 123 默认右对齐占 6 位printf(%-6d,a);// 123 减号左对齐printf(%d,a);// 123 加号强制显示正号printf(%06d,a);// 000123 0用 0 填充浮点数精度控制floatx3.14159;printf(%.2f,x);// 3.14 保留 2 位小数printf(%6.2f,x);// 3.14 总宽 6小数 2 位这些修饰符可以组合使用但要记住顺序%[标志][宽度][.精度][长度]类型。五、格式化输入 scanf——一个到处都是坑的函数5.1 原型和基础intscanf(constchar*format,...);// 返回值成功匹配并赋值的参数个数关键点参数列表必须是地址。普通变量要加inta;scanf(%d,a);// 正确传地址scanf(%d,a);// 错误a 的值当成了地址段错误5.2 占位符的差异类型printfscanffloat%f%fdouble%f或%lf必须%lflong double%Lf%Lf注意 double 输入必须用%lf这是一个高频出错点。5.3 scanf 匹配结束的三个条件遇到空白符空格、Tab、回车遇到非法字符如用%d去读a达到指定宽度如%3d读入 12345 只会取 123六、三个高频陷阱 陷阱 1%c会吃掉空格和换行inta;charch;scanf(%d,a);// 输入 123输入缓冲区还剩下一个 \nscanf(%c,ch);// 直接读走了那个换行符不会等你输入解决方案有三种// 方案 1在 %c 前加空格跳过所有空白符scanf(%d %c,a,ch);// 方案 2用 %*c 跳过 1 个字符scanf(%d%*c%c,a,ch);// 方案 3用 getchar() 手动吃掉换行scanf(%d,a);getchar();// 吃掉 \nscanf(%c,ch); 陷阱 2格式字符串里不要写\n回到开篇的问题——scanf(%d\n, a)。格式字符串中的\n表示匹配任意多个空白符所以 scanf 会一直等待直到你输入一个非空白符才停止。正确写法就是scanf(%d, a)。 陷阱 3格式字符串里不要写普通字符scanf(a%d,a);// 你必须原样输入 a123少一个字符都不行初学者很容易踩这个坑建议格式字符串里只写占位符。七、作业题解作业 1交换三个数输入 a, b, c将 a 的值给 bb 的值给 cc 的值给 a。#includestdio.hintmain(){inta,b,c,tmp;printf(请输入 a b c);scanf(%d %d %d,a,b,c);tmpa;// 暂存 aac;// c → acb;// b → cbtmp;// a(原) → bprintf(交换后a%d b%d c%d\n,a,b,c);return0;}核心思路用一个临时变量 tmp按逆时针方向传递数值。作业 2计算表达式的算式和结果输入两个整数 a 和 b输出六种运算的算式和结果每个占一行。#includestdio.hintmain(){inta,b;printf(请输入 a b);scanf(%d %d,a,b);printf(%d%d%d\n,a,b,ab);printf(%d-%d%d\n,a,b,a-b);printf(%d*%d%d\n,a,b,a*b);printf(%d/%d%d\n,a,b,a/b);printf((float)%d/%d%f\n,a,b,(float)a/b);printf(%d%%%d%d\n,a,b,a%b);return0;}注意两点① 除法用(float)a强制转换得到小数结果②%在 printf 里要写成%%才能输出一个百分号。八、今日避坑指南忘记给 scanf 的普通变量加→ 段错误scanf 用%c前没清缓冲区 → 读到了上次遗留的换行在 scanf 格式字符串末尾写\n→ 程序卡住不退出double 输入用%f而不是%lf→ 数据错误浮点数直接用比较 → 精度不同永远不等printf 里输出%→ 必须写成%%九、一句话总结getchar/putchar 是基础——字符级 I/O返回 int底层直接操作缓冲区。printf 修饰符是门面——宽度、对齐、精度、填充组合顺序一定记住是%[标志][宽度][.精度][长度]类型。scanf 参数必传地址——不能丢丢了就是段错误。%c前必清缓冲——空格、%*c、getchar() 三种方法任选其一。scanf 格式串保持干净——只写占位符不写\n不写普通字符。