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. 基本用法回顾
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. 高级格式控制
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| printf("商品列表:\n"); printf("%-10s %8.2f 元\n", "苹果", 5.99); printf("%-10s %8.2f 元\n", "香蕉", 3.49); printf("%-10s %8.2f 元\n", "橙子", 4.25);
int temperature = 15; printf("当前温度:%+d°C\n", temperature);
int year = 2026, month = 1, day = 27; printf("日期:%04d-%02d-%02d\n", year, month, day);
|
printf()成功时返回输出的字符数,失败时返回负值。
三、scanf()函数:格式化的输入
scanf()是C语言中最重要的输入函数,用于从stdin读取格式化的数据。
1. 基本用法
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. 安全输入和宽度限制
为了避免缓冲区溢出,应始终指定最大读取宽度:
1 2 3 4 5 6 7 8 9 10 11
| char name[11];
scanf("%s", name);
scanf("%10s", name);
int x, y, z; scanf("%d %d %d", &x, &y, &z);
|
4. 输入格式控制
1 2 3 4 5 6 7
| int year, month, day;
printf("请输入日期(YYYY-MM-DD):"); scanf("%d-%d-%d", &year, &month, &day);
printf("日期:%d年%02d月%02d日\n", year, month, day);
|
5. 赋值忽略符*
如果输入格式可能变化,可以使用赋值忽略符跳过不需要的部分:
1 2 3 4 5 6
| int year, month, day;
scanf("%d%*c%d%*c%d", &year, &month, &day);
printf("解析结果:%d年%02d月%02d日\n", year, month, day);
|
scanf()成功时返回成功赋值的变量数量,失败或遇到文件结尾时返回EOF。
四、sscanf()函数:从字符串中解析数据
sscanf()与scanf()类似,但数据来源不是标准输入,而是字符串。
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():读取单个字符
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| #include <stdio.h>
int main(void) { int ch; printf("请输入一个字符:"); ch = getchar(); printf("你输入的字符是:"); putchar(ch); putchar('\n'); return 0; }
|
getchar()不会跳过空白字符(空格、制表符、换行符)。
2. putchar():输出单个字符
1 2 3 4 5 6
| putchar('A'); putchar('\n');
printf("%c\n", 'A');
|
3. 实用技巧
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()) == ' ') ;
|
由于getchar()和putchar()通常用宏实现,比scanf()和printf()更快,处理单个字符时应优先使用。
六、puts()函数:输出字符串并换行
puts()用于输出字符串,并自动在末尾添加换行符。
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标准中废除。
1 2 3 4
| char buffer[10]; printf("请输入:"); gets(buffer);
|
替代方案:使用安全的fgets()函数:
1 2 3 4 5
| char buffer[10]; printf("请输入:");
fgets(buffer, sizeof(buffer), stdin);
|
八、I/O函数综合应用示例
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); 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('\n'); for (int i = 0; i < 40; i++) { putchar('='); } putchar('\n'); printf("信息登记完成!\n"); return 0; }
|
九、最佳实践总结
- 安全性第一:使用
fgets()代替gets(),为scanf()的字符串指定宽度限制
- 错误检查:检查
scanf()、fgets()等函数的返回值
- 清空缓冲区:混合使用
scanf()和fgets()时,注意清空输入缓冲区
- 选择合适函数:
- 格式化输出用
printf()
- 格式化输入用
scanf()
- 单字符I/O用
getchar()/putchar()
- 字符串输出用
puts()
- 效率考虑:处理单个字符时优先使用
getchar()/putchar()
十、结语
C语言的I/O函数虽然基础,但功能强大、灵活。掌握这些函数,你就掌握了程序与用户交互的钥匙。记住:
printf()是你的输出工具包
scanf()是你的输入解析器
getchar()/putchar()是高效字符处理器
puts()是简单字符串输出器
- 永远不要使用
gets()
现在,尝试编写一个程序,使用这些I/O函数创建一个简单的用户信息收集系统,体验C语言I/O的强大功能吧!