std::scanf, std::fscanf, std::sscanf
| 在标头 <cstdio> 定义
|
||
| |
(1) | |
| |
(2) | |
| |
(3) | |
从各种源读取数据,按照 format 进行转换并存储结果于给定位置。
stream 读数据。buffer 读数据。参数
| stream | - | 读取来源的文件流 |
| buffer | - | 指向读取数据来源的空终止字符串 |
| format | - | 指向空终止字符串的指针,指定如何读取输入 |
| ... | - | 接收的参数 |
格式字符串由下列内容组成
- 非空白多字节字符,除了
%:每个格式字符串中的这种字符处理一个来自输入流的完全相同的字符,或在它与流的下个字符比较不相等时导致函数失败。 - 空白字符:任何格式字符串中的单个空白字符处理所有来自输入的可用连续空白字符(如同通过于循环中调用 std::isspace 确定)。注意,格式字符串中
"\n"、" "、"\t\t"或其他空白无区别。 - 转换指示:每个转换指示拥有下列格式:
- 引入用
%字符
- 引入用
- (可选) 赋值抑制字符
*。如果存在此选项,那么此函数不将结果赋值给任何接收用实参。
- (可选) 赋值抑制字符
- (可选) 指定最大字段宽度 的整数数字(大于零),即函数进行在当前转换指示所指定的转换时,允许处理的最大字符数。注意如果没有提供宽度,那么
%s和%[可能导致缓冲区溢出。
- (可选) 指定最大字段宽度 的整数数字(大于零),即函数进行在当前转换指示所指定的转换时,允许处理的最大字符数。注意如果没有提供宽度,那么
- (可选) 指定接收实参大小的长度修饰符,即实际目标类型。这影响转换准确性和溢出规则。默认目标类型对每个转换类型有所不同(见下表)。
- 转换格式指示符。
下列格式指示符可用:
| 转换指示符 | 解释 | 期望的实参类型 | ||||||||
|---|---|---|---|---|---|---|---|---|---|---|
| 长度修饰符→ | hh | h | 无 | l | ll | j | z | t | L | |
| 仅从 C++11 起可用→ | 是 | 是 | 是 | 是 | 是 | |||||
%
|
匹配字面
%。 |
不适用 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 |
c
|
匹配一个字符或字符的序列。
|
不适用 | 不适用 | char* |
wchar_t* |
不适用 | 不适用 | 不适用 | 不适用 | 不适用 |
s
|
匹配非空白字符的序列(一个字符串)。
| |||||||||
[集合 ]
|
匹配集合 中的字符的一个非空字符序列。
| |||||||||
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* |
不适用 |
i
|
匹配一个整数。
| |||||||||
u
|
匹配一个无符号十进制整数。
| |||||||||
o
|
匹配一个无符号八进制数。
| |||||||||
xX
|
匹配一个无符号十六进制整数。
| |||||||||
n
|
返回迄今读取的字符数。
| |||||||||
a (C++11)A (C++11)eEfF (C++11)gG
|
匹配一个浮点数。
|
不适用 | 不适用 | float* |
double* |
不适用 | 不适用 | 不适用 | 不适用 | long double* |
p
|
匹配定义了一个指针的由实现定义的字符序列。
|
不适用 | 不适用 | void** |
不适用 | 不适用 | 不适用 | 不适用 | 不适用 | 不适用 |
| 注解 | ||||||||||
|
对于每个 所有异于 转换指示符 转换指示符 定宽整数类型(std::int8_t 等)的正确的转换指示在标头 <cinttypes> 定义(虽然 SCNdMAX、SCNuMAX 等就是 在每个转换指示符后有一个序列点;这允许存储多个字段到同一“池”变量中。 在分析以无数字指数为结尾的不完整浮点数,如以转换指示符 如果转换指示非法,那么行为未定义。 | ||||||||||
返回值
成功赋值的接收实参个数(在首个接收实参被赋值前发生匹配失败的情况下可为零),或若在首个接收实参被赋值前发生输入失败则为 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); // 忽略 %d 后的换行符,然后读一个 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[] = u8"25 54.32E-1 Thompson 56789 0123 56ß水";
// 按如下分析:
// %d:整数
// %f:浮点数
// %9s:至多 9 个非空白字符的字符串
// %2d:二位整数(数字 5 与 6)
// %f:浮点数(数字 7、8、9)
// %*d 不存储于任何位置的整数
// ' ':所有连续空白符
// %3[0-9]:至多 3 位数字的字符串(数字 5 与 6)
// %2lc:两个宽字符,用多字节到宽转换
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 << "转换了 " << ret << " 个字段:\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';
}
输出:
转换了 7 个字段:
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) |
转换字符序列到整数或浮点数 (函数) |
scanf, fscanf, sscanf 的 C 文档
| |