Printf, fprintf, sprintf форматный вывод


Содержание

Printf, fprintf, sprintf форматный вывод

Функция printf переводит внутренние значения в текст.

В предыдущих главах мы использовали printf неформально. Здесь мы покажем наиболее типичные случаи применения этой функции; полное ее описание дано в приложении В.

Функция printf преобразует, форматирует и печатает свои аргументы в стандартном выводе под управлением формата. Возвращает она количество напечатанных символов.

Форматная строка содержит два вида объектов: обычные символы, которые напрямую копируются в выходной поток, и спецификации преобразования, каждая из которых вызывает преобразование и печать очередного аргумента printf . Любая спецификация преобразования начинается знаком % и заканчивается символом-спецификатором. Между % и символом-спецификатором могут быть расположены (в указанном ниже порядке) следующие элементы:

  • Знак минус, предписывающий выравнивать преобразованный аргумент по левому краю поля.
  • Число, специфицирующее минимальную ширину поля. Преобразованный аргумент будет занимать поле по крайней мере указанной ширины. при необходимости лишние позиции слева (или справа при левостороннем расположении) будут заполнены пробелами.
  • Точка, отделяющая ширину поля от величины, устанавливающей точность.
  • Число (точность), задающее максимальное количество печатаемых символов в строке, или количество цифр после десятичной точки (для чисел с плавающей запятой), или минимальное количество цифр (для целых чисел).
  • Буква h , если печатаемое целое должно рассматриваться как short , или l (строчная латинская буква L), если целое должно рассматриваться как long .

Символы-спецификаторы перечислены в таблице 7.1. Если за % не помещен символ-спецификатор, поведение функции printf будет не определено.

Таблица 7.1. Основные преобразования printf

Символ Тип аргумента; вид печати
d , i int ; десятичное целое
o int ; беззнаковое восьмеричное (octal) целое (без нуля слева)
x , X unsigned int ; беззнаковое шестнадцатиричное целое (без 0x или 0X слева), для шестнадцатиричных цифр от 10 до 15 используются символы a , b , c , d , e , f или A , B , C , D , E , F
u int ; беззнаковое десятичное целое
c int ; одиночный символ
s char * ; печатает символы, пока не встретится символ \0 , или количество символов, заданное точностью
f double ; [-] m.dddddd, где количество цифр d задается точностью (по умолчанию равно 6)
e , E double ; [-] m.dddddd e + xx или [-] m.dddddd E + xx, где количество цифр d задается точностью (по умолчанию равно 6)
g , G double ; использует %e или %E , если порядок меньше, чем -4, или больше или равен точности; в противном случае использует %f. Завершающие нули и завершающая десятичная точка не печатаются
p void * ; указатель (представление зависит от реализации)
% Аргумент не преобразуется; печатается знак %

Ширину и точность можно задавать с помощью знака * ; значение ширины (или точности) в этом случае берется из следующего аргумента, который должен быть типа int . Например, чтобы напечатать не более max символов из строки s , годится следующая запись:

Большая часть форматных преобразований была продемонстрирована в предыдущих главах. Исключение составляет задание точности для строк. Далее приводится перечень спецификаций и показывается их влияние на печать строки «hello, world», состоящей из 12 символов. Поле специально обрамлено двоеточиями, чтобы была видна его протяженность.

Предостережение: функция printf использует свой первый аргумент, чтобы определить, сколько еще ожидается аргументов и какого они будут типа. Вы не получите правильного результата, если аргуметов будет не хватать или они будут принадлежать не тому типу. Вы должны также понимать разницу в следующих двух обращениях:

Функция sprintf выполняет те же преобразования, что и printf , но вывод запоминается в строке

Эта функция форматирует аргументы arg 1 , arg 2 и т.д. в соответствии с информацией, заданной аргументом format , как мы описывали ранее, но результат помещает не в стандартный вывод, а в string . Заметим, что строка string должна быть достаточно большой, чтобы в ней поместился результат.

Форматировать многострочный вывод команды в bash с использованием printf

В моем сценарии Bash используется printf для вывода вывода некоторых других команд с применением форматирования следующим образом (обратите внимание на два ведущих пространства):

Два ведущих пространства есть, потому что первая строка в файле является комментарием, и мне нравится держать вещи красиво выровненными:

Это отлично работает для команд с однострочным выходом. Однако, когда выход является многострочным, на выходе теряется форматирование последующих строк.

Результаты в чем-то вроде этого:

Вместо этого я пытаюсь добиться многострочного вывода, причем каждая строка отформатирована (в столбцах, если хотите), что будет выглядеть так (обратите внимание на отсутствие «заголовка» в последующих строках):

До сих пор я понимаю, что printf с двумя аргументами (первая из которых является строкой, а другая — результатом данной команды) рассматривает второй аргумент как одну строку, которая может содержать символы новой строки внутри. Поэтому вывод действительно правильно отформатирован, в соответствии с тем, что я попросил printf , но это не то, что я ищу.

Я знаю о некоторых ошибках, связанных с анализом вывода команд типа ls , что исчерпывает мои текущие возможности решения этой проблемы. Кроме того, возможно, что printf не лучший инструмент для этого.

Я рассматриваю замену многострочной строки в список, разделенный запятыми, если решение этой проблемы не возможно, но это было бы последним средством.

Какой был бы лучший способ для достижения форматирования, в котором я нуждаюсь?

Синтаксис описания формата: функции printf и wprintf Format specification syntax: printf and wprintf functions

Различные функции printf и wprintf принимают строку формата и необязательные аргументы и создают форматированную последовательность символов для выходных данных. The various printf and wprintf functions take a format string and optional arguments and produce a formatted sequence of characters for output. Строка формата не содержит ни одной или содержит несколько директив, которые являются либо литеральными символами для выходных данных, либо закодированными спецификациями преобразования, описывающими способ форматирования аргумента в выходных данных. The format string contains zero or more directives, which are either literal characters for output or encoded conversion specifications that describe how to format an argument in the output. Эта статья описывает синтаксис для кодирования спецификаций преобразования в строке формата. This article describes the syntax used to encode conversion specifications in the format string. Список этих функций см. в разделе Потоковый ввод-вывод. For a listing of these functions, see Stream I/O.

Спецификация преобразования состоит из необязательных и обязательных полей, имеющих следующий вид: A conversion specification consists of optional and required fields in this form:

Каждое поле спецификации преобразования — это символ или число, указывающее конкретный параметр формата или описатель преобразования. Each field of the conversion specification is a character or a number that signifies a particular format option or conversion specifier. Обязательное поле type определяет тип преобразования, которое применяется к аргументу. The required type field specifies the kind of conversion to be applied to an argument. Необязательные поля flags, width и precision управляют дополнительными аспектами формата, такими как начальные пробелы или нули, выравнивание и отображаемая точность. The optional flags, width, and precision fields control additional format aspects such as leading spaces or zeroes, justification, and displayed precision. Поле size указывает размер использованного и преобразованного аргумента. The size field specifies the size of the argument consumed and converted.

Базовая спецификация преобразования содержит только символ процента и символ type. A basic conversion specification contains only the percent sign and a type character. Например, %s определяет преобразование строк. For example, %s specifies a string conversion. Чтобы вывести символ знака процента, используйте %% . To print a percent-sign character, use %% . Если за символом процента следует символ, который не имеет смысла в поле формата, вызывается обработчик недопустимого параметра. If a percent sign is followed by a character that has no meaning as a format field, the invalid parameter handler is invoked. Дополнительные сведения см. в разделе Проверка параметров. For more information, see Parameter Validation.

Для обеспечения безопасности и стабильности убедитесь, что строки спецификации преобразования не определяются пользователем. For security and stability, ensure that conversion specification strings are not user-defined. Например, рассмотрим программу, которая предлагает пользователю ввести имя и сохраняет введенные данные в строковой переменной с именем user_name . For example, consider a program that prompts the user to enter a name and stores the input in a string variable that’s named user_name . Для печати переменной user_name не используйте следующий код: To print user_name , do not do this:

printf( user_name ); /* Danger! If user_name contains «%s», program will crash */

Вместо этого используйте следующий код: Instead, do this:

printf( «%s», user_name );

В Visual Studio 2015 семейство функций printf и scanf было объявлено как встроенное и перемещено в заголовки и . In Visual Studio 2015 The printf and scanf family of functions were declared as inline and moved to the and headers. При переносе старого кода вы можете увидеть ошибку LNK2020 в подключении к этим функциям. If you are migrating older code you might see LNK2020 in connection with these functions. Дополнительные сведения см. в разделе C++ журнал изменений Visual 2003-2015. For more information, see Visual C++ change history 2003 — 2015.

Спецификатор преобразования типов Type conversion specifier

Символ спецификации преобразования type определяет, как должен интерпретироваться соответствующий аргумент: как символ, строка, указатель, целое число или число с плавающей запятой. The type conversion specifier character specifies whether to interpret the corresponding argument as a character, a string, a pointer, an integer, or a floating-point number. Символ type — единственное обязательное поле спецификации преобразования; он указывается после всех необязательных полей. The type character is the only required conversion specification field, and it appears after any optional fields.

Аргументы, которые следуют за строкой формата, интерпретируются согласно соответствующему символу type и необязательному префиксу size. The arguments that follow the format string are interpreted according to the corresponding type character and the optional size prefix. Преобразования для символьных типов char и wchar_t определяются с помощью символов c или C; однобайтовые и многобайтовые строки или строки с расширенными символами указываются с помощью символа s или S, в зависимости от используемой функции форматирования. Conversions for character types char and wchar_t are specified by using c or C, and single-byte and multi-byte or wide character strings are specified by using s or S, depending on which formatting function is being used. Символьные и строковые аргументы, указанные с использованием c и s, интерпретируется как char и char* функциями семейства printf или как wchar_t и wchar_t* функциями семейства wprintf . Character and string arguments that are specified by using c and s are interpreted as char and char* by printf family functions, or as wchar_t and wchar_t* by wprintf family functions. Символьные и строковые аргументы, указанные с использованием C и S, интерпретируется как wchar_t и wchar_t* функциями семейства printf или как char и char* функциями семейства wprintf . Character and string arguments that are specified by using C and S are interpreted as wchar_t and wchar_t* by printf family functions, or as char and char* by wprintf family functions. Такое поведение относится только к системам Майкрософт. This behavior is Microsoft specific.

Целочисленные типы, такие как short , int , long , long long и их unsigned варианты, задаются с помощью d, i, o, u, xи x. Типы с плавающей запятой, такие как 1, 2 и 3, задаются с помощью, a, e, e, f, f, gи g. По умолчанию, если они не изменяются префиксом размера , целочисленные аргументы приводятся к типу 3, а аргументы с плавающей запятой приводятся к 4. Integer types such as short , int , long , long long , and their unsigned variants, are specified by using d, i, o, u, x, and X. Floating-point types such as float , double , and long double , are specified by using a, A, e, E, f, F, g, and G. By default, unless they are modified by a size prefix, integer arguments are coerced to int type, and floating-point arguments are coerced to double . В 64-разрядных системах тип int является 32-разрядным значением; поэтому 64-разрядные целые числа будут усекаться при форматировании для вывода, если не используется префикс size со значением ll или I64. On 64-bit systems, an int is a 32-bit value; therefore, 64-bit integers will be truncated when they are formatted for output unless a size prefix of ll or I64 is used. Для типов указателей, которые указываются с помощью символаp, используется размер указателя по умолчанию для платформы. Pointer types that are specified by p use the default pointer size for the platform.

Относится только к системам Майкрософт. Символ типа Z, а также поведение символов типа c, C, s и S при использовании с функциями printf и wprintf представляют собой расширения Майкрософт. Microsoft Specific The Z type character, and the behavior of the c, C, s, and S type characters when they are used with the printf and wprintf functions, are Microsoft extensions. C стандарта ISO постоянно использует c и s для узких символов и строк, и C и S — для расширенных символов и строк во всех функциях форматирования. The ISO C standard uses c and s consistently for narrow characters and strings, and C and S for wide characters and strings, in all formatting functions.

Символы поля типа Type field characters

