C语言输入输出详解:掌握printf、scanf等核心I/O函数

C语言输入输出详解:掌握printf、scanf等核心I/O函数

程序的交互性是其核心特性之一——程序需要接收用户的输入,处理后给出相应的输出。C语言通过一套强大的I/O(Input/Output)函数来实现这种交互。本篇博客将全面讲解C语言的核心输入输出函数,包括printf()scanf()getchar()putchar()等,帮助你掌握如何高效地处理用户数据。

一、理解I/O基础:缓存和字节流

在学习具体函数之前,我们先了解C语言I/O的基础概念。C语言处理输入输出时,将各种输入输出设备都抽象为流(stream)

  • 标准输入流stdin):通常指键盘
  • 标准输出流stdout):通常指显示器
  • 标准错误流stderr):错误信息输出,也指向显示器

这些函数通常带有缓存(buffer),意味着数据会先被收集在缓存中,然后才批量处理,这能显著提高I/O效率。

二、printf()函数:格式化的输出

printf()是C语言中最常用、最强大的输出函数,用于将格式化的数据输出到stdout

1. 基本用法回顾

C
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>

int main(void) {
printf("Hello, World!\n");
printf("C语言I/O函数学习\n");

int age = 25;
double salary = 7500.50;
printf("年龄:%d,月薪:%.2f元\n", age, salary);

return 0;
}

2. 常用占位符总结

  • %d%i:十进制整数
  • %f:浮点数
  • %c:单个字符
  • %s:字符串
  • %p:指针(地址)
  • %x%X:十六进制整数(小写/大写)
  • %o:八进制整数
  • %u:无符号十进制整数

3. 高级格式控制

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
// 宽度控制
printf("商品列表:\n");
printf("%-10s %8.2f 元\n", "苹果", 5.99); // 左对齐,宽10
printf("%-10s %8.2f 元\n", "香蕉", 3.49); // 保留2位小数
printf("%-10s %8.2f 元\n", "橙子", 4.25);

// 符号显示
int temperature = 15;
printf("当前温度:%+d°C\n", temperature); // 显示正负号

// 前导0填充
int year = 2026, month = 1, day = 27;
printf("日期:%04d-%02d-%02d\n", year, month, day);
// 输出:2026-01-27

printf()成功时返回输出的字符数,失败时返回负值。

三、scanf()函数:格式化的输入

scanf()是C语言中最重要的输入函数,用于从stdin读取格式化的数据。

1. 基本用法

C
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>

int main(void) {
int age;
char name[50];

printf("请输入你的姓名和年龄:");
scanf("%s %d", name, &age); // 注意&符号

printf("你好,%s!你今年%d岁。\n", name, age);

return 0;
}

注意:非数组类型的变量前需要加&取地址符,而数组名本身就是地址,不需要&

2. 常用占位符

  • %d:整数
  • %f:浮点数
  • %c:字符
  • %s:字符串
  • %lf:双精度浮点数

3. 安全输入和宽度限制
为了避免缓冲区溢出,应始终指定最大读取宽度:

C
1
2
3
4
5
6
7
8
9
10
11
char name[11];  // 包含结尾\0,最多10个字符

// 危险:可能导致数组越界
scanf("%s", name);

// 安全:最多读取10个字符
scanf("%10s", name);

// 多数据读取示例
int x, y, z;
scanf("%d %d %d", &x, &y, &z);

4. 输入格式控制

C
1
2
3
4
5
6
7
int year, month, day;

// 要求用户输入2026-01-27格式的日期
printf("请输入日期(YYYY-MM-DD):");
scanf("%d-%d-%d", &year, &month, &day);

printf("日期:%d年%02d月%02d日\n", year, month, day);

5. 赋值忽略符*
如果输入格式可能变化,可以使用赋值忽略符跳过不需要的部分:

C
1
2
3
4
5
6
int year, month, day;

// 无论用户输入2026-01-27还是2026/01/27,都能正确解析
scanf("%d%*c%d%*c%d", &year, &month, &day);

printf("解析结果:%d年%02d月%02d日\n", year, month, day);

scanf()成功时返回成功赋值的变量数量,失败或遇到文件结尾时返回EOF

四、sscanf()函数:从字符串中解析数据

sscanf()scanf()类似,但数据来源不是标准输入,而是字符串。

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <string.h>

int main(void) {
char str[] = "姓名:张三 年龄:25 工资:7500.50";
char name[50];
int age;
double salary;

// 从字符串中提取数据
sscanf(str, "姓名:%s 年龄:%d 工资:%lf", name, &age, &salary);

printf("提取结果:\n");
printf("姓名:%s\n", name);
printf("年龄:%d\n", age);
printf("工资:%.2f\n", salary);

return 0;
}

