
一、前言本文核心内容来自学习笔记围绕scanf的三个关键问题展开为什么变量必须取地址为什么会阻塞缓冲区残留的\n怎么处理在此基础上补充了常用格式符、返回值、常见错误与输入安全等知识点。二、核心知识点 1变量必须取地址scanf用来读取标准输入把标准输入内的内容放到某个变量空间里因此变量必须取地址。int i; scanf(%d, i); // 必须传 i而不是 i原因scanf需要把读到的值写入变量对应的内存空间只有拿到地址才能通过指针真正修改那块内存。直接传i只是传了值的副本改不到外面的i。例外读取字符串时字符数组名本身就是地址不需要加char str[20]; scanf(%s, str); // 数组名即地址三、核心知识点 2scanf 为什么会阻塞scanf会阻塞是因为标准输入缓冲区是空的。当你运行程序后光标一直闪烁、毫无反应并不是死机而是scanf在等待输入。只有输入内容并按下回车数据进入缓冲区程序才会继续执行。注意scanf需要回车才能读取值所以其实我们输入的是 值 \n。四、核心代码示例 1单类型依次读取 清空缓冲区#include stdio.h //scanf用来读取标准输入scanf把标准输入内的内容需要放到某个变量空间里因此变量必须取地址 //scanf会阻塞是因为标准输入缓冲区是空的 int main() { int i; char c; float f; scanf(%d, i); printf(i%d\n, i);//把标准缓冲区中的整型数读走了 //Scanf需要回车才能读取值所以其实我们输入的是 值\n //而把标准缓冲区中的整型数读走了没有读取\n //\n就会被下一个Scanf给读取所以需要清空缓冲区 //不然\n就会被下一个Scanf给读取无法正常执行你想要输入的值 fflush(stdin);//清空标准输入缓冲区 //在C语言中%s格式说明符会自动跳过所有前导空白字符包括换行符、空格、制表符等 //只有%c和%[格式说明符不会自动跳过前导空白字符 //其他格式说明符如%d、%f、%s等都会自动跳过前导空白字符 scanf(%c, c); printf(c%c\n, c);//输出字符变量c scanf(%f, f); printf(f%4.1f\n, f); return 0; }运行流程输入42回车缓冲区里是4 2 \nscanf(%d)读走42\n残留在缓冲区若不清理下一个scanf(%c)会把\n直接读走导致无法正常输入想要的字符fflush(stdin)清空缓冲区后%c才能读到真正的字符。运行结果五、核心知识点 3空白字符跳过规则在 C 语言中%s格式说明符会自动跳过所有前导空白字符包括换行符、空格、制表符等只有%c和%[格式说明符不会自动跳过前导空白字符其他格式说明符如%d、%f、%s等都会自动跳过前导空白字符。六、核心代码示例 2一次读取多种数据类型#include stdio.h //scanf一次读多种数据类型 int main() { int i, ret; float f; char c; ret scanf(%d %c%f, i, c, f);//ret是指scanf匹配成功的个数 %c可以读取空格 printf(i%d,c%c,f%5.2f\n, i, c, f); return 0; }运行效果输入12 A 3.14回车输出i12,cA,f 3.14。ret是scanf匹配成功的个数本例成功匹配 3 项ret 3。运行结果七、知识点 1fflush (stdin) 的争议与标准清空方案fflush在 C 标准中只对输出流有明确定义fflush(stdin)属于非标准用法。它在 Windows 的 Visual Studio 等编译器上通常有效但在 Linux / GCC 下行为未定义。推荐用标准可移植的写法清空缓冲区void clear_stdin(void) { int ch; while ((ch getchar()) ! \n ch ! EOF) ; }八、知识点 2% c 前加空格 —— 最优雅的解法既然问题出在%c不跳过空白那就在格式串里显式要求跳过scanf( %c, c); // 空格表示先跳过所有空白字符含 \n再读取字符这样连清空缓冲区的代码都省了。九、知识点 3常用格式说明符对照表表格格式符含义是否自动跳过前导空白%d十进制整数是%f/%lf单精度 / 双精度浮点是%c单个字符否%s字符串遇空白停止是%x/%o十六进制 / 八进制整数是%e科学计数法浮点是%[ ]指定字符集合否十、知识点 4scanf 的返回值与循环输入scanf返回匹配成功的项数读到文件末尾返回EOF即 -1。循环读入时一定要判断返回值否则输入不匹配会陷入死循环int a, ret; while ((ret scanf(%d, a)) ! EOF) { if (ret 1) printf(读到%d\n, a); else { /* 清空本次无效输入 */ clear_stdin(); } }十一、知识点 5常见错误汇总表格错误写法问题正确写法scanf(%d, i)忘记取地址scanf(%d, i)scanf(%d)后接scanf(%c)\n残留被%c读走清空缓冲区或scanf( %c, c)scanf(%s, str)输入过长缓冲区溢出scanf(%9s, str)忽略返回值输入不匹配时变量值不确定用ret接收并判断double 用%f类型不匹配double 用%lf十二、知识点 6输入安全性用%s读字符串务必加宽度限制防止缓冲区溢出char name[10]; scanf(%9s, name); // 最多读 9 个字符第 10 个留给 \0在 Visual Studio 中也可以用更安全的scanf_s。涉及整行输入的场景推荐用fgets替代scanf避免缓冲区状态混乱。十三、总结取地址scanf要写进变量的内存空间必须传变量名字符串数组名本身就是地址。阻塞缓冲区为空时scanf等待输入回车后缓冲区是 值 \n。残留%d、%f等只读走值\n残留%c、%[不跳过空白最容易中招。可用fflush(stdin)非标准或getchar循环清空推荐scanf( %c, c)直接跳过。返回值匹配成功个数 EOF 判断是处理输入的关键。安全%s加宽度限制防止缓冲区溢出。