Spec-Zone.ru › C++

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 и сохраняет результаты в указанных местах.

1) Считывает данные из stdin.
2) Считывает данные из файлового потока stream.
3) Считывает данные из строки символов с завершающим нулевым символом buffer.

Параметры

stream - входной файловый поток для чтения
buffer - указатель на строку символов с завершающим нулевым символом, из которой выполняется чтение
format - указатель на строку символов с завершающим нулевым символом, задающую способ чтения входных данных
... - принимающие аргументы

Строка format состоит из

  • непробельных многобайтовых символов, кроме %: каждый такой символ в строке формата считывает из входного потока ровно один идентичный символ или приводит к ошибке функции, если следующий символ в потоке не равен ему.
  • пробельных символов: любой одиночный пробельный символ в строке формата считывает из входных данных все доступные идущие подряд пробельные символы (определяется так, как если бы в цикле вызывалась std::isspace). Обратите внимание, что между "\n", " ", "\t\t" и другими пробельными символами в строке формата нет разницы.
  • спецификаторов преобразования. Каждый спецификатор преобразования имеет следующий формат:
    • начальный символ %.
    • (необязательно) символ подавления присваивания *. Если этот параметр указан, функция не присваивает результат преобразования ни одному принимающему аргументу.
    • (необязательно) целое число (больше нуля), задающее максимальную ширину поля, то есть максимальное количество символов, которое функция может считывать при выполнении преобразования, заданного текущим спецификатором преобразования. Обратите внимание, что %s и %[ могут привести к переполнению буфера, если ширина не указана.
    • (необязательно) модификатор длины, задающий размер принимающего аргумента, то есть фактический тип назначения. Он влияет на точность преобразования и правила переполнения. Тип назначения по умолчанию различается для разных типов преобразования (см. таблицу ниже).
    • спецификатор формата преобразования.

Доступны следующие спецификаторы формата:

Спецификатор
преобразования
Описание Ожидаемый
тип аргумента
Модификатор длины→ hh h нет l ll j z t L
Доступен только начиная с C++11→ Да Да Да Да Да
% Соответствует литеральному символу %. Н/П Н/П Н/П Н/П Н/П Н/П Н/П Н/П Н/П
c

Соответствует символу или последовательности символов.

  • Если используется спецификатор ширины, соответствует ровно width символам (аргумент должен быть указателем на массив достаточного размера).
  • В отличие от %s и %[, не добавляет нулевой символ в массив.
Н/П Н/П
char*
wchar_t*
Н/П Н/П Н/П Н/П Н/П
s

Соответствует последовательности непробельных символов (строке).

  • Если используется спецификатор ширины, соответствует не более чем width символам или до первого пробельного символа — в зависимости от того, что наступит раньше.
  • Всегда сохраняет нулевой символ в дополнение к совпавшим символам (поэтому в массиве аргумента должно быть место как минимум для width+1 символов).
[set ]

Соответствует непустой последовательности символов из набора символов set.

  • Если первый символ набора — ^, соответствуют все символы, не входящие в набор.
  • Если набор начинается с ] или ^], символ ] также включается в набор.
  • Определяется реализацией, может ли символ -, находящийся не в начале сканируемого набора, обозначать диапазон, как в [0-9].
  • Если используется спецификатор ширины, соответствует не более чем width символам.
  • Всегда сохраняет нулевой символ в дополнение к совпавшим символам (поэтому в массиве аргумента должно быть место как минимум для width+1 символов).
d

Соответствует десятичному целому числу.

  • Формат числа совпадает с форматом, ожидаемым функцией std::strtol при значении 10 для аргумента base.
signedchar* or unsignedchar*
signedshort* or unsignedshort*
signedint* or unsignedint*
signedlong* or unsignedlong*
signedlonglong* or unsignedlonglong*
std::intmax_t* or std::uintmax_t*
std::size_t*
std::ptrdiff_t*
Н/П
b (C++26)

Соответствует беззнаковому двоичному целому числу.

  • Формат числа совпадает с форматом, ожидаемым функцией std::strtoul при значении 2 для аргумента base.
i

Соответствует целому числу.

  • Формат числа совпадает с форматом, ожидаемым функцией std::strtol при значении 0 для аргумента base (основание определяется по первым разобранным символам).
u

Соответствует беззнаковому десятичному целому числу.

  • Формат числа совпадает с форматом, ожидаемым функцией std::strtoul при значении 10 для аргумента base.
o

Соответствует беззнаковому восьмеричному целому числу.

  • Формат числа совпадает с форматом, ожидаемым функцией std::strtoul при значении 8 для аргумента base.
