сканирование
Эта статья нуждается в дополнительных цитатах для проверки . ( май 2010 г. ) |
scanf , сокращение от scan formatted, — это C стандартной библиотеки функция , которая считывает и анализирует текст со стандартного ввода .
Функция принимает параметр строки формата, который определяет макет входного текста . Функция анализирует входной текст и загружает значения в переменные в зависимости от типа данных .
Подобные функции с другими именами появились раньше C, например: readf
в Алголе 68 .
Строки входного формата дополняют строки выходного формата (см. printf ), которые обеспечивают форматированный вывод ( шаблоны ).
История
[ редактировать ] Майка Леска , Портативная библиотека ввода/вывода включающая scanf
официально стал частью Unix в версии 7 . [1]
Использование
[ редактировать ]The scanf
Функция считывает ввод чисел и других типов данных со стандартного ввода .
Следующий код C считывает переменное количество неформатированных десятичных целых чисел из стандартного ввода и выводит каждое из них в отдельных строках:
#include <stdio.h>
int main(void)
{
int n;
while (scanf("%d", &n) == 1)
printf("%d\n", n);
return 0;
}
Для ввода:
456 123 789 456 12 456 1 2378
Результат:
456
123
789
456
12
456
1
2378
Чтобы распечатать слово:
#include <stdio.h>
int main(void)
{
char word[20];
if (scanf("%19s", word) == 1)
puts(word);
return 0;
}
Независимо от того, какой тип данных программист хочет прочитать, аргументы (например, &n
выше) должны быть указателями, указывающими на память. В противном случае функция не будет работать правильно, поскольку она будет пытаться перезаписать неправильные разделы памяти, вместо того, чтобы указывать на ячейку памяти переменной, для которой вы пытаетесь получить входные данные.
В последнем примере оператор адреса ( &
) не используется в качестве аргумента: поскольку word
имя массива это char
, как таковой он (во всех контекстах, в которых его результатом является адрес) эквивалентен указателю на первый элемент массива. Хотя выражение &word
будет иметь численное значение одного и того же значения, семантически оно имеет совершенно другое значение, поскольку обозначает адрес всего массива, а не его элемента. Этот факт необходимо иметь в виду при назначении scanf
вывод в строки.
Как scanf
предназначен только для чтения со стандартного ввода, многие языки программирования с интерфейсами , такие как PHP , имеют производные, такие как sscanf
и fscanf
но не scanf
сам.
Спецификации строки формата
[ редактировать ] форматирования Заполнители в scanf
более или менее такие же, как и в printf
, его обратная функция. Как и в printf, расширение POSIX n$
определяется. [2]
В строке формата редко встречаются константы (т. е. символы, не являющиеся заполнителями форматирования ), главным образом потому, что программа обычно не предназначена для чтения известных данных, хотя scanf
принимает их, если это явно указано. Исключением является один или несколько символов пробелов , которые отбрасывают все символы пробелов во входных данных. [2]
Ниже приведены некоторые из наиболее часто используемых заполнителей:
%a
: сканирование числа с плавающей запятой в шестнадцатеричном формате.%d
: Сканировать целое число как десятичное число со знаком.%i
: Сканировать целое число как число со знаком. Похоже на:%d
, но интерпретирует число как шестнадцатеричное , если ему предшествует0x
и восьмеричный, если ему предшествует0
. Например, строка031
будет читаться как 31, используя%d
и 25 с использованием%i
. Флагh
в%hi
указывает на преобразование вshort
иhh
преобразование вchar
.%u
: Сканировать десятичные числаunsigned int
(Обратите внимание, что в стандарте C99 знак минус входного значения является необязательным, поэтому, если считывается знак минус, ошибок не возникает, и результатом будет дополнение до двух отрицательного числа, вероятно, очень большое значение. См.strtoul()
. [ не удалось пройти проверку ] ) Соответственно,%hu
сканирует в поискахunsigned short
и%hhu
дляunsigned char
.%f
: сканирование числа с плавающей запятой в обычном представлении ( с фиксированной запятой ).%g
,%G
: сканирование числа с плавающей запятой в обычном или экспоненциальном представлении.%g
использует строчные буквы и%G
использует верхний регистр.%x
,%X
: Сканировать целое число как беззнаковое шестнадцатеричное число.%o
: Сканировать целое число как восьмеричное .%s
: Сканировать строку символов . Сканирование завершается на пробеле . длины . В конце строки сохраняется нулевой символ. Это означает, что предоставленный буфер должен быть как минимум на один символ длиннее указанной входной%c
: Сканировать символ (char). не Нулевой символ добавляется.- пробел : любые пробельные символы запускают сканирование на наличие нуля или более пробельных символов. Количество и тип пробельных символов не обязательно должны совпадать в любом направлении.
%lf
: Сканировать как двойное число с плавающей запятой. Формат «Float» со спецификатором «long».%Lf
: Сканировать как длинное двойное число с плавающей запятой. «Float» форматирует спецификатор «long long».%n
: Ничего не ожидается. Количество символов, использованных на данный момент от ввода, сохраняется через указатель next, который должен быть указателем на int. Это не преобразование и не увеличивает счетчик, возвращаемый функцией.
Вышеупомянутое можно использовать в сочетании с числовыми модификаторами и l
, L
модификаторы, обозначающие «long» и «long long» между символом процента и буквой. Между символом процента и буквами, предшествующими символу процента, также могут быть числовые значения. long
модификаторы, если таковые имеются, которые определяют количество сканируемых символов. Необязательная звездочка ( *
) сразу после символа процента означает, что данные, считанные этим спецификатором формата, не должны сохраняться в переменной. Для этой отброшенной переменной не следует включать аргументы в строке формата.
The ff
Модификатор в printf отсутствует в scanf, что приводит к различиям между режимами ввода и вывода. ll
и hh
модификаторы отсутствуют в стандарте C90, но присутствуют в стандарте C99. [3]
Пример строки формата:
"%7d%s %c%lf"
Приведенная выше строка формата сканирует первые семь символов как десятичное целое число, затем читает оставшиеся как строку до тех пор, пока не будет найден пробел, новая строка или табуляция, затем потребляет пробелы до тех пор, пока не будет найден первый символ, не являющийся пробелом, затем потребляет этот символ. и, наконец, сканирует оставшиеся символы как двойные . Следовательно, надежная программа должна проверять, scanf
вызов успешен и предпримите соответствующие действия. Если ввод был не в правильном формате, ошибочные данные все равно будут находиться во входном потоке и должны быть отброшены, прежде чем можно будет прочитать новый ввод. Альтернативный метод, позволяющий избежать этого, заключается в использовании fgets
а затем проверьте прочитанную строку. Последний шаг можно выполнить с помощью sscanf
, например.
В случае большого количества символов типа float a, e, f, g , многие реализации предпочитают сжимать большинство данных в один и тот же синтаксический анализатор. Microsoft MSVCRT делает это с помощью е, ж, ж , [4] в то время как glibc делает то же самое со всеми четырьмя. [2]
ISO C99 включает в себя inttypes.h
заголовочный файл, который включает в себя ряд макросов для использования в независимых от платформы scanf
кодирование. Они должны быть вне двойных кавычек, например scanf("%" SCNd64 "\n", &t);
Примеры макросов включают в себя:
Макрос | Описание |
---|---|
СКНд32 | Обычно эквивалентно I32d ( Win32/Win64 ) или д |
СКНд64 | Обычно эквивалентно I64d ( Win32/Win64 ), lld ( 32-битные платформы ) или ld ( 64-битные платформы ) |
СКНи32 | Обычно эквивалентно I32i ( Win32/Win64 ) или я |
SCNi64 | Обычно эквивалентно I64i ( Win32/Win64 ), lli ( 32-битные платформы ) или li ( 64-битные платформы ) |
СКНу32 | Обычно эквивалентно I32u ( Win32/Win64 ) или в |
СКНу64 | Обычно эквивалентно И64у ( Win32/Win64 ), llu ( 32-битные платформы ) или lu ( 64-битные платформы ) |
СКНx32 | Обычно эквивалентно I32x ( Win32/Win64 ) или х |
SCNx64 | Обычно эквивалентно I64x ( Win32/Win64 ), llx ( 32-битные платформы ) или lx ( 64-битные платформы ) |
Уязвимости
[ редактировать ]scanf
уязвим для атак на строку формата . Следует уделить особое внимание тому, чтобы строка форматирования включала ограничения на размеры строк и массивов. В большинстве случаев размер входной строки от пользователя является произвольным и не может быть определен до scanf
функция выполняется. Это означает, что %s
заполнители без спецификаторов длины по своей сути небезопасны и могут быть использованы для переполнения буфера . Другая потенциальная проблема — разрешить строки динамического форматирования, например строки форматирования, хранящиеся в файлах конфигурации или других файлах, управляемых пользователем. В этом случае разрешенную входную длину размеров строк невозможно указать, если строка форматирования не проверена заранее и не применяются ограничения. С этим связаны дополнительные или несовпадающие заполнители форматирования, которые не соответствуют фактическому списку переменных аргументов . Эти заполнители могут быть частично извлечены из стека или содержать нежелательные или даже небезопасные указатели, в зависимости от конкретной реализации varargs .
См. также
[ редактировать ]Ссылки
[ редактировать ]- ^ Макилрой, доктор медицины (1987). Читатель Research Unix: аннотированные выдержки из Руководства программиста, 1971–1986 (PDF) (Технический отчет). CSTR. Лаборатории Белла. 139.
- ^ Jump up to: а б с Linux программиста Руководство – Библиотечные функции –
- ^ Стандарт C99, §7.19.6.2 «Функция fscanf» alinea 11.
- ^ «Символы поля типа сканирования» . docs.microsoft.com . 26 октября 2022 г.
Внешние ссылки
[ редактировать ]- Единая спецификация UNIX , версия 4 от Открытой группы. – Справочник по системным интерфейсам,
- Справочник по C++ для
std::scanf