Символ типа Type character Аргумент Argument Формат вывода Output format
c c Знак Character При использовании с функциями printf определяет однобайтовый символ; при использовании с функциями wprintf определяет расширенный символ. When used with printf functions, specifies a single-byte character; when used with wprintf functions, specifies a wide character.
C C Знак Character При использовании с функциями printf определяет расширенный символ; при использовании с функциями wprintf определяет однобайтовый символ. When used with printf functions, specifies a wide character; when used with wprintf functions, specifies a single-byte character.
d d Целое число Integer Десятичное целое число со знаком. Signed decimal integer.
i i Целое число Integer Десятичное целое число со знаком. Signed decimal integer.
o o Целое число Integer Восьмеричное целое число без знака. Unsigned octal integer.
u u Целое число Integer Десятичное целое число без знака. Unsigned decimal integer.
x x Целое число Integer Шестнадцатеричное целое число без знака, используются буквы «abcdef». Unsigned hexadecimal integer; uses «abcdef.»
X X Целое число Integer Шестнадцатеричное целое число без знака, используются буквы «ABCDEF». Unsigned hexadecimal integer; uses «ABCDEF.»
e e С плавающей запятой Floating-point Значение со знаком, имеющее формат [-]d.dddddd[d], где d — одна десятичная цифра, dddd — одна или несколько десятичных цифр в зависимости от указанной точности или шесть по умолчанию, dd[d] — две или три десятичные цифры в зависимости от формата вывода и величины экспоненты. Signed value that has the form [-]d.dddddd[d], where d is one decimal digit, dddd is one or more decimal digits depending on the specified precision, or six by default, and dd[d] is two or three decimal digits depending on the output format and size of the exponent.
E E С плавающей запятой Floating-point Аналогичен формату e, за исключением того, что вместо e порядок величины представляет символ E. Identical to the e format except that E rather than e introduces the exponent.
f f С плавающей запятой Floating-point Значение со знаком, имеющее формат [–]dddd . dddd, где dddd — одна или несколько десятичных цифр. Signed value that has the form [-]dddd.dddd, where dddd is one or more decimal digits. Количество цифр перед десятичной запятой зависит от величины числа, а количество знаков после десятичной запятой зависит от указанной точности либо используется шесть по умолчанию. The number of digits before the decimal point depends on the magnitude of the number, and the number of digits after the decimal point depends on the requested precision, or six by default.
F F С плавающей запятой Floating-point Идентичен формату f, за исключением того, что выходные данные бесконечности и NaN пишутся прописными буквами. Identical to the f format except that infinity and nan output is capitalized.
g g С плавающей запятой Floating-point Значения со знаком отображаются в формате f или e в зависимости от того, какой формат является более компактным для заданного значения и точности. Signed values are displayed in f or e format, whichever is more compact for the given value and precision. Формат e используется только в том случае, когда порядок значения меньше –4 или больше или равен значению аргумента precision. The e format is used only when the exponent of the value is less than -4 or greater than or equal to the precision argument. Нули в конце отбрасываются, а десятичная запятая отображается только в том случае, если за ней следует хотя бы одна цифра. Trailing zeros are truncated, and the decimal point appears only if one or more digits follow it.
G G С плавающей запятой Floating-point Аналогичен формату g, за исключением того, что вместоe порядок величины представляет символ E (где это необходимо). Identical to the g format, except that E, rather than e, introduces the exponent (where appropriate).
a a С плавающей запятой Floating-point Шестнадцатеричное значение с плавающей запятой двойной точности со знаком, которое имеет формат [−]0xh.hhhhdd, где h.hhhh — шестнадцатеричные цифры мантиссы (с использованием строчных букв) и dd — одна или более цифр порядка величины. Signed hexadecimal double-precision floating-point value that has the form [-]0xh.hhhhdd, where h.hhhh are the hex digits (using lower case letters) of the mantissa, and dd are one or more digits for the exponent. Точность определяет количество цифр после запятой. The precision specifies the number of digits after the point.
A A С плавающей запятой Floating-point Шестнадцатеричное значение с плавающей запятой двойной точности со знаком, которое имеет формат [−]0Xh.hhhhdd, где h.hhhh — шестнадцатеричные цифры мантиссы (с использованием заглавных букв) и dd — одна или более цифр порядка величины. Signed hexadecimal double-precision floating-point value that has the form [-]0Xh.hhhhdd, where h.hhhh are the hex digits (using capital letters) of the mantissa, and dd are one or more digits for the exponent. Точность определяет количество цифр после запятой. The precision specifies the number of digits after the point.
n n Указатель на целое число Pointer to integer Число символов, которые успешно записаны на данный момент в поток или буфер. Number of characters that are successfully written so far to the stream or buffer. Это значение хранится в целом числе, адрес которого указан в качестве аргумента. This value is stored in the integer whose address is given as the argument. Размер целочисленного значения, на которое ссылается указатель, управляется префиксом спецификации размера аргумента. The size of the integer pointed at can be controlled by an argument size specification prefix. Спецификатор n отключен по умолчанию. Дополнительные сведения см. в примечании по безопасности. The n specifier is disabled by default; for information see the important security note.
p p Тип указателя Pointer type Отображает аргумент как адрес в шестнадцатеричных цифрах. Displays the argument as an address in hexadecimal digits.
s s Строковое String При использовании с функциями printf определяет строку однобайтовых или многобайтовых символов; при использовании с функциями wprintf определяет строку расширенных символов. When used with printf functions, specifies a single-byte or multi-byte character string; when used with wprintf functions, specifies a wide-character string. Символы отображаются до первого нулевого символа или до тех пор, пока не будет достигнуто значение precision. Characters are displayed up to the first null character or until the precision value is reached.
S S Строковое String При использовании с функциями printf определяет строку расширенных символов; при использовании с функциями wprintf определяет строку однобайтовых или многобайтовых символов. When used with printf functions, specifies a wide-character string; when used with wprintf functions, specifies a single-byte or multi-byte character string. Символы отображаются до первого нулевого символа или до тех пор, пока не будет достигнуто значение precision. Characters are displayed up to the first null character or until the precision value is reached.
Z Z Структура ANSI_STRING или UNICODE_STRING ANSI_STRING or UNICODE_STRING structure Если в качестве аргумента передается адрес структуры ANSI_STRING или UNICODE_STRING, отображается строка, содержащаяся в буфере, на который указывает поле Buffer структуры. When the address of an ANSI_STRING or UNICODE_STRING structure is passed as the argument, displays the string contained in the buffer pointed to by the Buffer field of the structure. Используйте префикс-модификатор size для w, чтобы указать аргумент UNICODE_STRING , например %wZ . Use a size modifier prefix of w to specify a UNICODE_STRING argument—for example, %wZ . Поле Length структуры должно содержать значение длины строки в байтах. The Length field of the structure must be set to the length, in bytes, of the string. Поле MaximumLength структуры должно содержать значение длины буфера в байтах. The MaximumLength field of the structure must be set to the length, in bytes, of the buffer.

Как правило, символ типа Z используется только в функциях отладки драйвера, которые используют спецификацию преобразования, таких как dbgPrint и kdPrint . Typically, the Z type character is used only in driver debugging functions that use a conversion specification, such as dbgPrint and kdPrint .

Начиная с Visual Studio 2015, если аргумент, соответствующий описателю преобразования с плавающей запятой (a, A, e, E, f, F, g, G), равен бесконечности, не определен или не является числом (NaN), выводится форматированный результат, соответствующий стандарту C99. Starting in Visual Studio 2015, if the argument that corresponds to a floating-point conversion specifier (a, A, e, E, f, F, g, G) is infinite, indefinite, or NaN, the formatted output conforms to the C99 standard. В этой таблице перечислены форматированные выходные данные. This table lists the formatted output:

значения Value Вывод Output
infinity infinity inf
Несигнальное значение NaN Quiet NaN nan
Сигнальное значение NaN Signaling NaN nan(snan)
Неопределенное значение NaN Indefinite NaN nan(ind)

Любое из этих значение может иметь префикс в виде знака. Any of these values may be prefixed by a sign. Если символ описателя преобразования type с плавающей запятой является прописной буквой, выходные данные форматируются также прописными буквами. If a floating-point type conversion specifier character is a capital letter, then the output is also formatted in capital letters. Например, если спецификатором формата является %F вместо %f , бесконечность форматируется как INF вместо inf . For example, if the format specifier is %F instead of %f , an infinity is formatted as INF instead of inf . Функции scanf также могут анализировать эти строки, поэтому эти значения могут совершать круговой путь через функции printf и scanf . The scanf functions can also parse these strings, so these values can make a round trip through printf and scanf functions.

До выхода Visual Studio 2015 в среде CRT использовался другой нестандартный формат для выходных данных значений бесконечности, неопределенных значений и значений NaN. Before Visual Studio 2015, the CRT used a different, non-standard format for output of infinite, indefinite, and NaN values:

значения Value Вывод Output
+ бесконечность + infinity 1.#INF случайные цифры 1.#INF random-digits
— infinity — infinity -1.#INF случайные цифры -1.#INF random-digits
Неопределенное (то же, что и не число без вызова исключения) Indefinite (same as quiet NaN) цифра .#IND случайные цифры digit .#IND random-digits
NaN NaN цифра .#NAN случайные цифры digit .#NAN random-digits

Любое из этих значений могло иметь префикс в виде знака и могло быть отформатировано немного иначе в зависимости от ширины поля и точности (иногда с необычными эффектами). Any of these may have been prefixed by a sign, and may have been formatted slightly differently depending on field width and precision, sometimes with unusual effects. Например, printf(«%.2f\n», INFINITY) выводит 1.#J , так как #INF «округляется» до точности в два знака. For example, printf(«%.2f\n», INFINITY) would print 1.#J because the #INF would be «rounded» to 2 digits of precision.

Если аргумент, который соответствует %s или %S , или поле Buffer аргумента, который соответствует %Z , является указателем NULL, отображается значение «(NULL)». If the argument that corresponds to %s or %S , or the Buffer field of the argument that corresponds to %Z , is a null pointer, «(null)» is displayed.

Во всех экспоненциальных форматах минимальное отображаемое количество цифр показателя степени по умолчанию равно двум (три используются только при необходимости). In all exponential formats, the minimum number of digits of exponent to display is two, using three only if necessary. С помощью функции _set_output_format можно задать три отображаемых знака для обеспечения обратной совместимости с кодом, написанным для Visual Studio 2013 и более ранних версий. By using the _set_output_format function, you can set the number of digits displayed to three for backward compatibility with code written for Visual Studio 2013 and before.

Поскольку формат %n является небезопасным, по умолчанию он запрещен. Because the %n format is inherently insecure, it is disabled by default. Если в строке формата имеется символ %n , вызывается обработчик недопустимого параметра, как описано в разделе Проверка параметров. If %n is encountered in a format string, the invalid parameter handler is invoked, as described in Parameter Validation. Чтобы включить поддержку %n , изучите раздел _set_printf_count_output. To enable %n support, see _set_printf_count_output.

Директивы флагов Flag directives

Первое необязательное поле в спецификации преобразования содержит директивы флагов, ни одного или несколько символов флага, указывающих выравнивание выходных данных и управляющих выводом символов, пустых значений, начальных нулей, десятичных запятых и восьмеричных и шестнадцатеричных префиксов. The first optional field in a conversion specification contains flag directives, zero or more flag characters that specify output justification and control output of signs, blanks, leading zeros, decimal points, and octal and hexadecimal prefixes. В спецификации преобразования может быть указано несколько директив флагов, и символы флагов могут размещаться в любом порядке. More than one flag directive may appear in a conversion specification, and the flag characters can appear in any order.

Символы флагов Flag characters

Flag Flag Смысл Meaning Значение по умолчанию Default
Выравнивание результата по левому краю в пределах заданной ширины поля. Left align the result within the given field width. Выравнивание по правому краю. Right align.
+ Если выходное значение имеет тип со знаком, используйте для него префикс + или –. Use a sign (+ or -) to prefix the output value if it is of a signed type. Знак отображается только для отрицательных значений со знаком –. Sign appears only for negative signed values (-).
Если width предшествует префикс , добавляется несколько ведущих нулей для достижения минимальной ширины. If width is prefixed by , leading zeros are added until the minimum width is reached. Если отображаются и , игнорируется. If both and appear, the is ignored. Если указывается в целочисленном формате (i, u, x, X, o, d) и в сочетании со спецификацией точности, (например, %04.d ), знак игнорируется. If is specified for an integer format (i, u, x, X, o, d) and a precision specification is also present—for example, %04.d —the is ignored. Если указывается в формате плавающей запятой a или A, в начало мантиссы добавляются ведущие нули после префикса 0x или 0X . If is specified for the a or A floating-point format, leading zeros are prepended to the mantissa, after the 0x or 0X prefix. Без заполнения. No padding.
пустой (» «) blank (‘ ‘) Используйте пустой префикс для положительных выходных значений со знаком. Use a blank to prefix the output value if it is signed and positive. Пустой префикс игнорируется, если одновременно с ним присутствует флаг +. The blank is ignored if both the blank and + flags appear. Пустой префикс не отображается. No blank appears.
# Если используется в сочетании с форматом o, x или X, флаг # выводит префикс 0, 0x или 0X соответственно для всех ненулевых выходных значений. When it’s used with the o, x, or X format, the # flag uses 0, 0x, or 0X, respectively, to prefix any nonzero output value. Пустой префикс не отображается. No blank appears.
При использовании с форматом e, E, f, F, a или A флаг # принудительно добавляет к выходному значению десятичный разделитель. When it’s used with the e, E, f, F, a, or A format, the # flag forces the output value to contain a decimal point. Десятичный разделитель появляется, только если после него есть цифры. Decimal point appears only if digits follow it.
Если используется в сочетании с форматом g или G, флаг # принудительно добавляет десятичный разделитель к выходному значению и запрещает отбрасывать конечные нули. When it’s used with the g or G format, the # flag forces the output value to contain a decimal point and prevents the truncation of trailing zeros.

Флаг игнорируется в сочетании с форматами c, d, i, u или s. Ignored when used with c, d, i, u, or s. Десятичный разделитель появляется, только если после него есть цифры. Decimal point appears only if digits follow it. Конечные нули отбрасываются. Trailing zeros are truncated.

Спецификация ширины Width specification

В спецификации преобразования необязательное поле спецификации ширины отображается после любых символов флага. In a conversion specification, the optional width specification field appears after any flags characters. Аргумент width — неотрицательное целое десятичное число, управляющее минимальным количеством выводимых символов. The width argument is a non-negative decimal integer that controls the minimum number of characters that are output. Если количество символов в выходном значении меньше заданной ширины, к значениям слева или справа (в зависимости от того, определен ли флаг выравнивания по левому краю ( )) добавляются пробелы, в количестве, необходимом для достижения минимальной ширины. If the number of characters in the output value is less than the specified width, blanks are added to the left or the right of the values—depending on whether the left-alignment flag () is specified—until the minimum width is reached. Если параметр width имеет префикс 0, при преобразовании к целому числу или числу с плавающей запятой добавляются начальные нули до тех пор, пока не будет достигнута минимальная ширина, кроме случаев преобразования в бесконечность или NaN (не число). If width is prefixed by 0, leading zeros are added to integer or floating-point conversions until the minimum width is reached, except when conversion is to an infinity or NaN.

Спецификация ширины никогда не вызывает усечения значения. The width specification never causes a value to be truncated. Если число символов в выходном значении превышает указанную ширину или если аргумент width не задан, выводятся все символы значения в соответствии со спецификацией precision. If the number of characters in the output value is greater than the specified width, or if width isn’t given, all characters of the value are output, subject to the precision specification.

Если в качестве спецификации ширины указана звездочка ( * ), значение ширины задается аргументом int из списка аргументов. If the width specification is an asterisk ( * ), an int argument from the argument list supplies the value. Аргумент width должен предшествовать форматируемому значению в списке аргументов, как показано в следующем примере: The width argument must precede the value that’s being formatted in the argument list, as shown in this example:

printf(«%0*d», 5, 3); /* 00003 is output */

Отсутствующее или малое значение width в спецификации преобразования не приводит к усечению выходного значения. A missing or small width value in a conversion specification doesn’t cause the truncation of an output value. Если количество символов в результате преобразования больше значения параметра width, поле расширяется, чтобы вместить результат преобразования. If the result of a conversion is wider than the width value, the field expands to contain the conversion result.

Спецификация точности Precision specification

В спецификации преобразования третье необязательное поле является спецификацией точности. In a conversion specification, the third optional field is the precision specification. Эта спецификация состоит из точки (.), за которой следует неотрицательное целое десятичное число, которое, в зависимости от типа преобразования, определяет количество символов строки, количество десятичных разрядов или количество значащих цифр для вывода. It consists of a period (.) followed by a non-negative decimal integer that, depending on the conversion type, specifies the number of string characters, the number of decimal places, or the number of significant digits to be output.