x
X

Соответствует беззнаковому шестнадцатеричному целому числу.

  • Формат числа совпадает с форматом, ожидаемым функцией std::strtoul при значении 16 для аргумента base.
n

Возвращает количество символов, считанных к данному моменту.

  • Ввод не потребляется. Счётчик присваиваний не увеличивается.
  • Если для спецификатора задан оператор подавления присваивания, поведение не определено.
a (C++11)
A (C++11)
e
E
f
F (C++11)
g
G

Соответствует числу с плавающей точкой.

  • Формат числа совпадает с форматом, ожидаемым функцией std::strtof.
Н/П Н/П
float*
double*
Н/П Н/П Н/П Н/П
longdouble*
p

Соответствует определяемой реализацией последовательности символов, представляющей указатель.

  • Семейство функций printf должно создавать ту же последовательность с помощью спецификатора формата %p.
Н/П Н/П
void**
Н/П Н/П Н/П Н/П Н/П Н/П
Примечания

Для каждого спецификатора преобразования, кроме n, из потока считывается самая длинная последовательность входных символов, которая не превышает указанную ширину поля и либо в точности соответствует ожидаемой спецификатором преобразования последовательности, либо является её префиксом. Первый символ после этой считанной последовательности, если он есть, остаётся непрочитанным. Если длина считанной последовательности равна нулю или её невозможно преобразовать указанным выше способом, возникает ошибка сопоставления, если только ввод из потока не был прерван концом файла, ошибкой кодирования или ошибкой чтения; в таком случае возникает ошибка ввода.

За исключением спецификатора %, элемент ввода (или, для %n, количество входных символов) сначала преобразуется в тип, соответствующий спецификатору преобразования. Если присваивание не было подавлено с помощью *, результат преобразования записывается в объект, на который указывает следующий аргумент, ещё не использованный для записи. Если этот объект имеет неподходящий тип или результат преобразования не может быть в нём представлен, поведение не определено.

Все спецификаторы преобразования, кроме [, c и n, перед попыткой разобрать входные данные считывают и отбрасывают все начальные пробельные символы (определяемые так, как если бы вызывалась std::isspace). Эти считанные символы не учитываются в указанной максимальной ширине поля.

Спецификаторы преобразования lc, ls и l[ выполняют преобразование многобайтовых символов в широкие так, как если бы вызывалась std::mbrtowc с объектом std::mbstate_t, инициализированным нулём перед преобразованием первого символа.

Спецификаторы преобразования s и [ всегда сохраняют завершающий нулевой символ в дополнение к совпавшим символам. Размер массива назначения должен быть как минимум на один больше указанной ширины поля. Использование %s или %[ без указания размера массива назначения так же небезопасно, как использование std::gets.

Правильные спецификации преобразования для целочисленных типов фиксированной ширины (std::int8_t и т. д.) определены в заголовочном файле <cinttypes> (хотя SCNdMAX, SCNuMAX и т. д. являются синонимами %jd, %ju и т. д.).

После выполнения каждого спецификатора преобразования происходит точка следования; это позволяет сохранять несколько полей в одной и той же переменной-приёмнике.

При разборе неполного значения с плавающей точкой, заканчивающегося показателем степени без цифр, например при разборе "100er" со спецификатором преобразования %f, считывается последовательность "100e" (самый длинный префикс потенциально допустимого числа с плавающей точкой), что приводит к ошибке сопоставления (считанную последовательность невозможно преобразовать в число с плавающей точкой), а "r" остаётся непрочитанным. Некоторые существующие реализации не следуют этому правилу и откатываются, считывая только "100" и оставляя "er", например ошибка glibc 1765.

Если спецификация преобразования недопустима, поведение не определено.

Возвращаемое значение

Количество успешно присвоенных принимающим аргументам значений (может быть равно нулю, если ошибка сопоставления произошла до присваивания первого принимающего аргумента) или 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

См. также

vscanfvfscanfvsscanf
(C++11)(C++11)(C++11)
считывает форматированный ввод из stdin, файлового потока или буфера
с использованием списка аргументов переменной длины
(функция)
fgets
считывает строку символов из файлового потока
(функция)
printffprintfsprintfsnprintf
(C++11)
выводит форматированные данные в stdout, файловый поток или буфер
(функция)
from_chars
(C++17)
преобразует последовательность символов в целое число или значение с плавающей точкой
(функция)
Документация по C для scanf, fscanf, sscanf

© cppreference.com
Licensed under the Creative Commons Attribution-ShareAlike Unported License v3.0.
https://en.cppreference.com/cpp/io/c/fscanf

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API