尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

printf和scanf入门:C语言输入输出格式控制与常见坑

printf和scanf入门:C语言输入输出格式控制与常见坑 C语言入门最绕不开的两个函数就是printf和scanf。一个是输出一个是输入几乎所有程序的第一步都靠它们来完成。这篇教程直接从零开始把这两个函数的用法、格式控制、常见坑和排查方法一次讲清楚。不需要任何前置基础只要能在电脑上写代码、编译运行就能跟着走完。1. printf 和 scanf 核心能力速览能力项printfscanf头文件stdio.hstdio.h函数原型int printf(const char *format, ...);int scanf(const char *format, ...);主要功能按格式输出到标准输出屏幕从标准输入键盘按格式读取数据可变参数支持支持返回值成功输出的字符数失败返回负值成功读取并赋值的变量个数失败返回 EOF常用格式%d%f%c%s%x等%d%f%c%s等使用难点格式符与变量类型不匹配缓冲区、空格、回车、字符读取学习成本低中从表格可以看出printf侧重“输出格式”scanf侧重“输入解析”。两者都依赖格式控制字符串但scanf的坑明显更多尤其处理字符和字符串时。2. 适用场景与学习路径printf和scanf是 C 语言标准库中最基础、最常用的函数几乎覆盖所有初学阶段输出提示信息、运行结果、调试变量。输入数值、字符、字符串实现交互式程序。配合循环、数组、结构体完成数据展示和处理。在竞赛编程中快速验证算法逻辑。不适合直接用printf和scanf的场景也有高频 IO、超大字符串输入、格式化复杂 JSON 等场景应该使用更专业的库或函数。但初学者完全不需要考虑先把这两个函数用熟练即可。学习路径建议先掌握printf的常用格式控制符。再掌握scanf的基本读入方式。理解缓冲区对字符输入的影响。最后通过完整案例把输入、计算、输出串起来。这篇教程就是按照这个路径设计的。3. 开发环境准备与第一个 C 程序3.1 开发工具选择C 语言开发环境有很多零基础建议选一个能一键编译运行的集成开发环境Windows 用户Dev-C、Code::Blocks、Visual Studio需要选择“使用 C 的桌面开发”工作负载。macOS 用户Xcode 或者直接用 VS Code clang。Linux 用户VS Code、CLion或者直接用gcc命令。本文示例使用gcc编译器因为它在各平台通用。测试命令如下gcc --version如果显示类似gcc (GCC) 11.2.0说明环境就绪。3.2 第一个程序输出一句话新建文件hello.c输入以下代码#include stdio.h int main() { printf(Hello, C Language!\n); return 0; }编译运行gcc hello.c -o hello ./helloWindows 下运行gcc hello.c -o hello.exe hello.exe预期输出Hello, C Language!这个程序只用了printf但已经包含了 C 程序的基本结构头文件、main函数、语句和返回值。#include stdio.h是必需的因为printf声明在这个头文件里。3.3 程序执行流程从源代码到运行结果经历四个阶段预处理处理#include、宏定义等到.i文件。编译把 C 代码翻译成汇编代码。汇编把汇编代码翻译成机器码生成.o或.obj文件。链接把目标文件和库文件合并成可执行文件。初学阶段不需要深入每个步骤但要知道如果程序没有反应或报错先看编译阶段有没有出红字。编译通过后再关注运行结果。4. printf 函数使用详解4.1 基本输出printf的第一个参数是格式控制字符串后面的参数是要输出的值。最简单的用法是直接输出常量字符串printf(Hello World);但更多时候需要输出变量的值比如int age 20; printf(我的年龄是%d岁\n, age);输出我的年龄是20岁这里的%d是格式控制符表示以十进制整数形式输出。age是与之匹配的变量。如果变量类型是float就要用%f如果是字符用%c如果是字符串用%s。4.2 常用格式控制符汇总格式控制符对应数据类型输出形式%dint带符号十进制整数%uunsigned int无符号十进制整数%ffloat/double十进制浮点数%lfdouble十进制双精度浮点数输入时用输出时%f也可以%cchar单个字符%schar*字符串%xunsigned int十六进制整数%ounsigned int八进制整数%edouble科学计数法%pvoid*指针地址注意printf中输出double既可以用%f也可以用%lf但在scanf中读取double必须用%lf。这是初学者经常混淆的地方。4.3 宽度、精度和标志格式串中可以在%和格式字符之间插入修饰符控制输出对齐、宽度和小数位数。格式为%[标志][宽度][.精度]格式字符常用标志标志含义-左对齐默认右对齐输出正负号0用 0 填充宽度空格正数输出空格负数输出负号#对八进制、十六进制显示前缀宽度和精度示例printf(%5d\n, 123); // 宽度5右对齐 printf(%-5d|\n, 123); // 宽度5左对齐 printf(%05d\n, 123); // 宽度5用0填充 printf(%.2f\n, 3.14159); // 保留2位小数输出结果123 123 | 00123 3.14注意printf的浮点数默认输出 6 位小数。如果不想看到多余的 0就要手动指定精度。4.4 多个变量连续输出一个printf可以输出多个变量格式控制符与变量按顺序一一对应int year 2024; double score 98.5; char grade A; printf(年份%d分数%.1f等级%c\n, year, score, grade);输出年份2024分数98.5等级A出现最多的问题就是格式符数量和变量数量不一致。多了会输出垃圾数据少了会出现未定义行为。要养成习惯写完后数一下%和逗号后的变量。4.5 常见输出示例打印九九乘法表写一个稍复杂的例子把printf嵌套在循环里#include stdio.h int main() { for (int i 1; i 9; i) { for (int j 1; j i; j) { printf(%d*%d%-2d , j, i, i * j); } printf(\n); } return 0; }重点看%-2d-表示左对齐2表示至少占 2 个字符宽度。这样表格输出整齐。运行后可以看到阶梯状乘法表。这个例子说明printf的输出效果可以直接影响程序体验练习时就该注意对齐和排版。5. scanf 函数使用详解5.1 基本输入scanf读取键盘输入按格式控制串解析数据存入变量地址int num; scanf(%d, num);注意不能少。scanf需要的是变量的内存地址而不是变量本身。很多初学者直接写scanf(%d, num);运行时轻则读不到值重则程序崩溃。读取多个变量int a, b; scanf(%d%d, a, b);%d之间可以不加空格。scanf默认跳过空白字符空格、Tab、换行所以输入10 20或10\n20都能正确读取。5.2 常用格式控制符与返回值格式控制符读取类型示例%dint*scanf(%d, n);%ffloat*scanf(%f, f);%lfdouble*scanf(%lf, d);%cchar*scanf(%c, ch);%schar[]scanf(%s, str);%xunsigned int*scanf(%x, hex);scanf的返回值表示成功读取并赋值的变量个数。例如int n scanf(%d %d, a, b);如果用户输入10 20n的值是 2如果只输了一个数n是 1如果输入格式错误n可能是 0。这个返回值常用于判断输入是否合法。注意%s不需要因为数组名本身就是地址。但%c必须用。5.3 字符输入的缓冲区问题这是scanf最大的坑尤其是读取字符时。先看一个典型错误int age; char gender; printf(请输入年龄); scanf(%d, age); printf(请输入性别(m/f)); scanf(%c, gender);运行时会发现第二个scanf没有等待输入直接读取到了一个换行符。原因是第一个scanf(%d, age)读取数字后输入缓冲区里还残留一个\n。第二个%c直接把这个换行符读走了。解决方案有几种在%c前加空格让scanf跳过空白字符scanf( %c, gender);用getchar()吃掉遗留的换行getchar(); scanf(%c, gender);使用fflush(stdin)但在 C 标准中这是未定义行为不建议使用。推荐第一种方式简单安全。5.4 字符串输入的限制scanf读字符串有个安全缺陷它不检查目标数组长度可能越界写入。char name[10]; scanf(%s, name);如果用户输入超过 9 个字符就会造成缓冲区溢出。更安全的方法是限制宽度scanf(%9s, name);9表示最多读取 9 个字符剩下的留给后续输入。这是必须养成的习惯。另外scanf(%s, name)遇到空格会停止读取。例如输入Zhang Sanname只会得到Zhang。如果要读一行包含空格的字符串需要用fgets或gets不推荐gets。初学者要清楚这个限制。5.5 常见输入示例计算两个整数之和#include stdio.h int main() { int x, y; printf(请输入两个整数用空格分隔); int ret scanf(%d%d, x, y); if (ret 2) { printf(%d %d %d\n, x, y, x y); } else { printf(输入格式错误请重新运行程序。\n); } return 0; }引入返回值判断后程序对非法输入的容忍度更高。实际项目中仅仅检查返回值还不够还要考虑输入流中残留的垃圾字符但初学阶段先做到这一步已经不错了。6. printf 与 scanf 的返回值与错误处理6.1 printf 返回值int len printf(abc);len的值是 3因为打印了 3 个字符。如果打印失败len为负。这个返回值平时不常用但在重定向输出到文件时可以用来确认写入是否成功。6.2 scanf 返回值scanf返回值很重要推荐在每个从键盘读数据的程序里都检查一下。int num; int result scanf(%d, num); if (result ! 1) { printf(输入无效\n); return 1; }如果用户输入了abcresult会是 0说明没有成功赋值。更麻烦的情况是用户输入了12abc。此时scanf(%d, num)会成功读取12num被赋值为 12但abc仍然留在缓冲区。如果后面再读可能会干扰。处理这种脏数据的方法是清空缓冲区例如用循环读取int c; while ((c getchar()) ! \n c ! EOF) { }这段代码会把缓冲区中剩余的字符读走直到遇到换行或文件结束符。6.3 格式匹配失败时的行为int a; scanf(%d, a);如果输入12.5scanf会读到12遇到小数点.时停止因为小数点不是%d能识别的字符。12被赋值给a剩余.5留在缓冲区。这种“部分成功”很容易让程序出现隐性问题所以建议用返回值确认是否读取完整。7. 常见问题与排查方法问题现象可能原因排查思路解决方案编译时报错printf was not declared缺少#include stdio.h检查代码头部添加#include stdio.h输出乱码中文字符编码与编译器环境不一致检查源文件编码和终端编码统一使用 UTF-8 编码或在 Windows 下执行chcp 65001printf 输出%d显示很大随机数格式符与变量类型不匹配检查变量声明类型和格式符使用正确格式符例如%f对应floatscanf 读取字符时跳过输入缓冲区残留换行符观察前一个输入是否留下\n在%c前加空格scanf 读取不到字符串输入中带空格%s终止读取确认输入需求使用fgets编译通过但程序一运行就崩溃可能scanf缺少检查所有scanf调用给变量地址加数组名不需要输入数字后无法继续输入scanf格式串不匹配或缓冲区脏数据打印缓冲区剩余内容辅助判断清空缓冲区或 add 空格跳过空白运行结果不换行输出语句缺少\n检查末尾是否有换行控制符加上\n表格里的问题基本覆盖了初学者最高频的报错。遇到问题不要先怀疑编译器优先检查格式串、变量类型、和头文件。8. 最佳实践与学习建议8.1 始终检查 scanf 的返回值不要假设用户一定会按预期输入。返回值就是有效输入数量的唯一证据。养成写if (scanf(...) 期望个数)的习惯能避免大量未知问题。8.2 为 scanf 限制字符串长度char str[100]; scanf(%99s, str);数组长度是 100最多读 99 个字符留一个给字符串结束符\0。这能防止缓冲区溢出也是安全编程的基本要求。8.3 避免在 printf 中直接使用用户输入作为格式串错误示范char input[100]; scanf(%s, input); printf(input); // 这是不安全用法如果input中包含%d、%s等格式符printf会试图读取不存在的参数产生未定义行为。正确写法是printf(%s, input);8.4 用调试输出辅助定位问题学习时可以在关键位置临时加printf输出变量当前值。例如printf(DEBUG: a%d, b%d\n, a, b);定位完再删除。这是最朴素也最有效的调试手段。8.5 多做输入输出专项练习输出固定宽度、左对齐的小数。读取两个整数并输出它们的商和余数。读取一个字符并用%d输出其 ASCII 码。读取多个整数求和直到输入 0 结束。读取一行英文姓名并以固定格式输出。这些练习能把printf和scanf的细节彻底练熟。9. 总结printf和scanf是 C 语言入门的必过关卡。printf的难点在格式控制符与变量类型的匹配以及宽度、精度、对齐这些细节scanf的难点在缓冲区、空格、字符读取和返回值处理。不要只看不写把上面每个示例都亲自编译运行一遍再尝试修改格式串观察输出变化。出错很正常关键是从错误中学到规律。接下来可以继续学习条件语句、循环、数组和函数。但无论学到哪里printf和scanf都会一直陪着你。先把这两个基础打牢后面会顺畅很多。
返回列表