В отличие от спецификации ширины, спецификация точности может вызывать либо усечение выходного значения, либо округление значения с плавающей запятой. Unlike the width specification, the precision specification can cause either truncation of the output value or rounding of a floating-point value. Если аргумент precision указан равным 0 и преобразуемое значение равно 0, никакие символы в результате выводиться не будут, как показано в следующем примере: If precision is specified as 0, and the value to be converted is 0, the result is no characters output, as shown in this example:

printf( «%.0d», 0 ); /* No characters output */

Если спецификация точности представляет собой звездочку (*), аргумент int из списка аргументов предоставляет значение. If the precision specification is an asterisk (*), an int argument from the argument list supplies the value. В списке аргументов аргумент precision должен предшествовать форматируемому значению, как показано в следующем примере: In the argument list, the precision argument must precede the value that’s being formatted, as shown in this example:

printf( «%.*f», 3, 3.14159265 ); /* 3.142 output */

Символ type определяет либо интерпретацию аргумента precision, либо точность по умолчанию при опущенном аргументе precision, как показано в следующей таблице. The type character determines either the interpretation of precision or the default precision when precision is omitted, as shown in the following table.

Влияние значений точности на тип How Precision Values Affect Type

Type Type Смысл Meaning Значение по умолчанию Default
a, A a, A Точность определяет количество цифр после запятой. The precision specifies the number of digits after the point. Точность по умолчанию — 13. Default precision is 13. Если точность равна 0, десятичная запятая не выводится, если не используется флаг # . If precision is 0, no decimal point is printed unless the # flag is used.
c, C c, C Точность не применяется. The precision has no effect. Символ выводится. Character is printed.
d, i, o, u, x, X d, i, o, u, x, X Точность определяет минимальное выводимое количество цифр. The precision specifies the minimum number of digits to be printed. Если количество цифр в аргументе меньше значения precision, выходное значение дополняется слева нулями. If the number of digits in the argument is less than precision, the output value is padded on the left with zeros. Значение не усекается, когда количество цифр превышает значение precision. The value is not truncated when the number of digits exceeds precision. Точность по умолчанию — 1. Default precision is 1.
e, E e, E Выводимое количество знаков дробной части задается спецификацией точности. The precision specifies the number of digits to be printed after the decimal point. Последняя выводимая цифра округляется. The last printed digit is rounded. Точность по умолчанию — 6. Default precision is 6. Если аргумент precision равен 0 или присутствует точка (.) без числа после нее, десятичная запятая не выводится. If precision is 0 or the period (.) appears without a number following it, no decimal point is printed.
f, F f, F Значение точности задает количество цифр после десятичной запятой. The precision value specifies the number of digits after the decimal point. Если десятичная запятая присутствует, перед ней присутствует по крайней мере одна цифра. If a decimal point appears, at least one digit appears before it. Значение округляется до соответствующего количества цифр. The value is rounded to the appropriate number of digits. Точность по умолчанию — 6. Default precision is 6. Если аргумент precision равен 0 или если присутствует точка (.) без числа после нее, десятичная запятая не выводится. If precision is 0, or if the period (.) appears without a number following it, no decimal point is printed.
g, G g, G Точность определяет максимальное выводимое количество значащих цифр. The precision specifies the maximum number of significant digits printed. Выводятся шесть значащих цифр, а конечные нули усекаются. Six significant digits are printed, and any trailing zeros are truncated.
s, S s, S Точность определяет максимальное количество выводимых символов. The precision specifies the maximum number of characters to be printed. Символы, выходящие за рамки precision, не выводятся. Characters in excess of precision aren’t printed. Символы выводятся до тех пор, пока не будет обнаружен нуль-символ. Characters are printed until a null character is encountered.

Спецификация размера аргумента Argument size specification

В спецификации преобразования поле size — это модификатор длины аргумента для описателя преобразования type. In a conversion specification, the size field is an argument length modifier for the type conversion specifier. Префиксы поля size для поля type (hh, h, j, l (строчная L), L, ll, t, w, z, I (прописная i), I32 и I64) определяют «размер» соответствующего аргумента — длинный или короткий, 32- или 64-разрядный, однобайтовый или расширенный символ — в зависимости от описателя преобразования, который они модифицируют. The size field prefixes to the type field—hh, h, j, l (lowercase L), L, ll, t, w, z, I (uppercase i), I32, and I64—specify the «size» of the corresponding argument—long or short, 32-bit or 64-bit, single-byte character or wide character—depending on the conversion specifier that they modify. Эти префиксы размера используются с символами type в семействах функций printf и wprintf для определения интерпретации размеров аргументов, как показано в следующей таблице. These size prefixes are used with type characters in the printf and wprintf families of functions to specify the interpretation of argument sizes, as shown in the following table. Поле size является необязательным для некоторых типов аргументов. The size field is optional for some argument types. Если префикс размера не указан, модуль форматирования использует целые аргументы, например подписанные или не подписанные char , short , int , long и типы перечисления как 32-разрядные типы int , а аргументы float , double и long double с плавающей запятой используются как 64-разрядные типы double . When no size prefix is specified, the formatter consumes integer arguments—for example, signed or unsigned char , short , int , long , and enumeration types—as 32-bit int types, and float , double , and long double floating-point arguments are consumed as 64-bit double types. Такое поведение соответствует правилам повышения уровня аргументов по умолчанию для списков аргументов переменных. This behavior matches the default argument promotion rules for variable argument lists. Дополнительные сведения о повышении аргументов см. раздел Ellipses and Default Arguments (Многоточия и аргументы по умолчанию) в статье Postfix expressions (Постфиксные выражения). For more information about argument promotion, see Ellipses and Default Arguments in Postfix expressions. Как в 32-разрядной, так и в 64-разрядной системах спецификация преобразования 64-разрядного целого аргумента должна включать префикс размера ll или I64. On both 32-bit and 64-bit systems, the conversion specification of a 64-bit integer argument must include a size prefix of ll or I64. В противном случае поведение модуля форматирования не определено. Otherwise, the behavior of the formatter is undefined.

Некоторые типы имеют разный размер в 32-разрядном и 64-разрядном коде. Some types are different sizes in 32-bit and 64-bit code. Например, size_t на 32 бита длиннее в коде, скомпилированном для x86, и на 64 бита длиннее в коде, скомпилированном для x64. For example, size_t is 32 bits long in code compiled for x86, and 64 bits in code compiled for x64. Чтобы создать код форматирования для типов с переменным количеством байт, не зависящий от платформы, можно использовать модификатор размера аргумента с переменным количеством байт. To create platform-agnostic formatting code for variable-width types, you can use a variable-width argument size modifier. Кроме того, можно использовать 64-разрядный модификатор размера аргумента и явно повысить тип аргумента с переменным количеством байт до 64 бит. Alternatively, use a 64-bit argument size modifier and explicitly promote the variable-width argument type to 64 bits. Присущий Майкрософт модификатор размера аргумента I (прописная i) обрабатывает целочисленные аргументы переменной ширины, но для обеспечения переносимости рекомендуется использовать характерные для типа модификаторы j, t и z. The Microsoft-specific I (uppercase i) argument size modifier handles variable-width integer arguments, but we recommend the type-specific j, t, and z modifiers for portability.

Префиксы размера для описателей формата функций printf и wprintf Size Prefixes for printf and wprintf Format-Type Specifiers

Чтобы указать To specify Используемый префикс Use prefix Со спецификатором типа With type specifier
char
unsigned char
hh hh d, i, o, u, x или X d, i, o, u, x, or X
short int
short unsigned int
h h d, i, o, u, x или X d, i, o, u, x, or X
__int32
unsigned __int32
I32 I32 d, i, o, u, x или X d, i, o, u, x, or X
__int64
unsigned __int64
I64 I64 d, i, o, u, x или X d, i, o, u, x, or X
intmax_t
uintmax_t
j или I64 j or I64 d, i, o, u, x или X d, i, o, u, x, or X
long double l (строчная L) или L l (lowercase L) or L a, A, e, E, f, F, g или G a, A, e, E, f, F, g, or G
long int
long unsigned int
l (строчная L) l (lowercase L) d, i, o, u, x или X d, i, o, u, x, or X
long long int
unsigned long long int
ll (строчные LL) ll (lowercase LL) d, i, o, u, x или X d, i, o, u, x, or X
ptrdiff_t t или I (прописная i) t or I (uppercase i) d, i, o, u, x или X d, i, o, u, x, or X
size_t z или I (прописная i) z or I (uppercase i) d, i, o, u, x или X d, i, o, u, x, or X
Однобайтовый символ Single-byte character h h c или C c or C
Расширенный символ Wide character l (строчная L) или w l (lowercase L) or w c или C c or C
Строка однобайтовых символов Single-byte character string h h s, S или Z s, S, or Z
Строка расширенных символов Wide-character string l (строчная L) или w l (lowercase L) or w s, S или Z s, S, or Z

Типы ptrdiff_t и size_t являются __int32 или unsigned __int32 на 32-разрядных платформах и __int64 или unsigned __int64 на 64-разрядных платформах. The ptrdiff_t and size_t types are __int32 or unsigned __int32 on 32-bit platforms, and __int64 or unsigned __int64 on 64-bit platforms. Префиксы размера I (прописная i), j, t и z принимают правильное значение ширины аргументов для платформы. The I (uppercase i), j, t, and z size prefixes take the correct argument width for the platform.

В Visual C++ хотя long double является отдельным типом, он имеет то же внутреннее представление, что и тип double . In Visual C++, although long double is a distinct type, it has the same internal representation as double .

Спецификатор типа hc или hC аналогичен c в функциях printf и C в функциях wprintf . An hc or hC type specifier is synonymous with c in printf functions and with C in wprintf functions. Спецификатор типа lc, lC, wc или wC аналогичен C в функциях printf и c в функциях wprintf . An lc, lC, wc, or wC type specifier is synonymous with C in printf functions and with c in wprintf functions. Спецификатор типа hs или hS аналогичен s в функциях printf и S в функциях wprintf . An hs or hS type specifier is synonymous with s in printf functions and with S in wprintf functions. Спецификатор типа ls, lS, ws или wS аналогичен S в функциях printf и s в функциях wprintf . An ls, lS, ws or wS type specifier is synonymous with S in printf functions and with s in wprintf functions.

Относится только к системам Майкрософт. Префиксы модификатора размера аргумента I (прописная i), I32, I64 и w являются расширениями Майкрософт и не совместимы с C стандарта ISO. Microsoft Specific The I (uppercase i), I32, I64, and w argument size modifier prefixes are Microsoft extensions and are not ISO C-compatible. Префикс h при использовании с данными типа char и префикс l (строчная L) при использовании с данными типа double являются расширениями Майкрософт. The h prefix when it’s used with data of type char and the l (lowercase L) prefix when it’s used with data of type double are Microsoft extensions.

Разница между fprintf, printf и sprintf?

кто-нибудь может объяснить на простом английском языке о различиях между printf , fprintf и sprintf с примерами?

Я действительно запутался между тремя из них, читая о «обработке файлов в C».

8 ответов

в C «поток» является абстракцией; с точки зрения программы это просто производитель (входной поток) или потребитель (выходной поток) байтов. Он может соответствовать файлу на диске, трубе, терминалу или другому устройству, такому как принтер или tty. The FILE type содержит информацию о потоке. Обычно вы не связываетесь с FILE содержимое объекта напрямую, вы просто передаете указатель на него различным процедурам ввода-вывода.

есть три стандартные потоки: stdin — это указатель на стандартный входной поток, stdout является указателем на стандартный выходной поток и stderr указатель на стандартный поток вывода ошибок. В интерактивном сеансе эти три обычно ссылаются на вашу консоль, хотя вы можете перенаправить их на другие файлы или устройства:

в этом примере stdin Теперь указывает на inputfile.dat , stdout указывает на output.txt и stderr указывает на errors.txt .

fprintf записывает форматированный текст в указанный поток вывода.

printf эквивалентно записи fprintf(stdout, . ) и записывает форматированный текст туда,куда указывает стандартный выходной поток.

sprintf записывает форматированный текст в массив char , в отличие от потока.

printf выходы в стандартный выходной поток ( stdout )

fprintf переходит к дескриптору файла ( FILE* )

sprintf переходит к буферу, который вы выделили. ( char* )

printf(«формат», args) используется для печати данных на стандартный вывод, который часто является монитором компьютера.

sprintf(char *, «format», args) похоже на printf. Вместо отображения формированной строки на стандартном выходе, т. е. мониторе, он хранит формированные данные в строке, на которую указывает указатель char (самый первый параметр). Расположение строки-единственное различие между printf и sprint синтаксис.

fprintf(файл *fp, «формат», args) снова похож на printf. Здесь вместо отображения данных на мониторе или сохранения их в какой-либо строке формируемые данные сохраняются в файле, на который указывает указатель файла, который используется в качестве первого параметра fprintf. Указатель файла является единственным дополнением к синтаксису printf.

Если стандартный вывод файл используется в качестве первого параметра в fprintf, затем рассматривается его работа эквивалентно printf.

printf(. ) эквивалентно fprintf(stdout. ) .

fprintf используется для вывода в поток.

sprintf(buffer. ) используется для форматирования строки в буфер.

обратите внимание, что есть также vsprintf , vfprintf и vprintf

вы также можете делать очень полезные вещи с функцией vsnprintf ():

Документация

Данные о формате в строку или вектор символов

Синтаксис

Описание

str = sprintf(formatSpec,A1. An) форматирует данные в массивах A1. An с помощью операторов форматирования, заданных formatSpec , и возвращает получившийся текст в str . Функция sprintf форматирует значения в A1. An в порядке следования столбцов. Если formatSpec является строкой, то так вывод str . В противном случае str является вектором символов.

Чтобы возвратить несколько частей форматированного текста как массив строк или массив ячеек из символьных векторов, используйте функцию compose .

[str,errmsg] = sprintf(formatSpec,A1. An) возвращает сообщение об ошибке как вектор символов, когда операция неудачна. В противном случае errmsg пуст.

str = sprintf(literalText) переводит последовательности символа ESC в literalText , такие как \n и \t . Это возвращает все другие неизменные символы. Если literalText содержит оператор форматирования (такой как %f ), то str отбрасывает его и все символы после.

