C语言学习笔记20260713-格式化输入输出家族汇总
C语言学习笔记20260713-格式化输入输出家族汇总
核心概念:这组函数本质相同,区别仅在于数据源(Source)和目的地(Destination)不同。
头文件:<stdio.h>
核心对比总览
| 函数族 | 函数名 | 数据来源 (Input) | 数据去向 (Output) | 典型应用场景 |
|---|---|---|---|---|
| 标准 I/O | scanf | 键盘 (stdin) | 内存变量 | 用户交互输入 |
printf | 内存变量 | 屏幕 (stdout) | 打印结果、日志 | |
| 文件 I/O | fscanf | 文件指针 (FILE*) | 内存变量 | 读取配置文件、解析文本数据 |
fprintf | 内存变量 | 文件指针 (FILE*) | 写入日志文件、保存数据 | |
| 字符串 I/O | sscanf | 字符串 (char*) | 内存变量 | 解析字符串中的特定数据(如提取 IP) |
sprintf | 内存变量 | 字符串 (char*) | 拼接字符串、数字转字符串 |
1. 标准输入输出:人机交互
这是最基础的函数,默认绑定到控制台(黑窗口)。
scanf:等待用户在键盘敲击并回车,将数据读入变量。printf:将变量的内容显示在屏幕上。
代码示例
#include<stdio.h>intmain(){intage;// printf: 提示用户输入printf("请输入你的年龄: ");// scanf: 从键盘读取整数存入 age// 注意:这里必须加 & 取地址符if(scanf("%d",&age)==1){// printf: 格式化输出结果printf("你今年 %d 岁了。\n",age);}else{printf("输入无效!\n");}return0;}2. 文件流操作:持久化存储
这两个函数比标准 I/O 多了一个参数FILE *stream,用于指定操作哪个文件。
fscanf:从文件中按格式读取数据。fprintf:按格式将数据写入文件。
代码示例
#include<stdio.h>intmain(){FILE*fp=fopen("data.txt","w+");if(!fp)return1;charname[50]="Alice";intscore=98;// fprintf: 将数据格式化写入文件// 类似于 printf,但第一个参数是文件指针fprintf(fp,"Name: %s, Score: %d\n",name,score);// 重置文件指针到开头以便读取rewind(fp);charread_name[50];intread_score;// fscanf: 从文件读取格式化数据// 类似于 scanf,但第一个参数是文件指针if(fscanf(fp,"Name: %s, Score: %d",read_name,&read_score)==2){printf("读取成功 -> 姓名: %s, 分数: %d\n",read_name,read_score);}fclose(fp);return0;}3. 字符串流操作:内存中的转换
这两个函数不依赖外部设备或文件,直接在内存中的字符数组(字符串)进行操作。
sscanf(String Scan):从一个已存在的字符串中提取数据。sprintf(String Print):将各种类型的数据拼接到一个字符串中。
场景 A:使用sscanf解析复杂字符串
假设你有一个字符串"2023-10-05",想把它拆分成年、月、日。
#include<stdio.h>intmain(){constchar*date_str="2023-10-05";intyear,month,day;// sscanf: 从 date_str 中按 "-" 分割提取整数// 返回值是成功匹配并赋值的变量个数intcount=sscanf(date_str,"%d-%d-%d",&year,&month,&day);if(count==3){printf("解析成功: %d 年 %d 月 %d 日\n",year,month,day);}return0;}场景 B:使用sprintf拼接/转换字符串
假设你想把多个变量拼成一句话,或者把数字变成字符串。
#include<stdio.h>intmain(){charbuffer[100];// 目标缓冲区,必须足够大intid=1001;doubleprice=99.5;// sprintf: 将数据格式化写入 buffer 字符串// 注意:如果数据太长超过 buffer 大小,会发生溢出(危险!)sprintf(buffer,"ID: %d, Price: %.2f USD",id,price);printf("生成的字符串: %s\n",buffer);// 应用:数字转字符串charnum_str[20];sprintf(num_str,"%d",12345);printf("数字转字符串: %s\n",num_str);return0;}⚠️ 安全提示与最佳实践
sprintf的隐患:sprintf不检查目标缓冲区的大小,容易导致缓冲区溢出。- 推荐替代方案:使用
snprintf(buffer, size, ...),它可以限制写入的最大长度,更加安全。
// 安全写法:限制最多写入 sizeof(buffer)-1 个字符snprintf(buffer,sizeof(buffer),"ID: %d",id);scanf的隐患:- 读取字符串时如果不限制长度(如
%s),用户输入过长也会导致溢出。 - 推荐写法:
scanf("%19s", str)(假设str大小为 20)。
- 读取字符串时如果不限制长度(如
返回值检查:
- 所有的
scanf系列函数都会返回成功匹配并赋值的项数。务必检查返回值以确保数据解析正确。
- 所有的
总结
C 语言的格式化输入输出家族提供了灵活的数据处理能力:
- 标准 I/O用于人机交互
- 文件 I/O用于数据持久化
- 字符串 I/O用于内存中的数据转换和解析
掌握这些函数的区别和使用场景,能够让你在处理各种数据输入输出任务时更加得心应手。记住安全第一,始终检查返回值并使用安全的替代函数(如snprintf)。
