std::scanf, std::fscanf, std::sscanf
| 定义于头文件 <cstdio>
|
||
int scanf( const char* format, ... );
|
(1) | |
int fscanf( std::FILE* stream, const char* format, ... );
|
(2) | |
int sscanf( const char* buffer, const char* format, ... );
|
(3) | |
从多种来源读取数据,按照 format 解释并将其结果存储到给定位置。
stream 读取数据。buffer 读取数据。参数
| stream | - | 要读取的输入文件流 |
| buffer | - | 指向要读取的空终止字符串的指针 |
| format | - | 指向指定如何读取输入的空终止字符串的指针 |
| ... | - | 接收参数 |
format 字符串由下列组成
- 非空白多字节字符(
%除外):格式字符串中的每个此类字符从输入流消耗一个完全相同的字符,如果流中的下一个字符不相等,则导致函数失败。 - 空白字符:格式字符串中的任何单个空白字符消耗输入中所有可用的连续空白字符(通过循环调用 std::isspace 来确定)。注意格式字符串中的
"\n"、" "、"\t\t"或其他空白之间没有区别。 - 转换说明。每个转换说明具有以下格式:
- 引入的
%字符。
- 引入的
- (可选) 赋值禁止字符
*。如果出现此选项,函数不会将转换结果赋值给任何接收参数。
- (可选) 赋值禁止字符
- (可选) 指定 最大字段宽度 的整数(大于零),即执行当前转换说明所指定的转换时,函数允许消耗的最大字符数。注意如果未指定宽度,
%s和%[可能导致缓冲区溢出。
- (可选) 指定 最大字段宽度 的整数(大于零),即执行当前转换说明所指定的转换时,函数允许消耗的最大字符数。注意如果未指定宽度,
- (可选) 长度修饰符,指定接收参数的大小,即实际的目标类型。这会影响转换精度和溢出规则。默认目标类型因转换类型而异(见下表)。
- 转换格式说明符。
以下格式说明符可用:
| 转换 说明符 |
解释 | 预期 参数类型 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 长度修饰符→ | hh
|
h
|
无 | l
|
ll
|
j
|
z
|
t
|
L
| |
| 仅在 C++11 起可用→ | 是 | 是 | 是 | 是 | 是 | |||||
%
|
匹配字面量
%。 |
N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A | N/A |
c
|
匹配一个 字符 或一个 字符 序列。
|
N/A | N/A | char* |
wchar_t* |
N/A | N/A | N/A | N/A | N/A |
s
|
匹配一系列非空白字符(字符串)。
| |||||||||
[set ]
|
匹配来自 set 字符集的非空字符序列。
| |||||||||
d
|
匹配一个十进制整数。
|
signed char* 或 unsigned char* |
signed short* 或 unsigned short* |
signed int* 或 unsigned int* |
signed long* 或 unsigned long* |
signed long long* 或 unsigned long long* |
std::intmax_t* 或 std::uintmax_t* |
std::size_t* |
std::ptrdiff_t* |
N/A |
b (C++26)
|
匹配一个无符号二进制整数。
| |||||||||
i
|
匹配一个整数。
| |||||||||
u
|
匹配一个无符号十进制整数。
| |||||||||
o
|
匹配一个无符号八进制整数。
| |||||||||
xX
|
匹配一个无符号十六进制整数。
| |||||||||
n
|
返回到目前为止读取的字符数。
| |||||||||
a (C++11)A (C++11)eEfF (C++11)gG
|
匹配一个浮点数。
|
N/A | N/A | float* |
double* |
N/A | N/A | N/A | N/A | long double* |
p
|
匹配一个实现定义的定义指针的字符序列。
|
N/A | N/A | void** |
N/A | N/A | N/A | N/A | N/A | N/A |
| 注解 | ||||||||||
|
对于除 除 除 转换说明符 转换说明符 定宽整数类型(std::int8_t 等)的正确转换说明在头文件 <cinttypes> 中定义(尽管 SCNdMAX、SCNuMAX 等与 每个转换说明符的动作之后有一个序列点;这允许将多个字段存储到同一个“汇”变量中。 当解析一个不完整的浮点值,该值以指数结尾而无数字时,例如使用转换说明符 如果转换说明无效,则行为未定义。 | ||||||||||
返回值
成功赋值的接收参数的数量(如果在赋值第一个接收参数之前发生匹配失败,则可能为 0),或者如果在赋值第一个接收参数之前发生输入失败,则为 EOF。
复杂度
无保证。值得注意的是,某些 std::sscanf 的实现是 O(N),其中 N = std::strlen(buffer) [1]。对于高性能的字符串解析,请参见 std::from_chars。
注解
因为大多数转换说明符首先会消耗所有连续空白,所以代码如
std::scanf("%d", &a);
std::scanf("%d", &b);
将读取在不同行上输入的两个整数(第二个 %d 会消耗第一个留下的换行符)或在同一行上,由空格或制表符分隔(第二个 %d 会消耗空格或制表符)。
不消耗前导空白的转换说明符(例如 %c)可以通过在格式字符串中使用空白字符来使其消耗:
std::scanf("%d", &a);
std::scanf(" %c", &c); // ignore the endline after %d, then read a char
注意某些 std::sscanf 的实现会调用 std::strlen,使得其运行时间与整个字符串的长度成线性关系。这意味着如果在循环中重复调用 std::sscanf 来从字符串前端解析值,代码可能会以二次时间运行(示例)。
示例
#include <clocale>
#include <cstdio>
#include <iostream>
int main()
{
int i, j;
float x, y;
char str1[10], str2[4];
wchar_t warr[2];
std::setlocale(LC_ALL, "en_US.utf8");
char input[] = "25 54.32E-1 Thompson 56789 0123 56ß水";
// parse as follows:
// %d: an integer
// %f: a floating-point value
// %9s: a string of at most 9 non-whitespace characters
// %2d: two-digit integer (digits 5 and 6)
// %f: a floating-point value (digits 7, 8, 9)
// %*d an integer which isn't stored anywhere
// ' ': all consecutive whitespace
// %3[0-9]: a string of at most 3 digits (digits 5 and 6)
// %2lc: two wide characters, using multibyte to wide conversion
const int ret = std::sscanf(input, "%d%f%9s%2d%f%*d %3[0-9]%2lc",
&i, &x, str1, &j, &y, str2, warr);
std::cout << "Converted " << ret << " fields:\n"
"i = " << i << "\n"
"x = " << x << "\n"
"str1 = " << str1 << "\n"
"j = " << j << "\n"
"y = " << y << "\n"
"str2 = " << str2 << std::hex << "\n"
"warr[0] = U+" << (int)warr[0] << "\n"
"warr[1] = U+" << (int)warr[1] << '\n';
}
输出:
Converted 7 fields:
i = 25
x = 5.432
str1 = Thompson
j = 56
y = 789
str2 = 56
warr[0] = U+df
warr[1] = U+6c34
参阅
(C++11)(C++11)(C++11) |
从 stdin、文件流或缓冲区 使用可变参数列表读取格式化输入 (函数) |
| 从文件流获取一个字符串 (函数) | |
(C++11) |
打印格式化输出到 stdout、文件流或缓冲区 (函数) |
(C++17) |
将字符序列转换为整数或浮点值 (函数) |
C 文档关于 scanf、fscanf、sscanf
| |