Примеры

Форматы с плавающей точкой

Отформатируйте число с плавающей запятой с помощью %e , %f и спецификаторов %g .

Буквенный текст и вводы массивов

Объедините буквенный текст со значениями массивов, чтобы создать вектор символов.

Определение форматированного текста как массива строк

Чтобы возвратить форматированный текст как строку, задайте formatSpec как строку вместо вектора символов, когда вы вызовете функцию sprintf .

Начиная в R2020a, можно создать строки с помощью двойных кавычек. Преобразуйте данные и возвратите результат как строку.

Преобразуйте входную строку. Входные массивы, которые содержат текст или могут быть векторами символов или строками.

Целочисленный формат с вводами с плавающей точкой

Явным образом преобразуйте с двойной точностью значения в целые числа.

Определение ширины поля печатного значения

Задайте минимальную ширину печатного значения.

Флаг 0 в спецификаторе формата %025d запрашивает начальные нули в выводе.

Переупорядочение вводов Используя идентификатор положения (n$)

Переупорядочьте входные значения с помощью идентификатора положения n$ .


Создание вектора символа из значений в массиве ячеек

C <:>синтаксиса создает список, разделенный запятыми массивов, которые содержат содержимое каждой ячейки от C в порядке следования столбцов. Например, C<1>==1 и C<2>==’AA’ .

Входные параметры

formatSpec Формат выходных полей
форматирование операторов

Формат выходных полей, заданных операторов форматирования использования. formatSpec также может включать обычный текст и специальные символы.

formatSpec может быть вектором символов в одинарных кавычках, или, запускающийся в R2020b, скаляре строки.

Оператор форматирования запускается со знака процента, % , и заканчивается символом преобразования. Символ преобразования требуется. Опционально, можно задать идентификатор, флаги, ширину поля, точность, и выделить подтипы в операторах между % и символом преобразования. (Пробелы недопустимы между операторами и показаны здесь только для удобочитаемости).

Эта таблица показывает символы преобразования, чтобы отформатировать числовые и символьные данные как текст.

Целое число, подписанное

Целое число, без знака

Базируйтесь 8 (восьмеричный)

Основывайте 16 (шестнадцатеричных), строчных букв a – f

То же самое как %x , прописные буквы A – F

Число с плавающей запятой

Представление с фиксированной точкой (Используют оператор точности, чтобы задать количество цифр после десятичной точки.)

Экспоненциальное представление, такое как 3.141593e+00 (Используют оператор точности, чтобы задать количество цифр после десятичной точки.)

То же самое как %e , но верхний регистр, такой как 3.141593E+00 (Используют оператор точности, чтобы задать количество цифр после десятичной точки.)

Более компактный из %e или %f , без конечных нулей (Используют оператор точности, чтобы задать количество значительных цифр.)

Более компактный из %E или %f , без конечных нулей (Используют оператор точности, чтобы задать количество значительных цифр.)

Символы или строки

Вектор символов или массив строк. Тип синтезируемого текста совпадает с типом formatSpec .

Дополнительный идентификатор, флаги, ширина поля, точность и операторы подтипа далее задают формат синтезируемого текста.

Порядок для обработки аргументов входного параметра функции. Используйте синтаксис n$ , где n представляет положения других входных параметров в вызове функции.

Пример: (‘%3$s %2$s %1$s %2$s’,’A’,’B’,’C’) распечатывает входные параметры ‘A’ , ‘B’ , ‘C’ можно следующим образом: C B A B .

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

Лево-выровнять по ширине.
Пример: %-5.2f
Пример: %-10s

Всегда распечатывайте символ знака (+ или –) для любого числового значения.
Пример: %+5.2f
Право — выравнивает текст.
Пример: %+10s

Вставьте пробел перед значением.
Пример: % 5.2f

Заполните к ширине поля нулями перед значением.
Пример: %05.2f

Измените выбранные числовые преобразования:

Для %o %x или %X , распечатывает 0 , 0x или префикс 0X .

Для %f %e или %E , распечатывает десятичную точку, даже когда точность 0.

Для %g или %G , не удаляйте конечные нули или десятичную точку.

Минимальное количество символов, чтобы распечатать. Оператор ширины поля может быть номером или звездочкой ( * ), чтобы относиться к входному параметру.

Когда вы задаете * как оператор ширины поля, другие входные параметры должны обеспечить и ширину и значение, которое будет распечатано. Ширины и значения могут быть парами аргументов или парами в числовом массиве. С * как оператор ширины поля можно распечатать различные значения с различными ширинами.

Пример: входные параметры (‘%12d’,intmax) эквивалентны (‘%*d’,12,intmax) .

Пример: входные параметры (‘%*d’,[2 10 5 100]) возвращают ’10 100′ с двумя местами, выделенными для 10 и пятью пробелами для 100 . Как альтернатива, также можно задать ширину поля и значения в качестве нескольких аргументов, в качестве в (‘%*d’,2,10,5,100) .

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

Количество цифр справа от десятичной точки
Пример: ‘%.4f’ распечатывает pi как ‘3.1416’

Количество значительных цифр
Пример: ‘%.4g’ распечатывает pi как ‘3.142’

Оператор точности может быть номером или звездочкой ( * ), чтобы относиться к аргументу.

Когда вы задаете * как полевой оператор точности, другие входные параметры должны обеспечить и точность и значение, которое будет распечатано. Точность и значения могут быть парами аргументов или парами в числовом массиве. С * как оператор точности можно распечатать различные значения к различной точности.

Когда вы задаете *.* как ширину поля и операторы точности, необходимо задать ширину поля, точность и значения как триплеты.

Пример: входные параметры (‘%.4f’,pi) эквивалентны (‘%.*f’,4,pi) .

Пример: входные параметры (‘%6.4f’,pi) эквивалентны (‘%.*f’,6,4,pi) .

Пример: входные параметры (‘%*.*f’,6,4,pi,9,6,exp(1)) возвращают ‘3.1416 2.718282’ с 9 и 6 как ширина поля и точность для вывода exp(1) .

Примечание

Если вы задаете оператор точности для значений с плавающей точкой, который превышает точность входного типа числовых данных, результаты не могут совпадать с входными значениями к точности, которую вы задали. Результат зависит от вашего компьютерного оборудования и операционной системы.

Можно использовать оператор подтипа, чтобы распечатать значение с плавающей точкой как его восьмеричное, десятичное, или шестнадцатеричное значение. Оператор подтипа сразу предшествует символу преобразования. Эта таблица показывает преобразования, которые могут использовать подтипы.

Тип входного значения

Подтип и символ преобразования

Тип выходного значения

Число с плавающей запятой

С двойной точностью шестнадцатеричное, восьмеричное, или десятичное значение
Пример: %bx распечатывает pi как 400921fb54442d18

Шестнадцатеричное, восьмеричное, или десятичное значение с одинарной точностью
Пример: %tx распечатывает pi как 40490fdb

Текст прежде или после операторов форматирования

formatSpec может также включать дополнительный текст перед знаком процента, % , или после символа преобразования. Текст может быть:

Обычный текст, чтобы распечатать.

Специальные символы, которые вы не можете ввести как обычный текст. Эта таблица показывает, как представлять специальные символы в formatSpec .

Printf C: описание, форматирование, примеры

Стандартная функция консольного вывода в языке C – printf. Описание её содержится в заголовочном файле stdio.h. При помощи этой функции можно выводить данные или пользовательские сообщения в консоль. Язык C чувствителен к регистру. К примеру, две функции printf и scanf отличаются от подобных им Printf и Scanf. Все символы в функциях printf и scanf также должны быть записаны в нижнем регистре. Одним из простейших примеров C printf, выводящим на экран знакомое приветствие hello world, является:

Определение функций группы printf в файле «stdio.h»

Файл «stdio.h» относится к стандартной библиотеке ввода/вывода в языке С. Описание printf и подобных ей функций приводится в нём следующим образом:

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

Семейство функций printf

Функции группы printf в языке C служат для обработки и форматированного вывода данных в стандартный поток. Причём функции printf и vprintf производят запись в стандартный поток stdout, функции fprintf и vfprintf отправляют значения выводимых аргументов в некоторый заданный выходной поток, а snprintf, sprintf, vsnprintf и vsprintf записывают данные в символьную строку. Все перечисленные функции работают с использованием строки формата, указывающей необходимые преобразования аргументов для вывода.

Функция fprintf записывает результат в выходной поток stream. В буфер, представляющий собой символьную строку, выводит результат функция sprintf. Поведение функции не определено, если подлежащая выводу строка превышает размер массива буфера.

Функция snprintf так же, как и предыдущая, записывает данные в строковый буфер. Полученная строка символов завершается нулевым символом, если только bufsz (размер буфера) не равен нулю. Иначе, если значение bufsz равно нулю, то в буфер ничего не выводится, а сам буфер вполне может являться нулевым указателем, но возвращаемое значение (количество байтов, которое должно было быть записано) все равно вычисляется.

Функция printf_s в целом действует тем же образом, что и printf, за исключением одного момента. Главным отличием в описании printf_s в C и printf является следующее: функция printf_s выполняет проверку строки форматирования на наличие допустимых символов в отличие от printf, которая только проверяет строку формата на предмет пустого указателя.

Подробнее рассмотрим функцию printf.

Общее описание

В языке C печать символов через стандартный поток вывода осуществляется посредством вызова функции printf. Команда printf в C форматирует набор выводимых данных, и они отправляются в стандартный поток вывода stdout. Значения, переданные в качестве аргументов функции, выводятся в консоль согласно указанной строке форматирования, которая в свою очередь заключает в себе две разновидности элементов. Первая разновидность — это символы, выводимые на экран, а элементы, определяющие особенности формата данных и отвечающие за метод представления аргументов при выводе, относятся ко второму виду.

При выводе переменных с printf в C особые комбинации символов в строке аргументов заменяются на преобразованные в соответствии с этими символами данные, причём для каждого типа данных существуют свои спецификации формата вывода.

Тип функции и возвращаемое значение

Функция printf, имеющая тип int, возвращает целочисленную величину, обозначающую количество напечатанных на экране символов. К примеру, можно присвоить:

int k = printf(«Привет %c %d %s», ‘a’, 11, «всем!»),

и тогда по значению переменной k легко определяется, возникла ли ошибка при выводе. В случае возврата отрицательного значения (если функция вернула «-1») можно сделать вывод, что произошла ошибка при её выполнении.

Синтаксис и зависимости

Чтобы использовать функцию printf, требуется подключить заголовочный файл «stdio.h» следующим образом:

Шаблон функции выглядит:

int printf(const char *формат, . )

Под многоточием подразумевается список аргументов, подлежащих выводу. Функция printf может быть использована с различным числом аргументов, но первый из них всегда ограничивается с обеих сторон двойными кавычками, а каждый последующий необходимо отделять от предыдущего запятой. То, что записано в двойных кавычках и при том не является спецификацией формата, печатается без изменений, иначе, если встретился спецификатор, копируется тип его значения.

Форма задания спецификаций формата:

Форматирование с printf в C выходных значений

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

Символ «%» указывает на начало спецификации формата вывода, следом за ним идёт код формата. Все поля в спецификации представляют собой отдельные, определяющие условия форматирования числа или символы.

Форматированный вывод printf в C обладает своими особенностями. В случае, если количество перечисленных аргументов превышает число спецификаций формата, они пропускаются и не выводятся. Иначе, если спецификаций формата больше, чем значений в списке подлежащих печати аргументов, результат вызова функции не определяется.

Для явного указания, который по счёту аргумент нужно задействовать, возможно использовать «%m$» вместо «%» и «*m$» вместо «*», причём m, целочисленное десятичное значение, обозначает позицию нужного аргумента (индексирование начинается с единицы).

Параметры

Тип значения Преобразование Детали
stream Выходной поток для записи в файл
buffer Указатель на символьную строку для последующей записи в неё
bufsz Определяет число символов, допустимое для записи: максимальное значение — bufsz-1, и ещё нулевой ограничитель
format Указатель на многобайтовую строку с нулевым ограничителем, определяющую, как интерпретировать выводимые аргументы
Флаги, используемые в строке формата
Флаг Описание
Выравнивание результата по левому краю в поле вывода
+ При выводе численного значения, имеющего знак, принудительно печатается «+» перед положительной величиной (по умолчанию выводится только «-» перед отрицательным значением)
Для целых чисел и чисел с плавающей запятой ведущие нули используются вместо символов пробела для заполнения левых разрядов в случае, если задана ширина поля, превышающая длину числа. Для целых чисел флаг игнорируется, если явно указана точность. Для других преобразований с использованием этого флага поведение функции не определено. Флаг «0» не учитывается, если присутствует флаг «-«
space Если результат вывода выражения, имеющего знак, не начинается с символа этого знака или пуст, то пробел добавляется к результату. Флаг «space» игнорируется, если присутствует флаг «+»
# Выполняется альтернативная форма преобразования
Управляющие последовательности
Последовательность Результат
\a Звуковой сигнал
\n Перевод на новую строку
\r Возвращение курсора в начало строки
\t Табуляция
\v Вертикальная табуляция
Вывод двойной кавычки
\\ Вывод косой черты

Различные спецификаторы формата

Спецификатор формата Использование и описание для printf C Тип аргумента
% Запись литерала «%»
c Вывод одного символа. Происходит преобразование аргумента в тип unsigned char. При использовании модификатора «l» аргумент преобразуется в строку символов unsigned char
s Печать строки символов. Аргумент должен являться указателем на начальный элемент массива символов char char *
d
i
Вывод десятичного представления целочисленного значения со знаком int
o Вывод восьмеричного представления без знакового целочисленного значения unsigned int
x
X
Вывод шестнадцатеричного представления без знакового целочисленного значения. Символы «a», «b», «c», «d», «e», «f» применяются для преобразования «x». А для преобразования «X» — «A», «B», «C», «D», «E», «F» unsigned int
u Вывод десятичного преобразования без знакового целочисленного значения. Если преобразованное значение и точность вместе равны 0, то символы не выводятся unsigned int
f
F
Вывод десятичного представления числа с плавающей запятой, имеющего знак double
e
E
Вывод десятичного экспоненциального представления числа с плавающей запятой, округлённого и преобразованного так, что перед запятой остаётся одна цифра, а количество цифр после запятой соответствует точности представления (по умолчанию точность равна 6, а если указан 0, то символ запятой не выводится вообще). Символ «е» выводится в верхнем или нижнем регистре в зависимости от преобразования double
a
A
Вывод шестнадцатеричного представления числа с плавающей запятой double
g
G
Вывод десятичного представления числа с плавающей запятой или его десятичного экспоненциального представления в зависимости от значения и точности double
n Возврат числа элементов, выведенных функцией printf. Результат записывается в переменную, на которую указывает аргумент. Спецификация может не содержать флагов, ширины поля или точности int *
p Вывод указателя void *

