Вопрос:
Чтение руководства scanf Я встречаю эту строку:
Необязательный символ “m”. Это используется для преобразования строк (% s,% c,% [),
Может ли кто-нибудь объяснить это простым примером, указав разницу и необходимость такой опции в некоторых случаях?
Лучший ответ:
Стандарт C не определяет такой необязательный символ в форматах scanf().
GNU lib C, таким образом определяет необязательный индикатор a (с man-страницы для scanf):
Необязательный символ a. Это используется со строковыми преобразованиями и освобождает вызывающего абонента от необходимости назначать соответствующий буфер для хранения ввода: вместо этого scanf() выделяет буфер достаточного размера и присваивает адрес этого буфера соответствующему аргументу указателя, который должен быть указателем на переменную char * (эта переменная не должна быть инициализирована перед вызовом).
Затем вызывающий абонент должен free использовать этот буфер, когда он больше не требуется. Это расширение GNU; C99 использует символ a как спецификатор преобразования (и его также можно использовать как таковой в реализации GNU).
В разделе ПРИМЕЧАНИЯ на странице руководства говорится:
Модификатор a недоступен, если программа скомпилирована с помощью gcc -std=c99 или gcc -D_ISOC99_SOURCE (если не указано _GNU_SOURCE), и в этом случае a интерпретируется как спецификатор для плавающей запятой числа (см. выше).
Начиная с версии 2.7, glibc также предоставляет модификатор m для той же цели, что и модификатор. Модификатор m имеет следующие преимущества:
Он также может применяться к %c спецификаторам преобразования (например, %3mc).
Он избегает двусмысленности относительно спецификатора преобразования %a с плавающей запятой (и на него не влияет gcc -std=c99 и т.д.)
Он указан в предстоящей ревизии стандарта POSIX.1.
Страница руководства онлайн-linux на документирует этот параметр как:
Необязательный символ “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 для разбора слова со стандартного ввода и выделения достаточного количества памяти для хранения его символов плюс завершающий ‘