ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Day1语法:printf 与 scanf 使用

2026/8/12 15:17:39 拓冰建站 浏览量
Day1语法:printf 与 scanf 使用

1. 输入输出函数

printf 和 scanf 是 C 语言中最常用的格式化输入输出函数,但使用不当可能导致未定义行为或缓冲区溢出。本文梳理了它们的使用细节、常见错误及最佳实践,并补充了 getchar/putchar、fgets/fputs 等辅助函数,帮助你安全地进行输入输出操作。

2. printf 使用细节

2.1 基本语法

函数原型:int printf(const char *format, ...);

作用:格式化输出到标准输出(屏幕)。返回值:成功时返回打印的字符数,失败时返回负值。

2.2 输出缓冲区

printf 输出时会先存入输出缓冲区,遇到以下情况才刷新到屏幕:

  • 缓冲区已满
  • 遇到换行符\n
  • 程序正常结束
  • 显式调用fflush(stdout)

示例:

printf("Hello"); // 存储在缓冲区,不立即显示 printf(" World\n"); // 遇到 \n,缓冲区刷新,显示 "Hello World"

2.3 常见格式控制符

格式符说明示例
%d十进制整数printf("%d", 42);
%u无符号十进制整数printf("%u", 100u);
%f浮点数(默认6位小数)printf("%f", 3.14);
%.2f保留2位小数printf("%.2f", 3.14);
%c单个字符printf("%c", 'A');
%s字符串printf("%s", "Hi");
%x十六进制(小写)printf("%x", 255);
%X十六进制(大写)printf("%X", 255);
%p指针地址printf("%p", &x);
%%打印%本身printf("%%");

2.4 宽度与精度控制

  • %5d:至少占5个字符宽度,右对齐。
  • %-5d:左对齐。
  • %.3f:保留3位小数。
printf("%5d", 10); // 输出 " 10" printf("%-5d", 10); // 输出 "10 " printf("%.3f", 3.14159);// 输出 "3.142"

2.5 转义字符

  • \n:换行
  • \t:制表符
  • \\:打印反斜杠
  • \":打印双引号

2.6 类型匹配

格式符必须与变量类型严格匹配,否则引发未定义行为。例如用%d打印float是错误的:

float f = 3.14; printf("%d", f); // 错误!应使用 %f

3. scanf 使用细节

3.1 基本语法

函数原型:int scanf(const char *format, ...);

作用:从标准输入读取格式化数据。返回值:成功读取的变量个数,失败或遇到 EOF 返回 -1。

3.2 输入缓冲区

用户输入的数据首先进入输入缓冲区,scanf 从缓冲区读取并解析,未处理的数据会残留。

3.3 常见格式控制符

格式符说明示例
%d读取整数scanf("%d", &num);
%f读取floatscanf("%f", &fval);
%lf读取doublescanf("%lf", &dval);
%c读取字符(含空格)scanf("%c", &ch);
%s读取字符串(无空格)scanf("%s", str);
%[^\n]读取一行(含空格)scanf("%[^\n]", line);

3.4 关键细节

3.4.1 必须传递变量地址

除字符串(字符数组)外,其他变量必须加&

int num; scanf("%d", num); // 错误!应写成 scanf("%d", &num);
3.4.2 缓冲区残留问题

scanf 读取后,输入缓冲区可能残留\n,影响后续输入。可通过以下方式清空:

while (getchar() != '\n'); // 清空缓冲区
3.4.3 防止 %s 缓冲区溢出

scanf("%s", str)不检查长度,可能导致越界。建议限制读取长度:

char str[100]; scanf("%99s", str); // 最多读取 99 个字符,留 1 位给 '\0'
3.4.4 %c 会读取空白字符

如果前面有\n%c会直接读取它。解决方法是在%c前加空格:

scanf(" %c", &ch); // 跳过空白字符
3.4.5 检查返回值

始终检查输入是否成功,避免非法输入导致程序崩溃:

if (scanf("%d", &num) != 1) { printf("输入错误!\n"); while (getchar() != '\n'); // 清空缓冲区 }

4. printf 与 scanf 对比

特性printfscanf
用途输出数据输入数据
变量传递直接传值必须传地址
缓冲区通常自动刷新(带 \n)可能残留 \n,需清理
安全性一般安全%s 可能溢出,需限制长度
返回值成功打印的字符数成功读取的变量个数

5. 经典错误示例

5.1 scanf 忘记 &

int num; scanf("%d", num); // 错误,导致未定义行为

5.2 %d 读取 float

float f; scanf("%d", &f); // 错误,应使用 %f

5.3 %s 不限制长度

char name[10]; scanf("%s", name); // 输入超过 9 个字符导致缓冲区溢出

正确做法:

scanf("%9s", name);

5.4 scanf 读取整数时的残留字符

scanf 根据%d读取整数,遇到非数字字符会停止,并将该字符放回缓冲区,影响后续读取。

scanf("%d%d", &a, &b); scanf("%c", &c); // 若输入字母 a,c 会直接获取该字符

6. 最佳实践

6.1 printf

  • 使用\n确保输出刷新。
  • 确保格式符与变量类型匹配。
  • 合理控制输出宽度和精度。

6.2 scanf

  • 始终检查返回值。
  • %s使用长度限制。
  • 必要时清空输入缓冲区。

7. 其他相关函数

7.1 getchar 与 putchar

getchar()从标准输入读取一个字符,putchar()输出一个字符。

char ch = getchar(); // 等价于 scanf("%c", &ch); putchar(ch); // 等价于 printf("%c", ch);

7.2 getc 与 putc

与 getchar/putchar 类似,但允许指定文件指针(如stdinstdout或自定义文件流)。

ch = getc(stdin); // 从标准输入读取 ch = getc(fp); // 从文件指针 fp 读取

7.3 fgets 与 fputs

fgets从指定流读取一行,通过第二个参数限制长度,安全解决溢出问题。

char ch[20]; fgets(ch, 19, stdin); // 最多读取 19 个字符,保留 '\0' printf("%s", ch);

fputs将字符串写入指定流,不自动添加换行符。

fputs(buf, fp); // 将 buf 写入 fp 指向的文件

8. 总结

掌握 printf 和 scanf 的细节能有效避免未定义行为和缓冲区溢出。关键点:

  • printf 注意格式匹配和缓冲区刷新;
  • scanf 必须传地址,限制字符串长度,检查返回值,清理残留缓冲区;
  • 必要时使用 getchar/putchar、fgets/fputs 等更安全的函数替代。

希望笔记能帮助你巩固 C 语言输入输出相关知识,减少编码中的低级错误。