1. scanf
(标准输入)
功能:从标准输入(stdin,通常是键盘)读取格式化数据。
//原型:
int scanf(const char *format, ...);
//示例
int num;
scanf("%d", &num); // 从键盘读取整数
特点:
- 适用于交互式输入(如用户键盘输入)。
- 容易因缓冲区问题导致错误(如换行符残留)。
- 不安全,可能导致缓冲区溢出(如
%s
读取字符串时不检查长度)。
2. fscanf
(文件输入)
功能:从指定的文件流(FILE*)读取格式化数据。
// 原型:
int fscanf(FILE *stream, const char *format, ...);
// 示例:
FILE *file = fopen("data.txt", "r");
int num;
fscanf(file, "%d", &num); // 从文件读取整数
fclose(file);
特点:
- 适用于从文件读取结构化数据(如配置文件、日志文件)。
- 返回值可检测是否成功读取(如文件结束时返回
EOF
)。 - 和
scanf
一样,存在缓冲区溢出风险。
3. sscanf
(字符串输入)
功能:从字符串(const char*)读取格式化数据。
//原型
int sscanf(const char *str, const char *format, ...);
// 示例
char line[] = "42 3.14 hello";
int num;
float f;
char str[20];
sscanf(line, "%d %f %s", &num, &f, str); // 从字符串解析数据
特点:
- 适用于解析字符串(如解析
fgets
读取的行)。 - 比
scanf
和fscanf
更安全,因为输入来源是内存中的字符串,无溢出风险。 - 常用于数据转换(如将字符串转为数字)。
三者的核心区别
函数 |
数据来源 |
典型用途 |
安全性 |
|
标准输入(键盘) |
交互式输入 |
❌ 不安全 |
|
文件( |
读取文件数据 |
❌ 不安全 |
|
字符串( |
解析字符串(如 |
✅ 较安全 |
使用场景对比
1. 从键盘输入(scanf
)
int age;
printf("please input age:");
scanf("%d", &age); // 直接从键盘读取
问题:
- 如果输入非数字(如
abc
),会导致无限循环或错误。 - 换行符可能残留在缓冲区,影响后续输入。
改进方案:
用 fgets
+ sscanf
替代:
int age;
char input[100];
printf("please input age\n");
fgets(input, sizeof(input), stdin); // 先读取一行
sscanf(input, "%d", &age); // 再从字符串解析
printf("input age is: %d\n", age);
2. 从文件读取(fscanf
)
FILE *file = fopen("data.txt", "r");
int num;
int count = fscanf(file, "%d", &num);
while ((count != EOF) && (count != 0)) // 0 is meet unmatch data
{
printf("input date is %d, count = %d\n", num, count);
count = fscanf(file, "%d", &num);
}
fclose(file);
适用场景:
- 读取格式化的文件数据(如每行一个数字)。
3. 从字符串解析(sscanf
)
char data[] = "Alice 25 80.5";
char name[50];
int age;
float score;
sscanf(data, "%s %d %f", name, &age, &score);
适用场景:
- 解析命令行参数、网络数据或文本文件的行。
安全性对比
函数 |
缓冲区溢出风险 |
换行符问题 |
推荐使用场景 |
|
高( |
有( |
安全性低,简单输入 |
|
高(同 |
无(文件无交互) |
读取格式化文件 |
|
低(字符串长度已知) |
无 |
解析字符串 |
最佳实践
- 避免直接用
scanf
:
-
- 用
fgets
+sscanf
组合更安全。
- 用
char input[100];
fgets(input, sizeof(input), stdin); // 安全读取一行
int num;
sscanf(input, "%d", &num); // 安全解析
- 文件读取时检查
fscanf
返回值:
防止文件格式错误:
while (fscanf(file, "%d", &num) == 1) { ... } // add check return is 0 or not
sscanf
的高级用法:
跳过部分数据:
sscanf("2023-12-31", "%d-%d-%d", &year, &month, &day);
限制字符串长度:
char name[10];
sscanf(data, "%9s", name); // 最多读取 9 个字符