Модификатор ширины поля

В строке формата в printf C может быть записано целое число после знака процента и перед командой форматирования. Оно является модификатором ширины поля и влияет на представление отображаемых данных. Наименьшая ширина поля, предназначенная для значения, определяется этим числом, и присутствие такого модификатора в случае, если аргумент оказывается меньше выделенного ему поля, вызывает добавление к результату пробелов или нулей. Заполнителем по умолчанию служит символ пробела, однако можно установить ноль, прописав его перед спецификацией ширины. Модификатор указывает минимум ширины, и любое превышающее этот минимум значение будет напечатано без помех. Число, к примеру, состоящее менее чем из восьми символов и печатаемое со спецификацией «%08d», окажется дополненным до необходимых восьми знаков нулями.

Подобные модификаторы могут также задавать параметры точности или выравнивания.

Модификатор точности

Модификатор точности служит для определения числа печатаемых десятичных знаков в представлении чисел. Для добавления модификатора точности необходимо поставить точку после спецификации ширины поля и указать нужное значение точности после неё. Модификатор точности определяется для «e», «f», «a», «E», «A» и «F» форматов. Для целых чисел модификатор устанавливает количество отображаемых цифр, добавляя нули в левый разряд, если нужно, а при выводе рациональных чисел определяет необходимое количество знаков после запятой. Применительно к строковым переменным: следующее после точки число в модификаторе точности служит определителем максимальной длины поля при выводе. К примеру, при заданной спецификации формата «%4.8s» будет выведена строка, длина которой находится в диапазоне от четырёх до восьми символов, в случае превышения крайние символы будут опущены.

Другие модификаторы формата

Выравниванием по умолчанию является выравнивание по правому краю, однако это можно изменить, поставив знак «-» после «%». Такая спецификация формата устанавливает выравнивание по левому краю.

Кроме того, функция printf способна различать короткие и длинные типы выводимых целых значений. Допустимые спецификаторы: «о», «d», «u», «i», «x» и «X». Длинный тип значения устанавливается модификатором «l», а короткий – модификатором «h». Например, при выводе длинного целого числа и значения типа short unsigned int спецификации формата выглядят как «%ld» и «%hu» соответственно.

Длина Описание
h Для типов short или unsigned short
l Для типов long или unsigned long
L Для типа long double

Примеры

1. Описание printf C и результаты вызова каждой функции:

2. Вывод на экран простого диалогового сообщения:

3. Программный код:

Выражения, заданные в двойных кавычках перед спецификациями формата, печатаются на экране, также как и следующие за строкой формата аргументы. Результат выполнения приведённых выше функций printf C, описание выходных данных:

Данный пример иллюстрирует вывод на экран при помощи различных форматов строк, целочисленных переменных, символов, а также чисел с плавающей точкой.

Форматный вывод данных (функции printf() и fprintf()).

Для вывода форматированных данных, как правило, применяются функции printf() и fprintf(). Первая записывает данные в поток stdout, а вторая — в указанный файл или поток. Аргументами функции printf() являются строка форматирования и список выводимых переменных. (В функции fprintf() первый аргумент — указатель файла.) Для каждой переменной из списка задание формата вывода осуществляется с помощью следующего синтаксиса:

В простейшем случае указывается только знак процента и спецификатор, например %f. Обязательное поле спецификатор указывает на способ интерпретации переменной: как символа, строки или числа (таблица 1). Необязательное поле флаги определяет дополнительные особенности вывода (таблица 2).

Необязательное поле ширина задает минимальную ширину поля вывода. Если количество выводимых символов меньше указанного значения, поле дополняется слева или справа пробелами или нулями в зависимости от установленных флагов.

Необязательное поле точность интерпретируется следующим образом:

· при выводе чисел формата е, Е и f определяет количество цифр после десятичной точки (последняя цифра округляется);

· при выводе чисел формата g и G определяет количество значащих цифр (по умолчанию 6);

· при выводе целых чисел определяет минимальное количество цифр (если цифр недостаточно, число дополняется ведущими нулями);

· при выводе строк определяет максимальное количество символов, лишние сим­волы отбрасываются (по умолчанию строка выводится, пока не встретится символ \0).

Поля ширина и точность могут быть заданы с помощью символа-заменителя *. В этом случае в списке переменных должны быть указаны их настоящие значения.

Необязательные модификаторы h и l определяют размерность целочисленной переменной: h соответствует ключевому слову short, а l — long.

Таблица 1. Спецификаторы типа переменной в функциях printf() и fprintf()

Спецификатор Тип Формат вывода
c int Символ (переменная приводится к типу unsignedchar)
d, i int Знаковое десятичное целое число
o int Беззнаковое восьмеричное целое число
u int Беззнаковое десятичное целое число
x int Беззнаковое шестнадцатеричное целое число (в качестве цифр от 10 до 15 используются буквы «abcdef’)
X int Беззнаковое шестнадцатеричное целое число (в качестве цифр от 10 до 15 используются буквы «ABCDEF»)
e double Знаковое число с плавающей запятой в формате [ — ] т. ddde xxx, где т — одна десятичная цифра, ddd— ноль или более десятичных цифр (количество определяется значением поля точность, нулевая точность подавляет вывод десятичной точки, по умолчанию точность — 6), ‘е’ — символ экспоненты, ххх — ровно три десятичные цифры (показатель экспоненты)
E double То же, что и е, только вместо символа ‘е’ применяется ‘Е’
f double Знаковое число с плавающей запятой в формате [ — ] mmm.ddd, где mmm — одна или более десятичных цифр, ddd — ноль или более десятичных цифр (количество определяется значением поля точность, нулевая точность подавляет вывод десятичной точки, по умолчанию точность — 6)
g double Знаковое число с плавающей запятой в формате f или е; формат е выбирается, если показатель экспоненты меньше -4 или больше либо равен значению поля точность; десятичная точка не ставится, если за ней не следуют значащие цифры; хвостовые нули не выводятся
G double То же, что и g, но при необходимости выбирается формат Е, а не е
n int * Ничего не выводится; количество символов, выведенных к данному моменту функцией, записывается в переменную
p void * Адрес, содержащийся в указателе (отображается в формате х)
s char * Строка символов; вывод осуществляется до тех пор, пока не будет обнаружен символ \0 или число символов не станет равным значению поля точность

Таблица 2. Флаги в функциях printf() и fprintf()

Флаг Назначение
Если число выведенных символов оказывается меньше указанного, результат выравнивается по левому краю поля вывода (по умолчанию принято правостороннее выравнивание)
+ При выводе знаковых чисел знак отображается всегда (по умолчанию знак устанавливается только перед отрицательными числами)
Если значению поля ширина предшествует символ ‘0’, выводимое число дополняется ведущими нулями до минимальной ширины поля вывода (по умолчанию в качестве заполнителей применяются пробелы); при левостороннем выравнивании игнорируется
пробел Если выводится положительное знаковое число, перед ним ставится пробел (по умолчанию пробел в таких случаях не ставится); игнорируется при наличии флага +
# Для чисел формата о, х и X означает добавление ведущих 0, 0х и 0Х соответственно (по умолчанию отсутствуют); для чисел формата е, Е, g, G и f задает присутствие десятичной точки, даже когда за ней не следуют значащие цифры (по умолчанию точка в таких случаях не ставится); для чисел формата g и G предотвращает отбрасывание хвостовых нулей (по умолчанию отбрасываются)

Форматный ввод

Форматирование вводимых данных в языке С можно осуществлять с помощью достаточно мощных функций scanf() и fscanf(), Различие между ними заключается в том, что последняя требует указания файла, из которого читаются данные. Функция scanf() принимает данные из стандартного входного потока stdin.

Функция scanf(), как и ее «родственники» fscanf() и sscanf(), в качестве аргумента принимает такого же рода строку форматирования, что и функция printf(), осуществляющая вывод данных, хотя имеются и некоторые отличия. Для примера рассмотрим следующее выражение:


scanf(«%2d%5s%4f», sivalue, psz, &fvalue);

Данная функция считывает целое число, состоящее из двух цифр, строку из пяти символов и число с плавающей запятой, образованное не более чем четырьмя символами (2,97, 12,5 и т.п.). Все аргументы, перечисленные после строки форматирования, должны быть указателями, т.е. содержать адреса переменных. Другое выражение:

Первым в строке форматирования стоит пробел. Он служит указанием пропустить все ведущие пробелы, символы табуляции и новой строки, пока не встретится двойная кавычка («). В строке форматирования этот символ защищен обратной косой чертой (\»), так как в противном случае он означал бы завершение самой строки. Таким образом, обратная косая черта является своего рода командой отмены специального назначения следующего за ней символа.

Управляющая последовательность %[^A-Za-z-] говорит о том, что в строку рs1 нужно вводить все, кроме букв и символа дефиса (-). Квадратные скобки, в которых на первом месте стоит знак крышки (^), определяют диапазон символов, из которых не должна состоять вводимая строка. В данном случае в диапазон входят буквы от ‘А’ до ‘Z’ (дефис между ними означает «от и до») и от ‘а’ до ‘z’, а также сам дефис. Если убрать знак ^, то, наоборот, будут ожидаться только буквы и символы дефиса. В конец прочитанной строки добавляется символ \0. Если во входном потоке вслед за открывающей кавычкой первыми встретятся буква или дефис, выполнение функции scanf() завершится ошибкой и в переменные ps1 и рs2 ничего не будет записано, а сама строка останется в буфере потока. Чтение строки ps1 продолжается до тех пор, пока не встретится один из символов, указанных после знака ^.

Вторая управляющая последовательность %*[-] говорит о том, что после чтения строки ps1 должна быть обнаружена группа из одного или нескольких дефисов, которые необходимо пропустить. Символ звездочки (*) указывает на то, что данные должны быть прочитаны, но не сохранены. Отметим два важных момента.

Если после строки ps1 первой встретится буква, а не дефис, выполнение функции scanf() завершится ошибкой, в переменную ps2 ничего не будет записано, а сама строка останется в буфере потока.

Если бы в первой управляющей последовательности символ дефиса не был отмечен как пропускаемый, функция scanf() работала бы неправильно, так как символ дефиса, являющийся «ограничителем» строки ps1, воспринимался бы как часть этой строки. В этом случае чтение было бы прекращено только после обнаружения буквы, а это, в свою очередь, привело бы к возникновению ошибки, описанной в первом пункте.

Последняя управляющая последовательность %[^\»] указывает на то, что в строку ps2 нужно считывать все символы, кроме двойных кавычек, которые являются признаком завершения ввода.

Для полной ясности приведем пример входной строки:

Вот что будет получено в результате: *psl= 65, *ps2 = ааа.

Все вышесказанное справедливо и в отношении функций fscanf() и sscanf(). Функция sscanf() работает точно так же, как и scanf(), но читает данные из указанного символьного массива, а не из потока stdin. В следующем примере показано, как с помощью функции sscanf() преобразовать строку цифр в целое число:

Пример работы с форматным выводом

/*
* printf.c
* Эта программа на языке С демонстрирует применение
* спецификаторов форматирования функции printf().
*/

psz[]= «Строка для экспериментов»;
int iln = 0,

ivalue = 1234;
double dPi = 3.14159265;

/* 1 — вывод символа с */
printf(«\n[%2d] %c»,++iln, c) ;

/* 2 — вывод ASCII-кода символа с */
printf 2 ), отсюда можно заключить, что алгоритм пузырька очень медленен и малоэффективен. Тем не менее, у него есть громадный плюс: он прост и его можно по-всякому улучшать. Чем мы сейчас и займемся.

Во-первых, рассмотрим ситуацию, когда на каком-либо из проходов не произошло ни одного обмена. Это значит, что все пары расположены в правильном порядке, так что массив уже отсортирован. И продолжать процесс не имеет смысла.

Итак, первое улучшение алгоритма заключается в запоминании, производился ли на данном проходе какой-либо обмен. Если нет — алгоритм заканчивает работу.

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

Качественно другое улучшение алгоритма можно получить из следующего наблюдения. Хотя легкий пузырек снизу поднимется наверх за один проход, тяжелые пузырьки опускаются с минимальной скоростью: один шаг за итерацию. Так что массив 2 3 4 5 6 1 будет отсортирован за 1 проход, а сортировка последовательности 6 1 2 3 4 5 потребует 5 проходов.

Чтобы избежать подобного эффекта, можно менять направление следующих один за другим проходов. Получившийся алгоритм иногда называют «шейкер-сортировкой».

Насколько описанные изменения повлияли на эффективность метода? Среднее количество сравнений, хоть и уменьшилось, но остается O(n2), в то время как число обменов не поменялось вообще никак. Среднее(оно же худшее) количество операций остается квадратичным.

Дополнительная память, очевидно, не требуется. Поведение усовершенствованного (но не начального) метода довольно естественное, почти отсортированный массив будет отсортирован намного быстрее случайного. Сортировка пузырьком устойчива, однако шейкер-сортировка утрачивает это качество.

На практике метод пузырька, даже с улучшениями, работает, увы, слишком медленно. А потому — почти не применяется.

Сортировка вставками

Сортировка вставками похожа на процесс тасования карточек с именами. Регистратор заносит каждое имя на карточку, а затем упорядочивает карточки по алфавиту, вставляя карточку в верхнюю часть стопки в подходящее место. Опишем этот процесс на примере пятиэлементного списка A = 50, 20, 40, 75, 35 (рис. 9).

В функцию InsertionSort передается массив A и длина списка n. Рассмотрим i-ый проход (1 2 ). Наилучший случай – когда исходный список уже отсортирован. Тогда на i-ом проходе вставка производится в точке A[i], а общее число сравнений равно n-1, т.е. сложность составляет O(n). Наихудший случай возникает, когда список отсортирован по убыванию. Тогда каждая вставка происходит в точке A[0] и требует i сравнений. Общее число сравнений равно n(n-1)/2, т.е. сложность составляет O(n 2 ).