sscanf()的优势在于可以反复处理同一字符串,而scanf()的数据来源是流,只能读取一次。

五、getchar()和putchar()函数:字符级I/O

对于单个字符的输入输出,这两个函数更简单高效。

1. getchar():读取单个字符

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <stdio.h>

int main(void) {
int ch; // 必须用int,因为EOF通常是-1

printf("请输入一个字符:");
ch = getchar(); // 读取用户输入的第一个字符

printf("你输入的字符是:");
putchar(ch);
putchar('\n');

return 0;
}

getchar()不会跳过空白字符(空格、制表符、换行符)。

2. putchar():输出单个字符

C
1
2
3
4
5
6
// 输出单个字符
putchar('A');
putchar('\n');

// 等价于
printf("%c\n", 'A');

3. 实用技巧

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 跳过一行中的所有字符
printf("按回车键继续...");
while (getchar() != '\n')
; // 空循环体

// 计算一行的字符数
int count = 0;
printf("请输入一行文字:");
while (getchar() != '\n')
count++;
printf("此行有%d个字符\n", count);

// 跳过开头的空格
int ch;
printf("请输入(前面可能有空格):");
while ((ch = getchar()) == ' ')
; // 跳过空格
// 此时ch是第一个非空格字符

由于getchar()putchar()通常用宏实现,比scanf()printf()更快,处理单个字符时应优先使用。

六、puts()函数:输出字符串并换行

puts()用于输出字符串,并自动在末尾添加换行符

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>

int main(void) {
char message[] = "欢迎学习C语言I/O函数";

puts("以下是重要消息:");
puts(message); // 自动换行
puts("学习愉快!");

// 等价于
printf("以下是重要消息:\n");
printf("%s\n", message);
printf("学习愉快!\n");

return 0;
}

puts()printf()更简洁,但功能也更有限——只能输出字符串,不能格式化输出其他类型数据。

七、gets()函数:已废弃的危险函数

注意gets()函数因为存在严重的安全问题,已在C11标准中废除。

C
1
2
3
4
// 危险示例:永远不要使用!
char buffer[10];
printf("请输入:");
gets(buffer); // 如果用户输入超过9个字符,就会缓冲区溢出

替代方案:使用安全的fgets()函数

C
1
2
3
4
5
char buffer[10];
printf("请输入:");

// 安全:最多读取9个字符(留一个给\0)
fgets(buffer, sizeof(buffer), stdin);

八、I/O函数综合应用示例

C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
#include <stdio.h>
#include <string.h>

int main(void) {
char name[50];
int age;
char city[30];

// 用户信息输入
printf("===== 用户信息登记 =====\n");

printf("请输入姓名:");
fgets(name, sizeof(name), stdin);
// 移除fgets读取的换行符
name[strcspn(name, "\n")] = '\0';

printf("请输入年龄:");
scanf("%d", &age);

// 清除输入缓冲区
while (getchar() != '\n')
;

printf("请输入城市:");
fgets(city, sizeof(city), stdin);
city[strcspn(city, "\n")] = '\0';

// 信息输出
printf("\n===== 登记信息确认 =====\n");
printf("姓名:%s\n", name);
printf("年龄:%d\n", age);
printf("城市:%s\n", city);

// 使用putchar输出分隔线
putchar('\n');
for (int i = 0; i < 40; i++) {
putchar('=');
}
putchar('\n');

printf("信息登记完成!\n");

return 0;
}

九、最佳实践总结

  1. 安全性第一:使用fgets()代替gets(),为scanf()的字符串指定宽度限制
  2. 错误检查:检查scanf()fgets()等函数的返回值
  3. 清空缓冲区:混合使用scanf()fgets()时,注意清空输入缓冲区
  4. 选择合适函数
    • 格式化输出用printf()
    • 格式化输入用scanf()
    • 单字符I/O用getchar()/putchar()
    • 字符串输出用puts()
  5. 效率考虑:处理单个字符时优先使用getchar()/putchar()

十、结语

C语言的I/O函数虽然基础,但功能强大、灵活。掌握这些函数,你就掌握了程序与用户交互的钥匙。记住:

  • printf()是你的输出工具包
  • scanf()是你的输入解析器
  • getchar()/putchar()高效字符处理器
  • puts()简单字符串输出器
  • 永远不要使用gets()

现在,尝试编写一个程序,使用这些I/O函数创建一个简单的用户信息收集系统,体验C语言I/O的强大功能吧!


C语言输入输出详解:掌握printf、scanf等核心I/O函数
https://www.edenzeng.online/2015/11/09/0.技术栈/01.开发语言/01.C语言/16-输入输出详解/
作者
Edenzeng
发布于
2015年11月9日
许可协议