Стандарт C не определяет такой необязательный символ в форматах scanf()
.
GNU lib C определяет необязательный индикатор a
таким образом (из справочной страницы для scanf
):
Необязательный символ a
. Это используется со строковыми преобразованиями и освобождает вызывающую сторону от необходимости выделять соответствующий буфер для хранения ввода: вместо этого scanf()
выделяет буфер достаточного размера и присваивает адрес этого буфера соответствующему аргументу указателя, который должен быть указатель на переменную char *
(эту переменную не нужно инициализировать перед вызовом).
Вызывающий должен впоследствии free
этот буфер, когда он больше не требуется. Это расширение GNU; C99 использует символ a
в качестве спецификатора преобразования (и он также может использоваться как таковой в реализации GNU).
В разделе ПРИМЕЧАНИЯ справочной страницы говорится:
Модификатор a
недоступен, если программа скомпилирована с gcc -std=c99
или gcc -D_ISOC99_SOURCE
(если не указано также _GNU_SOURCE
), и в этом случае a
интерпретируется как спецификатор для чисел с плавающей запятой (см. выше).
Начиная с версии 2.7, glibc также предоставляет модификатор m
для той же цели, что и модификатор a. Модификатор m
имеет следующие преимущества:
Его также можно применять к спецификаторам преобразования %c
(например, %3mc
).
Это позволяет избежать двусмысленности в отношении спецификатора преобразования с плавающей запятой %a
(и не зависит от gcc -std=c99
и т. д.).
Это указано в предстоящей версии стандарта POSIX.1.
Страница интерактивного руководства по Linux по адресу http://linux.die.net/man/3/scanf только документирует эту опцию как:
Необязательный символ 'm'. Это используется со строковыми преобразованиями (%s
, %c
, %[
) и избавляет вызывающую сторону от необходимости выделять соответствующий буфер для хранения ввода: вместо этого scanf()
выделяет буфер достаточного размера и присваивает адрес этого буфера соответствующий аргумент-указатель, который должен быть указателем на переменную char *
(эту переменную не нужно инициализировать перед вызовом). Вызывающий должен впоследствии free(3)
этот буфер, когда он больше не требуется.
Стандарт Posix документирует это расширение в редакции POSIX.1-2008 (см. http://pubs.opengroup.org/onlinepubs/9699919799/functions/fscanf.html ):
Спецификаторы преобразования %c
, %s
и %[
должны принимать необязательный символ назначения-распределения m
, который должен вызывать выделение буфера памяти для хранения преобразованной строки, включая завершающий нулевой символ. В таком случае аргумент, соответствующий спецификатору преобразования, должен быть ссылкой на переменную-указатель, которая получит указатель на выделенный буфер. Система должна выделить буфер, как если бы был вызван malloc()
. Приложение должно нести ответственность за освобождение памяти после использования. Если для выделения буфера недостаточно памяти, функция должна установить errno
в [ENOMEM
], и результатом будет ошибка преобразования. Если функция возвращает EOF
, любая память, успешно выделенная для параметров с использованием символа назначения-распределения m
этим вызовом, должна быть освобождена до возврата функции.
Используя это расширение, вы можете написать:
char *p;
scanf("%ms", &p);
Заставляет scanf
анализировать слово из стандартного ввода и выделять достаточно памяти для хранения его символов плюс завершающий '\0'
. Указатель на выделенный массив будет сохранен в p
, а scanf()
вернет 1
, если только из stdin
нельзя будет прочитать символы, отличные от пробелов.
Вполне возможно, что другие системы используют m
для аналогичной семантики или для чего-то совсем другого. Нестандартные расширения не переносимы, и их следует использовать очень осторожно, задокументировав как таковые, в обстоятельствах, когда стандартный подход громоздок, непрактичен или вообще невозможен.
Обратите внимание, что синтаксический анализ слова произвольного размера действительно невозможен со стандартной версией scanf()
:
Вы можете разобрать слово с максимальным размером и должны указать максимальное количество символов для хранения перед '\0'
:
char buffer[20];
scanf("%19s", buffer);
Но это не говорит вам, сколько еще символов доступно для анализа в стандартном вводе. В любом случае, непередача максимального количества символов может привести к неопределенному поведению, если ввод достаточно длинный, и злоумышленник может даже использовать специально созданный ввод для взлома вашей программы:
char buffer[20];
scanf("%s", buffer); // potential undefined behavior,
// that could be exploited by an attacker.
person
chqrlie
schedule
31.07.2016