В принципе, алгоритм сортировки вставками можно значительно ускорить. Для этого следует не сдвигать элементы по одному, как это продемонстрировано в приведенном выше примере, а находить нужный элемент с помощью бинарного поиска, описанного в предыдущем номере (то есть, в цикле разбивая список на две равные части, пока в списке не останется один-два элемента), а для сдвижки использовать функции копирования памяти. Такой подход дает довольно высокую производительность на небольших массивах. Основным узким местом в данном случае является само копирование памяти. Пока объем копируемых данных (около половины размера массива) соизмерим с размером кэша процессора 1 уровня, производительность этого метода довольно высока. Но из-за множественных непроизводительных повторов копирования, этот способ менее предпочтителен, чем метод «быстрой» сортировки, описанный в следующем разделе. Этот же метод можно рекомендовать в случае относительно статичного массива, в который изредка производится вставка одного-двух элементов.

Быстрая» сортировка

Итак, мы рассмотрели алгоритм сортировки массива, имеющий сложность порядка O(n 2 ). Алгоритмы, использующие деревья (турнирная сортировка, сортировка посредством поискового дерева), обеспечивают значительно лучшую производительность O(n log 2 n). Несмотря на то, что они требуют копирования массива в дерево и обратно, эти затраты покрываются за счет большей эффективности самой сортировки.

Широко используемый метод пирамидальной сортировки также обрабатывает массив «на месте» и имеет эффективность O(n log2n). Однако «быстрая» сортировка, которую изобрел К.Хоар, для большинства приложений превосходит пирамидальную сортировку и является самой быстрой из известных до сих пор.

Как и для большинства алгоритмов сортировки, методика «быстрой» сортировки взята из повседневного опыта. Чтобы отсортировать большую стопку алфавитных карточек по именам, можно разбить ее на две меньшие стопки относительно какой-нибудь буквы, например K. Все имена, меньшие или равные K, идут в одну стопку, а остальные – в другую.

Рис. 10. Выполнение «быстрой» сортировки

Затем каждая стопка снова делится на две. Например, на рис. 10 точками разбиения являются буквы F и R. Процесс разбиения на все меньшие и меньшие стопки продолжается.

В алгоритме «быстрой» сортировки применяется метод разбиения с определением центрального элемента. Так как мы не можем позволить себе удовольствие разбрасывать стопки по всему столу, как при сортировке алфавитных карточек, элементы разбиваются на группы внутри массива. Рассмотрим алгоритм «быстрой» сортировки на примере, а затем обсудим технические детали. Пусть дан массив, состоящий из 10 целых чисел:

A = 800, 150, 300, 600, 550, 650, 400, 350, 450, 700

