C. scanf 函数基础
scanf 函数
- 1. scanf 函数基础
- 1.1 函数原型与头文件
- 1.2 格式化输入的基本概念
- 2.1 常见格式说明符
- 整数格式说明符
- 浮点数格式说明符
- 字符和字符串格式说明符
- 其他格式说明符
- 2.2 格式说明符的高级用法
- 宽度修饰符
- 精度修饰符
- 跳过输入
- 字段宽度
- 组合修饰符
- 对齐修饰符
- 实际应用示例
- 3.2 精度控制
- 浮点数精度
- 字符串精度
- 动态精度
- 实际应用示例
- 4.1 返回值的含义
- 4.2 返回值的应用场景
- 4.2.1 输入校验
- 4.2.2 循环读取输入
- 4.2.3 动态调整输入逻辑
- 4.2.4 调试与日志记录
- 5.1 格式化字符串漏洞
- 格式化字符串漏洞的成因
- 格式化字符串漏洞的利用
- 格式化字符串漏洞的实例
- 5.2 安全使用建议
- 1. 避免用户可控的格式化字符串
- 2. 确保格式说明符与参数匹配
- 3. 使用安全的格式化函数
- 4. 检查 `scanf` 的返回值
- 5. 避免使用 `%n` 格式说明符
- 6. 使用编译器的安全检查功能
- 6.1 fscanf
- 使用场景
- 返回值
- 6.2 sscanf
- 使用场景
- 返回值
- 7.1 日常编程中的使用场景
- 1. 输入用户数据
- 2. 读取配置文件
- 3. 输入表格数据
- 4. 输入带条件的数据
- 5. 输入带时间戳的数据
- 7.2 复杂格式化输入示例
- 1. 输入多行格式化数据
- 2. 动态格式化输入
- 3. 输入带有颜色的文本
- 4. 输入带有条件的文本
- 5. 输入带有时间戳的日志信息
1. scanf 函数基础
1.1 函数原型与头文件
scanf
函数是 C 语言中用于格式化输入的标准函数,其函数原型定义在头文件 <stdio.h>
中。具体原型如下:
int scanf(const char *format, ...);
const char *format
:格式控制字符串,用于指定输入的格式。它由普通字符和格式说明符组成。普通字符用于匹配输入中的相同字符,而格式说明符则用于指定后续参数的输入格式。...
:表示可变参数列表,这些参数是用于存储输入数据的变量的地址。每个格式说明符对应一个参数,参数的类型必须与格式说明符匹配。
在使用 scanf
函数时,必须包含头文件 <stdio.h>
,否则编译器将无法识别该函数。
1.2 格式化输入的基本概念
scanf
函数通过格式控制字符串来实现灵活的输入。格式控制字符串中的格式说明符以 %
开头,后跟一个或多个字符,用于指定输入数据的类型和格式。以下是一些常见的格式说明符及其含义:
格式说明符 | 含义 |
---|---|
%d 或 %i | 输入有符号十进制整数。例如:scanf("%d", &var); 输入 123 ,var 的值为 123 。 |
%u | 输入无符号十进制整数。例如:scanf("%u", &var); 输入 456 ,var 的值为 456 。 |
%f | 输入浮点数。例如:scanf("%f", &var); 输入 3.14 ,var 的值为 3.14 。 |
%c | 输入单个字符。例如:scanf("%c", &var); 输入 A ,var 的值为 A 。 |
%s | 输入字符串。例如:scanf("%s", str); 输入 Hello ,str 的值为 "Hello" 。 |
%p | 输入指针地址。例如:scanf("%p", &ptr); 输入地址,ptr 的值为该地址。 |
%% | 输入一个百分号 % 。例如:scanf("%%", &var); 输入 % ,var 的值为 % 。 |
格式说明符还可以包含一些可选的修饰符,用于控制输入的宽度、精度、对齐方式等。以下是一些常见的修饰符及其用法:
-
宽度修饰符:指定输入的最大宽度。对于字符串,指定最大输入字符数。例如:
char str[10]; scanf("%9s", str); // 最多读取 9 个字符
-
精度修饰符:对于浮点数,指定小数点后的位数。例如:
float var; scanf("%f", &var); // 默认读取浮点数
-
对齐修饰符:
-
用于左对齐,+
用于强制输出正负号,空格用于在正数前输出空格。例如:int var; scanf("%d", &var); // 默认读取整数
通过合理使用格式说明符和修饰符,scanf
函数可以实现灵活多样的格式化输入,满足各种编程需求。# 2. 格式说明符详解
2.1 常见格式说明符
scanf
函数的格式说明符是实现格式化输入的核心,以下是一些常见的格式说明符及其详细用法:
整数格式说明符
-
%d
或%i
:用于输入有符号十进制整数。这是最常用的整数格式说明符,适用于正负整数。int var; scanf("%d", &var); // 输入 123,var 的值为 123
-
%u
:用于输入无符号十进制整数。它适用于非负整数,输入时不会显示负号。unsigned int var; scanf("%u", &var); // 输入 456,var 的值为 456
-
%o
:用于输入无符号八进制整数。输入时需要以八进制形式输入,不显示前缀0
。int var; scanf("%o", &var); // 输入 377,var 的值为 255
-
%x
或%X
:用于输入无符号十六进制整数。%x
输入小写字母,%X
输入大写字母。int var; scanf("%x", &var); // 输入 ff,var 的值为 255 scanf("%X", &var); // 输入 FF,var 的值为 255
浮点数格式说明符
-
%f
:用于输入十进制浮点数。默认情况下,scanf
会读取小数点和数字,直到遇到非数字字符为止。float var; scanf("%f", &var); // 输入 3.14159,var 的值为 3.14159
-
%e
或%E
:用于输入科学计数法表示的浮点数。%e
输入小写字母e
,%E
输入大写字母E
。float var; scanf("%e", &var); // 输入 3.14159e+00,var 的值为 3.14159 scanf("%E", &var); // 输入 3.14159E+00,var 的值为 3.14159
字符和字符串格式说明符
-
%c
:用于输入单个字符。输入时只读取一个字符,包括空格和换行符。char var; scanf("%c", &var); // 输入 A,var 的值为 'A'
-
%s
:用于输入字符串。输入时会读取连续的字符,直到遇到空格、制表符或换行符为止。char str[10]; scanf("%s", str); // 输入 Hello,str 的值为 "Hello"
其他格式说明符
-
%p
:用于输入指针地址。输入时需要输入一个有效的指针地址。int *ptr; scanf("%p", &ptr); // 输入地址,ptr 的值为该地址
-
%%
:用于输入一个百分号%
。输入时需要输入一个%
符号。char var; scanf("%%", &var); // 输入 %,var 的值为 '%'
2.2 格式说明符的高级用法
格式说明符还可以结合多种修饰符来实现更复杂的格式化输入,以下是一些高级用法:
宽度修饰符
宽度修饰符用于指定输入的最大宽度。对于字符串,指定最大输入字符数。可以通过以下方式指定宽度:
-
固定宽度:直接指定一个整数。
char str[10]; scanf("%9s", str); // 最多读取 9 个字符
-
动态宽度:使用
*
表示宽度由后续参数指定。int width = 9; scanf("%*s", &width, str); // 最多读取 9 个字符
精度修饰符
精度修饰符用于控制输入的精度,对于浮点数和字符串有不同的含义:
-
浮点数:指定小数点后的位数。
float var; scanf("%f", &var); // 默认读取浮点数
-
字符串:指定最大输入长度。
char str[10]; scanf("%.9s", str); // 最多读取 9 个字符
跳过输入
使用 *
修饰符可以跳过某些输入项,不将其存储到变量中。例如:
int a, b;
scanf("%d %*d %d", &a, &b); // 输入 1 2 3,a 的值为 1,b 的值为 3
字段宽度
字段宽度修饰符用于指定输入字段的宽度。对于字符串,指定最大输入字符数。对于数字,指定最大输入数字的位数。例如:
int a;
scanf("%3d", &a); // 输入 1234,a 的值为 123
组合修饰符
可以将多种修饰符组合使用,以实现复杂的格式化需求:
char str[10];
scanf("%-9.5s", str); // 最多读取 9 个字符,字符串的最大长度为 5
```# 3. 输入控制与格式化
## 3.1 宽度与对齐`scanf` 函数通过宽度修饰符和对齐修饰符来控制输入的宽度和