Массив имеет нижнюю границу, равную 0 (low), и верхнюю границу, равную 9 (high). Его середина приходится на 4 элемент (m >

Рис. 11. Выполнение «прохода» быстрой сортировки

Оригинальность «быстрой» сортировки заключается во взаимодействии двух индексов в процессе сканирования списка. Индекс scanUp перемещается вверх по списку, а scanDown – вниз. Мы продвигаем scanUp вперед и ищем элемент A[scanUp] больший, чем центральный. В этом месте сканирование останавливается, и мы готовимся переместить найденный элемент в верхний подсписок. Перед тем, как это перемещение произойдет, мы продвигаем индекс scanDown вниз по списку и находим элемент, меньший или равный центральному. Таким образом, у нас есть два элемента, которые находятся не в тех подсписках, и их можно менять местами.

Swap (A[scanUp], A[scanDown]); // менять местами партнеров

Этот процесс продолжается до тех пор, пока scanUp и scanDown не зайдут друг за друга (scanUp = 6, scanDown = 5). В этот момент scanDown оказывается в подсписке, элементы которого меньше или равны центральному. Мы попали в точку разбиения двух списков и указали окончательную позицию для центрального элемента. В нашем примере поменялись местами числа 600 и 450, 800 и 350, 650 и 400 (см. рис. 12).

Рис. 12. Обмен элементами при выполнении
«быстрой» сортировки

Затем происходит обмен значениями центрального элемента A[0] с A[scanDown]:

В результате у нас появляются два подсписка A[0] – A[5] и A[6] – A[9], причем все элементы первого подсписка меньше элементов второго, и последний элемент первого подсписка является его наибольшим элементом. Таким образом, можно считать, что после проделанных операций подсписки разделены элементом А[5] = 550. Если теперь отсортировать каждый подсписок по отдельности, то у нас получится полностью отсортированный массив. Заметьте, что по сути оба этих подсписка являются такими же массивами, как и исходный, поэтому к ним можно применить тот же самый алгоритм. Применение того же алгоритма к частям массива называется рекурсивной фазой.

Одним и тем же методом обрабатываются два подсписка: Sl(A[0] – A[4]) и Sh(A[6] – A[9]). Элемент А[5] обрабатывать не надо, так как он уже находится на своем месте.

Рис. 13. Разбиение массива на части при
выполнении «быстрой» сортировки

Тот же алгоритм применяется для каждого подсписка, разбивая эти подсписки на меньшие части, пока в подсписке не останется одного элемента или пока подсписок не опустеет.

Этот рекурсивный алгоритм разделяет список A[low]—A[high] по центральному элементу, который выбирается из середины списка

После обмена местами центрального элемента с A[low], задаются начальные значения индексам scanUp = low + 1 и scanDown = high, указывающим на начало и конец списка, соответственно. Алгоритм управляет этими двумя индексами. Сначала scanUp продвигается вверх по списку, пока не превысит значение scanDown или пока не встретится элемент больший, чем центральный.

while (scanUp k (k = log2n), а центральный элемент располагается точно посередине каждого списка и разбивает его на два подсписка примерно одинаковой длины.

При первом сканировании производится n-1 сравнений. В результате создаются два подсписка размером n/2. На следующей фазе обработка каждого подсписка требует примерно n/2 сравнений. Общее число сравнений на этой фазе равно 2(n/2) = n. На следующей фазе обрабатываются четыре подсписка, что требует 4(n/4) сравнений, и т.д. В конце концов процесс разбиения прекращается после k проходов, когда получившиеся подсписки содержат по одному элементу. Общее число сравнений приблизительно равно

n + 2(n/2) + 4(n/4) + . + n(n/n) = n + n + . + n = n * k = n * log2n

Для списка общего вида вычислительная сложность «быстрой» сортировки равна O(n log2 n). Идеальный случай, который мы только что рассмотрели, фактически возникает тогда, когда массив уже отсортирован по возрастанию. Тогда центральный элемент попадает точно в середину каждого подсписка.

Если массив отсортирован по убыванию, то на первом проходе центральный элемент обнаруживается на середине списка и меняется местами с каждым элементом как в первом, так и во втором подсписке. Результирующий список почти отсортирован, алгоритм имеет сложность порядка O(n log2n).

Рис. 14. Состояние массива после первого прохода

Наихудшим сценарием для «быстрой» сортировки будет тот, при котором центральный элемент все время попадает в одноэлементный подсписок, а все прочие элементы остаются во втором подсписке. Это происходит тогда, когда центральным всегда является наименьший элемент. Рассмотрим последовательность 3, 8, 1, 5, 9.

На первом проходе производится n сравнений, а больший подсписок содержит n-1 элементов. На следующем проходе этот подсписок требует n-1 сравнений и дает подсписок из n-2 элементов и т.д. Общее число сравнений равно:

n + n-1 + n-2 + . + 2 = n(n+1)/2 – 1

Сложность худшего случая равна O(n 2 ), т.е. не лучше, чем для сортировок вставками и выбором. Однако этот случай является патологическим и маловероятен на практике. В общем, средняя производительность «быстрой» сортировки выше, чем у всех рассмотренных нами сортировок.

Алгоритм QuickSort выбирается за основу в большинстве универсальных сортирующих утилит. Если вы не можете смириться с производительностью наихудшего случая, используйте пирамидальную сортировку – более устойчивый алгоритм, сложность которого равна O(n log2n) и зависит только от размера списка.

Порядок выполнения работы

6. Ознакомиться с теоретическими сведениями.

7. Получить вариант задания у преподавателя.

8. Выполнить задание.

9. Продемонстрировать выполнение работы преподавателю.

10. Оформить отчет.

11. Защитить лабораторную работу.

7. 4. Требования к оформлению отчета

Отчет по лабораторной работе должен содержать следующие разделы:

· задание на лабораторную работу;

· ответы на контрольные вопросы;

· выводы по проделанной работе.

Задание на работу

1. Реализовать сортировку пузырьком для одномерного массива.

2. Реализовать сортировку вставками для одномерного массива.

3. Реализовать «быструю» сортировку для одномерного массива.

4. Реализовать сортировку пузырьком для двумерного массива.

5. Реализовать сортировку вставками для двумерного массива.

6. Реализовать «быструю» сортировку для двумерного массива.

9. 6. Контрольные вопросы

· В чем заключается идея сортировки пузырьком?

· В чем заключается идея сортировки вставками?

· В чем заключается идея «быстрой» сортировки?

· Какая из предложенных в работе сортировок эффективнее? Почему?

Лабораторная работа № 8.
Алгоритмические основы программирования на языке С++.
Структуры данных типа дерево

Цель работы

Ознакомится с представлением данных в виде деревьев. Изучить основные алгоритмы обхода деревьев.

Теоретические сведения

Элементы могут образовывать и более сложную структуру, чем линейный список. Часто данные, подлежащие обработке, образуют иерархическую структуру, подобную изображенной на рис. 15, которую необходимо отобразить в памяти компьютера и, соответственно, описать в структурах данных.

Каждый элемент такой структуры может содержать ссылки на элементы более низкого уровня иерархии, а может быть, и на объект, находящийся на более высоком уровне иерархии.

Рис. 15. Структура дерева

Если абстрагироваться от конкретного содержания объектов, то получится математический объект, называемый деревом (точнее, корневым деревом).

Корневым деревом называется множество элементов, в котором выделен один элемент, называемый корнем дерева, а все остальные элементы разбиты на несколько непересекающихся подмножеств, называемых поддеревьями исходного дерева, каждое из которых, в свою очередь, есть дерево.

При представлении в памяти компьютера элементы дерева (узлы) связывают между собой таким образом, чтобы каждый узел (который согласно определению обязательно является корнем некоторого дерева или поддерева) был связан с корнями своих поддеревьев.

Наиболее распространенными способами представления дерева являются следующие три (или их комбинации).

Printf, fprintf, sprintf форматный вывод

Перевод статьи «Secrets of printf» [1], статья посвящена практическому применению оператора вывода printf.

Оператор printf — это просто функция языка C, которая выполняет форматированную печать неких значений, параметров функции. «Форматированную» — означает, что перед выводом параметров на печать параметры функции преобразуются в текст по особым правилам (формату), задаваемым специальной строкой, так называемой строкой форматирования. Точно такая же функция printf есть и на языке PERL. В этой заметке сделана попытка объяснить, как работает printf, и как правильно разработать соответствующую строку форматирования для любого случая.

[1. Основные понятия]

В старые времена программисты должны были писать свои собственные подпрограммы для ввода и вывода чисел. По сути это было не очень сложным делом. Сначала надо было выделить массив текстовых символов для хранения результата, затем просто разделить число на 10, запомнить остаток, добавить 0x30 для получения ASCII кода цифры, и сохранить цифру в конец массива. Далее эту процедуру нужно было повторить, чтобы найти все десятичные цифры числа. Затем нужно было вывести массив на печать. Все просто, не правда ли?

Однако несмотря на то, что просто (для гения типа Эйнштейна), однако все еще требует применения некоторых усилий. И что мы будем делать в более сложных случаях при проверке ошибок, или при выводе отрицательных чисел? Чтобы решить эти проблемы, программисты создали специальные библиотеки с предварительно написанными функциями вывода. И это было неплохо. В конечном счете самые популярные из этих функций были канонизированы для того, чтобы составить «стандартные» библиотеки.

Это означало, что теперь программистам не нужно было снова и снова выдумывать подпрограммы для печати чисел. Это также означало, что самые любимые опции вывода также должны были бы стать стандартными.

Так родился printf.

[2. Простая печать]

В самом простом случае функция printf получает один аргумент: строка символов, которая должна быть напечатана. Как ясно из названия, эта строка состоит из символов, каждый из которых будет выведен именно так, как он появляется в строке. Так, оператор printf(«xyz»); должен просто вывести сначала x, затем y, и наконец z. Это не является по-настоящему «форматированной» печатью (formatted printf), однако это базовая операция, которую может произвести printf.

2.1. «Натуральные» специальные символы

Чтобы идентифицировать начало строки, мы применили двойные («) кавычки в её начале. Чтобы идентифицировать конец строки, мы поместили двойные кавычки также и в конец строки. Но как быть, если нам нужно напечатать также и двойные кавычки? Мы не можем просто поместить двойные кавычки в печатаемую строку, потому что тогда этот символ будет ошибочно задавать маркер конца строки. Таким образом, двойные кавычки стали специальным символом. Для них уже не работает правило печатаю-то-что-вижу. Как все-таки напечатать двойные кавычки?

Различные языки программирования применяют разные способы для решения этой проблемы. Некоторые требуют, чтобы специальный символ был введен дважды. Язык C использует обратный слеш (делительная черта, \) в качестве управляющего символа (escape character), для изменения значения следующего за ним символа. Таким образом, для печати двойных кавычек нужно указать обратный слеш и за ним двойную кавычку (\»). Чтобы напечатать сам обратный слеш, то его нужно ввести дважды. Таким образом, первый обратный слеш означает «следующий символ имеет альтернативное значение», и второй обратный слеш теперь означает «напечатать обратный слеш».

Без обратного слеша специальные символы имеют свое натуральное специальное назначение. С обратным слешем они печатаются так, как видятся. В таблице приведен частный список примеров использования специальных символов.

\ escape, управляющая последовательность для следующего символа
\\ печатается обратный слеш
« обозначает начало или конец строки
печатаются двойные кавычки
начало или конец символьной константы
\’ печатается одинарная кавычка
% начало спецификации формата
\% печатается символ процента
%% также печатается символ процента

2.2. Альтернативные специальные символы

Однако еще у нас есть символы, которые печатаются без обратного слеша как обычно, но когда слева к ним добавляется обратный слеш, они становятся также спецсимволами. Например, это символ новой строки (new line, или line feed LF, код ASCII 0x0A). Чтобы напечатать букву n, нам нужно просто указать в строке n. Чтобы перевести печать на новую строку, мы должны напечатать \n, что вовлекает альтернативное значение для n (новая строка). В следующей таблице приведен список таких альтернативных спецсимволов.

\a звуковой сигнал, предупреждение (звоночек, bell)
\b backspace, вернуться на 1 символ назад (затереть символ)
\f form feed, переход на новый лист
\n newline, новая строка (linefeed, перевод строки, код ASCII 0x0D, переход печати на новую строку)
\r carriage return, возврат каретки (CR, код ASCII 0x0D, позиция печати возвращается на начало строки)
\t tab, табуляция по горизонтали
\v vertical tab, вертикальная табуляция

[3. Как задавать формат вывода числа (Format Specifications)]

Настоящая сила printf раскрывается при выводе на печать переменных. К примеру, мы можем указать спецификатор формата %d . Если такой спецификатор присутствует в строке, то мы должны предоставить число в качестве второго параметра функции printf. Функция printf сделана так, что может принимать неограниченное количество параметров, если это необходимо (printf относится к функциям с переменным количеством параметров). Пример ниже показывает, как это происходит.

В этом простом примере функция printf имеет 2 аргумента. Первый аргумент — строка «I am %d years old\n» (в ней содержится спецификатор формата %d ). Вторым аргументом является целое число age.

3.1. Список аргументов

Когда printf обрабатывает свои аргументы (список аргументов, отделенных друг от друга запятыми), он начинает печатать символы, которые находит в левом аргументе, символ за символом. Когда в этом процессе попадается символ процента (%), то printf знает, что это спецификатор формата — специальный набор символов, который задает, как надо вывести число. Следующее по порядку с списке аргументов число выводится так, как указано в спецификаторе формата. Затем процесс обработки символов (вывод их на печать) первого аргумента продолжается. Можно указать в строке 1 аргумента функции printf несколько спецификаторов формата. В этом случае 1 спецификатор будет выводить первый дополнительный аргумент, 2 спецификатор второй дополнительный аргумент и так далее, до конца строки. Вот еще один пример (указано 2 спецификатора формата и два дополнительных аргумента функции printf):

3.2 Символ процента (Percent, %)

Каждый спецификатор формата начинается со знака процента, и заканчивается буквой. Буквы выбраны так, что они имеют некое мнемоническое обозначение для используемого формата. Вот список некоторых мнемоник формата:

%c выводит на печать одиночный символ (character)
%d выводит на печать десятичное число (представление числа с основанием 10)
%e выводит на печать числа с плавающей запятой (floating-point) в экспоненциальном формате
%f выводит на печать числа с плавающей запятой (floating-point)
%g выводит на печать числа с плавающей запятой (floating-point) в общем формате
%i выводит на печать десятичного целого числа (представление числа с основанием 10)
%o выводит на печать числа в восьмеричном формате (представление числа с основанием 8)
%s выводит на печать строки символов
%u выводит на печать целое десятичное число без знака (представление числа с основанием 10)
%x выводит на печать целого шестнадцатеричного числа (представление числа с основанием 16)
%% выводит на печать символ процента (можно использовать для этого также \%)

Самый простой вывод десятичного числа (целого и с плавающей точкой) требует указания только %d. В таблице приведены некоторые примеры аргументов printf и полученных результатов.

Имейте в виду, что в случае использования %d размер получаемой строки заранее не известен. Функция printf сгенерирует строку такого размера, какой нужен.

3.3. Опция ширины формата (Width Option)

Как уже упоминалось, простой печати чисел недостаточно. Есть другие желаемые опции. Возможно, самая важная из них — опция ширины формата. Если указать спецификатор формата %5d, то будет гарантировано, что вывод числа всегда займет 5 символьных позиций (если нужно, то больше, но никак не меньше). Эта возможность очень полезна при печати таблиц, потому что и большие, и маленькие числа займут в строке одинаковое место. Не так давно вся печать была моноширинной (monospaced, все символы по точкам в ширину были одинаковы), т. е. и символ w, и символ i занимали одинаковое место в строке по ширине. Это остается общим правилом в текстовых редакторах, используемых программистами.


Чтобы напечатать десятичное число определенной (как минимум заданной, не меньше) ширины, скажем шириной в 5 пробелов, спецификатор формата должен быть %5d. В таблице приведены простые примеры использования опции ширины (пробелы для наглядности показаны нижней квадратной скобкой).

Имейте в виду, что результат вывода будет дополнен слева пробелами до необходимой указанной ширины (для примеров в таблице это 5 символов). Слишком большие числа, которые требуют для печати большее количество символов, будут выведены полностью.

Чтобы добиться нормального использования, поле опции ширины должно быть указано таким, чтобы удовлетворять максимальному размеру ожидаемого выводимого числа. Например, если Ваши числа могут состоять из 1, 2 или максимум 3 цифр, то формат %3d подойдет. Опция ширины будет работать неправильно, если потребуется напечатать число, которое слишком большое, чтобы уместиться в заданную ширину поля. Функция printf примет решение вывести такие числа полностью, даже если они займут место больше, чем задано в спецификаторе ширины формата. Так сделано потому, что лучше вывести правильный ответ, пусть даже некрасиво, чем напечатать урезанный (неправильный) результат, и потом гадать, где же произошла ошибка.

3.4. Заполнение лишнего места

Когда печатается маленькое по размеру число наподобие 27 в поле формата %5d, встает вопрос — чем и как заполнить 3 другие (пустые) места печати. Цифры 27 можно напечатать по-разному: вывести в первых двух позициях, в последних двух позициях, или где-то посередине. Также пустые места могут быть заполнены не просто пробелами, а звездочками (***27, или 27***, или **27*), или знаками доллара ($$$27), или символами равенства (===27), или начальными нулями (наподобие 00027).

Эти дополнительные символы часто называют символами «проверочной защиты» (check protection), потому что они предназначены помешать плохим парням изменить печатаемую сумму в долларах. Относительно просто поменять заполнение пробелами на что-то другое. Гораздо сложнее подменить символ звездочки, знак доллара и ли символ равенства.

Функция printf предоставляет заполнение пространства пробелами (слева или справа), и заполнение нулями (только слева). Если Вам нужна check protection, или центрирование, то нужно использовать какие-то другие дополнительные методы. Но даже без check protection или центрирования printf
все равно имеет впечатляющую коллекцию опций форматирования.

3.5. Опция выравнивания (Justify Option)

Вывод на печать чисел функцией printf может быть выровнена влево (left-justified, напечатана в поле слева) или вправо (right-justified, напечатано в поле справа). Наиболее естественной выглядит печать чисел выровненными вправо, с дополнением пробелами слева. Так работает спецификатор формата %5d, он означает: напечатать число по основанию 10 в поле шириной 5 символов, и цифры числа выровнять по правому краю, слева дополнив нужным количеством пробелов.

Чтобы сделать число выровненным слева, к спецификатору формата нужно добавить знак минуса (-). Чтобы напечатать число в поле шириной в 5 символов, с выравниванием по левому краю спецификатор формата будет %-5d. В таблице приведены некоторые примеры использования левого выравнивания.

Так же, как и раньше, для коротких чисел результат будет дополнен справа пробелами. Слишком большие числа будут выведены без дополнения пробелами и не урезанные.

3.6. Заполнение лидирующими нулями (Zero-Fill Option)

Чтобы печать даты выглядела красиво и качественно, обычно одиночные цифры даты и месяца дополняют слева нулем. Это и есть «лидирующий ноль». Мы можем написать May 5, 2003, или как принято в США 05/05/2003. Можно написать также дату в виде 2003.05.05. Обратите внимание, что лидирующий ноль не изменяет значение дат, а просто добавляет наглядности. Таким способом отформатированная дата хорошо выглядит в списке.

Когда используется zero-filled (заполнение лидирующими нулями), нули всегда добавляются спереди, и результат получается выровненным как по левому, так и по правому краю. В этом случае знак минуса не дает эффекта. Чтобы вывести число в 5 позиций с дополнением нулями слева применяйте спецификатор формата %05d. В таблице показаны примеры использования и полученные результаты.

Короткие числа будут дополнены лидирующими нулями. Числа большого размера будут напечатаны как есть, без изменения.

3.7. Забава со знаками «плюс»

Отрицательные числа всегда будут выведены со знаком минуса (-). Положительные числа и нули обычно не печатаются со знаком, однако Вы можете это задать принудительно. Символ плюса (+) в спецификаторе формата делают такой запрос. Чтобы напечатать число со знаком в поле шириной 5 символов, спецификатор формата должен быть %+5d. В таблице показаны примеры использования и полученные результаты.

Имейте в виду, что 0 трактуется как положительное число. Короткие числа будут дополнены нужным количеством указанных заполнителей. Слишком большие числа будут выведены без дополнения и не урезанные.

Плюс и минус не связаны друг с другом. Они оба могут появляться в спецификаторе формата.

3.8. Невидимый знак «плюс»

Знак + немного причудлив, он может быть невидимым. В этом случае вместо печати + на положительных числах (и при печати 0), мы напечатаем пробел, где этот знак должен был бы находиться. Это может оказаться полезным при печати выровненных влево чисел, если Вы хотите, чтобы знак минуса значительно выделялся. В примерах ниже показаны два альтернативных варианта.

Помните о том, что спецификатор формата %-5d даст нам другой результат, который мы уже рассматривали ранее (он показан здесь снова для наглядности):

Имейте в виду, что знак + исчезает, но все еще занимает место слева от числа. Имейте в виду также, что мы можем скомбинировать некоторые опции в одном и том же спецификаторе формата. В этом случае мы имеем скомбинированные опции +, -, 5, или пробел, -, 5, или просто -, 5.

3.9. +, пробел и 0

Здесь приведен другой пример одновременного комбинирования некоторых опций в одном спецификаторе формата. Использование спецификаторов формата % 05d или %0 5d дадут нам следующие результаты:

Использование спецификаторов формата %+05d или %0+5d дадут нам следующие результаты:

Когда мы одновременно комбинируем + и пробел в одном спецификаторе формата, пробелы организуют пространство для знака, которое занимал бы знак +. Результат тот же, если бы даже пробел не был бы указан. Символ + имеет приоритет над пробелом.

3.10. Общие замечания по формату вывода

Опции вывода также называют флагами (flags), и между собой они могут появляться в любом порядке. В таблице приведен их частный список.

После опций если нужно, может быть указана минимальная ширина поля вывода.

[4. Вывод на печать строк]

Опция %s позволяет нам печатать строку внутри строки. Ниже дан пример.

Флаг левого выравнивания может быть применен к строкам, однако конечно же дополнение слева нулями (zero fill), знак +, и невидимый + являются бессмысленными.

[5. Вывод чисел с плавающей точкой (Floating Point)]

Числа с плавающей точкой наподобие 3.1415 содержат внутри себя точку. Обычные целые числа типа 27 не имеют такой точки.

Для печати чисел с плавающей точкой (float, double) флаги и правила работают точно так же, как и для целых чисел, но еще есть несколько новых опций. Самая важная указывает, какое количество цифр может появиться после десятичной точки. Это количество цифр называется точностью (precision) числа.

В обычной коммерции используются прайсы, где цены часто фигурируют как целые доллары или доллары и центы (precision составляет 0 или 2 цифры). Для цены на бензин цены упоминаются как доллары, центы, и десятая доля от цента (precision составляет 3 цифры). Ниже приведены примеры, как может быть выведено на печать число e=2.718281828.

Обратите внимание, что если в спецификаторе формата указаны точка и число, то это число (precision) указывает, сколько чисел должно появиться после десятичной точки.

Имейте в виду, что если не указаны точка и precision для %f, то по умолчанию будет приведен формат %.6f (6 цифр после десятичной точки).

Имейте также в виду, что если указана precision 0, то десятичная точка также исчезает. Если Вы хотите её вернуть, то нужно это сделать принудительно в виде простого текста (после спецификатора формата %f).

Мы можем указать оба и ширину (width), и точность (precision) одновременно в одном спецификаторе формата. Имейте в виду, что 5.2 означает общую длину 5, с 2 цифрами после десятичной точки. Самая распространенная ошибка, когда думают, что это означает 5 цифр до точки и 2 цифры после точки, но это неправильно. Будьте внимательны.

Можно также комбинировать precision с флагами, с которыми мы уже познакомились, чтобы указать левое выравнивание, дополнение слева нулями, применение знака +, и т. д.

[6. Как лучше всего разрабатывать формат]

Если Вы придумываете спецификатор формата, то первый шаг, который нужно сделать — решить, что именно Вы печатаете. Если это целое число (unsigned char, short, int, long), число с плавающей точкой (float, double), строка (char []) или одиночный символ (char), то Вы должны выбрать соответствующий спецификатор для базового типа формата.

Второй важный вопрос — какой ширины в символах должна быть печатаемое поле. Обычно это определяет самое большое по величине печатаемое число, которое Вы ожидаете при нормальной работе программы. Иногда этот размер определяется шириной предоставленного поля в форме или таблице (как например, в поле на кассовом чеке или на таблице счета-фактуры).

Решите, что Вы хотели бы увидеть на печати в различных ситуациях, в которых работает программа. В этой статье мы часто рассматривали результаты использования маленького положительного числа, маленького отрицательного числа, положительного числа вышедшего за установленный размер, отрицательного числа вышедшего за установленный размер. Опцию ширины Вы должны задать так, чтобы она хорошо подходила как к большим (но не превышающим максимальный размер), так и к малым числам. В самом простейшем случае можно разработать формат для корректного вывода самого большого числа, но если нужно обеспечить заданную относительную точность, то может потребоваться набор условных операторов с разными вариантами формата.

[7. Советы для тестирования]

Тест printf включает проверку появления подходящих проблем. Сам по себе алгоритм работы printf непрост для полного понимания — как будет работать вывод в разных ситуациях. Поэтому изучение тестового вывода printf даст более точную картину — что работает не так.

Вы можете сделать этот процесс нахождения ошибок очень быстрым и точным. Если Вы смотрите на результат работы функции printf с разными опциями форматирования, то можете быстро увидеть, какой спецификатор формата подходит лучше всего. Это быстро может сузить варианты форматирования до одного или двух.

7.1. Простые случаи

Можно просто увидеть, есть ли у коротких чисел лидирующие нули. Если так, то в спецификаторе формата здесь должен быть 0. Также просто увидеть, есть ли у положительных чисел знак +. Если этот так, то + должен быть и в спецификации форматирования.

7.2. Перед, между, позади

Следующее, что нужно проверить — что печатается до выводимого числа, в промежутке, и после. К примеру, В спецификации форматирования типа x%5dz, где x стоит перед числом и z за числом. Части x и z не входят в спецификатор формата, но входят как часть в печатаемый результат. Все остальное относится к тому, что печатается «между».

Для того, чтобы определить, что же печатается за числом, посмотрите на вывод отрицательного числа чрезмерно большого размера. Любые пробелы до выведенного числа и после него покажут на пробелы до и после спецификатора формата. Например, если -2035065302 печатается как __-2035065302_ (здесь для наглядности пробелы заменены на подчеркивания), то можете быть уверенными, что строка печати была наподобие __%. _ , с двумя пробелами перед и одним пробелом после спецификатора формата. Это произошло потому, что чрезмерно большое число заняло все позиции, которые были отведены в спецификаторе формата.

Как только Вы определили, что перед, и что позади, Вы можете использовать эту информацию, чтобы сделать соответствующий выбор спецификатора формата. Часто бывает, что искомый ответ сразу становится очевидным.

7.3. Невидимый знак +

Сравните между собой вывод чрезмерно большого отрицательного и такого же положительного числа. Если положительное число имеет дополнительный пробел слева, то в этом месте формат задает невидимый знак +. Если слева от числа нет дополнительного пробела, но невидимый знак не задан.

7.4. Левое выравнивание

Вычтите друг из друга то, что перед, и то что позади. Посмотрите, что осталось слева. Посмотрите на вывод маленького отрицательного числа. Где Вы видите дополнительные печатаемые пробелы? Если они находятся спереди числа, то применено правое выравнивание числа. Если они находятся позади, то число выровнено при печати влево. Если пробелы есть и спереди, и сзади, значит Вы что-то делаете неправильно.

[8. Заключение]

Функция printf является мощным инструментом (в умелых руках) для вывода чисел и чего-нибудь еще, хранимого в переменных. Из-за того, что инструмент мощный и имеет много возможностей, он несколько сложен в освоении. Если попытаться использовать printf наобум, без изучения документации, то его сложность часто делает невозможным понимание принципа вывода. Однако при незначительном изучении сложность может быть развернута в простые возможности, включающие width (ширина поля вывода), precision (точность), signage (управление выводом знака), justification (выравнивание) и fill (заполнение пустых мест поля вывода). Если распознать и понять эти возможности, то printf становится удобным и надежным помощником при выводе значений на печать.

[Ссылки]

1. Secrets of “printf”, Professor Don Colton, Brigham Young University Hawaii .
2. IAR EWB ARM: форматированный вывод printf библиотеки DLIB.

Форматный вывод — функция printf

Две функции: printf для вывода и scanf для ввода позволяют преобразовывать численные величины в символьное представление и обратно. Они также позволяют ге­нерировать и интерпретировать форматные строки. Мы уже всюду в предыдущих главах неформально использовали функцию printf; здесь приводится более полное и точное описание. Функция

printf(control, arg1, arg2, . )

преобразует, определяет формат и печатает свои аргументы в стандартный вывод под управлением строки control. Управляю­щая строка содержит два типа объектов: обычные символы, ко­торые просто копируются в выходной поток, и спецификации преобразований, каждая из которых вызывает преобразование и печать очередного аргумента printf.

Строка формата используется при каждом обращении к функциям семейства . printf для указания того, как функция должна преобразовать, сформатировать и вывести свои аргументы.

Аргументов не должно быть меньше спецификаторов формата. В противном случае результаты непредсказуемы и, возможно, катастрофические. Лишние аргументы (сверх количества, требуемого строкой формата) просто игнорируются.

Строка формата — символьная строка, содержащая объекты двух типов: основные символы и спецификаторы формата.

· Основные символы просто копируются в выходной поток без изменений.

· Спецификаторы формата вызывают применение определяемого ими форматирования к значениям аргументов перед выводом их в поток.

Спецификаторы формата функций семейства . printf имеют следующую форму:

% [flags] [width] [.prec] [F|N|h|l|L] type

Каждый спецификатор формата начинается с символа процента (%). После % следуют, в указанном порядке:

· необязательная последовательность символов-флагов, [flags] — Выравнивание при выводе, отображение знака числа, десятичной точки, незначащих нулей, восьмеричные и шестнадцатеричные префиксы

o — Результат выравнивается влево и дополняется пробелами справа. Если не задан, результат выравнивается вправо и дополняется слева пробелами или нулями.

o + Результат преобразования с учетом знака всегда начинается со знака плюс (+) или минус (-).

o Пробел Если значение неотрицательно, вывод начинается с пробела вместо плюса; отрицательные значения начинаются с минуса. Плюс (+) имеет приоритет над пробелом ( ), если заданы оба.

o # Определяет, что arg преобразуется с помощью «альтернативной формы». Смотри следующую таблицу.

Символ Воздействие # на arg
c,s,d,i,u Не влияет.
o В начало ненулевого arg добавляется 0.
x или X В начало arg добавляется 0х (или 0Х)
e,E или f Результат всегда содержит десятичную точку, даже если после нее нет цифр. Обычно десятичная точка появляется, только если после нее есть цифры.
g или G То же, что е и Е; кроме того, незна­чащие нули не удаляются.

· необязательный спецификатор ширины, [width] — Минимальное количество символов для печати, дополнение пробелами или нулями. Ширина задается одним из двух способов: непосредственно — строкой десятичных цифр, или косвенно — звездочкой (*). Если вы используете звездочку, минимальная ширина поля вывода определяется значением очередного аргумента (который должен иметь тип int). Ни при каких обстоятельствах спецификатор ширины, его отсутствие или неверное значение не будет вызывать усечения выводимого поля. Если результат преобразования оказывается шире установленного спецификатором, поле вывода просто расширяется, чтобы поместить результат преобразования.

o n По крайней мере n символов будут напечатаны. Если выводимое значение содержит менее n символов, поле вывода дополняется пробелами (справа — если указан символ-флаг «минус»(-), слева — в остальных случаях).

o 0n По крайней мере n символов будут напечатаны. Если выводимое значение содержит менее n символов, поле вывода дополняется нулями слева.

o * Значение спецификатора ширины содержится в списке аргументов и предшествует форматируемому аргументу.

· необязательный спецификатор точности, [.prec] — Максимальное количество символов для печати; для целых чисел — минимальное количество цифр для печати. Спецификатор точности всегда начинается с точки точности (.), которая отделяет его от предшествующего спецификатора ширины. Как и ширина, точность задается либо непосредственно — строкой десятичных цифр, либо косвенно — звездочкой (*). Если вы используете звездочку, точность поля вывода определяется значением очередного аргумента (который интерпретируется как int). Если вы используете звездочки для ширины, точности, или для того и другого, аргумент ширины должен соответствовать текущему спецификатору, за ним должен следовать аргумент точности, а затем — аргумент с данными, которые должны быть преобразованы.

o (не задан) Точность устанавливается по умолчанию: 1 — для типов d, i, o, u, x, X; 6 — для типов e, E, f; все значащие цифры — для типов g, G; выводятся все символы до первого нуль-символа — для типа s; не влияет — на тип с.

o .0 Для типов d,i,o,u,x точность устанавливается по умолчанию; для типов e,E,f — не выводится десятичная точка.

o .n Выводится n символов или n десятичных позиций. Если выводимое значение содержит более n символов, оно может быть усечено или округлено (в зависимости от символа типа).

d,i,o,u,x,X .n указывает, что по крайней мере n цифр будут выведены. Если входной аргумент имеет менее n цифр, выводимое значение дополняется слева нулями. Если входной аргумент имеет более n цифр, выводимое значение не усекается.
e,E,f .n указывает, что после десятичной точки выводятся n символов, и последняя выводимая цифра округляется.
g,G .n указывает, что выводится не более n значащих цифр.
c .n не влияет на выводимое поле.
s .n указывает, что выводится не более n символов.

o * Значение спецификатора точности содержится в списке аргументов и предшествует форматируемому аргументу.

o . Если явно задана нулевая точность, И спецификатор формата для данного поля относится к цело­численным (т.е., d,i,o,u,x), И значение, кото­рое должно быть выведено, равно 0, — ни одной цифры не будет выведено в это поле (т.е. поле будет заполнено пробелами).

· необязательный модификатор длины аргумента, [F|N|h|l|L] — Изменяет принимаемое по умолчанию значение длины аргумента влияют на то, как функции семейства . printf интерпретируют тип данных соответствующего ар­гумента arg. F и N применяются только к аргу­ментам, которые являются указателями (%p, %s и %n). h, l, и L применяются к числовым аргумен­там (целым и с плавающей точкой).:

o N = near pointer. Изменяют интерпретацию arg. Обычно длина arg для преобразований %p, %s или %n соот­ветствует принимаемой по умолчанию для указате­лей в используемой модели памяти. N требует: «Интерпретировать arg как ближний ука­затель».

o F = far pointer. изменяют интерпретацию arg. Обычно длина arg для преобразований %p, %s или %n соот­ветствует принимаемой по умолчанию для указате­лей в используемой модели памяти. F требует: «Интерпретировать arg как дальний указатель».

o h = short int. Замещает установленную по умолчанию длину числовых аргументов: приме­няется только к целым типам, не вли­яют на символьные типы (c,s) или на указатели (p,n).

o l = long. Замещает установленную по умолчанию длину числовых аргументов: l применяется к целым типам (d,i,o,u,x,X) и типам с плавающей точкой (e,E,f,g и G), не вли­яют на символьные типы (c,s) или на указатели (p,n).

o L = long double. Замещает установленную по умолчанию длину числовых аргументов: применяется к целым типам (d,i,o,u,x,X) и типам с плавающей точкой (e,E,f,g и G).

Модификатор длины аргумента Как интерпретируется arg
F arg интерпретируется как дальний указатель.
N arg интерпретируется как ближний указатель. N не может быть использовано ни для каких преобразований в модели памяти huge.
h arg интерпретируется как short int для d, i, o, u, x или X
l arg интерпретируется как long int для d, i, o, u, x или X; arg интерпретируется как double для e, E, f, g или G.
L arg интерпретируется как long double для e, E, f, g или G.

· type — символ типа преобразования.

Символ типа Входной аргумент Формат вывода
Числовые
d integer Десятичное целое (с учетом знака)
i integer Десятичное целое (с учетом знака)
o integer Беззнаковое восьмерич­ное целое
u integer Беззнаковое десятичное целое
x integer Беззнаковое шестнадца­теричное целое (с цифрами a,b,c,d,e,f)
X integer Беззнаковое шестнадца­теричное целое (с цифрами A,B,C,D,E,F)
f floating-point Значение (с учетом знака) в виде [-]dddd.dddd. где коли­чество цифр после десятичной точки равно значению точности (если задано ненулевое значение точности).
e floating-point Значение (с учетом знака) в виде [-]d.ddd. e[+/-]ddd где одна цифра предшествует десятичной точке; количество цифр после десятичной точки равно значению точности; порядок всегда содержит по крайней мере две цифры
g floating-point Значение (с учетом зна­ка) либо в виде e, либо в виде f, исходя из за­данного значения и точ­ности, причем значение точности определя­ет количество значащих цифр. Незначащие нули и десятичная точка вы­водятся, только если это необходимо. Формат е используется, только если порядок результата преобразова­ния превышает значение точности или меньше -4.
E floating-point То же, что и е, но для экспоненты используется символ E
G floating-point То же, что и g, но для экспоненты используется символ E, если выводит­ся формат e
Символьные
c Character Одиночный символ
s Указатель на строку Символы выводятся, пока не встретится нуль-сим­вол (\0) или пока не будет выведено макси­мальное число символов (значение спецификатора точности)
% нет Выводится символ %
Указатели
n Указатель на int Записывыает (по адресу, на который указывает аргумент) счетчик выведенных ранее символов
p pointer Выводит аргумент в виде указателя. Формат зави­сит от используемой мо­дели памяти: XXXX:YYYY или YYYY (только смеще­ние)

. Бесконечные числа с плавающей точкой выводятся как +INF и -INF. Не-Число (в смысле IEEE) выводится как +NAN или -NAN.

Следующая таблица демонстрирует влияние задания различных спецификаций на печать «HELLO, WORLD» (12 символов). Мы по­местили двоеточия вокруг каждого поля для того, чтобы вы могли видеть его протяженность.

:%10s: :HELLO, WORLD:

:%10-s: :HELLO, WORLD:

:%20s: : HELLO, WORLD:

:%-20s: :HELLO, WORLD :

:%20.10s: : HELLO, WOR:

:%-20.10s: :HELLO, WOR :

Предостережение: printf использует свой первый аргумент для определения числа последующих аргументов и их типов. Ес­ли количество аргументов окажется недостаточным или они бу­дут иметь несоответственные типы, то возникнет путаница и вы получите бессмысленные результаты.

Функция возвращает количество выведенных символов или EOF в случае ошибки.

Форматирование вывода с помощью printf: усечение или отступы

Я хотел бы создать следующий вывод:

Как вы можете видеть, имена короче 14 символов заполняются пробелами. Имена длиной более 15 символов усекаются: «Yutte Schimmelpenninck» обрезает «Yutte Schim. «.

Вот что я пытался достичь этого (переменные $name , $height и $weight извлекаются из файлов, а цикл запускает команду printf для каждого файла):

A printf однострочный слой является искомым решением.

Какой код выдает первый блок вывода?

Перед вашей командой printf вы хотите проверить, превышает ли имя более 14 символов, и если да, усечь его и заменить последние три символа точками. Эта команда делает это:

Он заменяет name своими первыми одиннадцатью символами и добавляет . .

Вы также должны исправить строку формата printf : вместо

или вы получите результаты, такие как

Возможно, это была только опечатка, так как в вашем примере вывода не было дефиса.

Итак, если вы прочитаете это из файла, например, запятой, вы получите такой цикл:

в результате чего

Я не думаю, что это возможно в однострочном лайнере. Я экспериментировал с тернарным оператором и пробовал что-то вроде

но проблема заключается в том, что он работает только для целых чисел, а строки в арифметическом контексте расширяются до нуля.

Илон Маск рекомендует:  Что такое код loadresource
Понравилась статья? Поделиться с друзьями:
Кодинг, CSS и SQL