Многогранная функция printf()

Функции puts() и putchar() используются довольно часто, но, к сожалению, их возможности несколько ограничены. Ни одна из них не может обеспечить вывод числовых данных, и обе они имеют только один аргумент (параметр). Это означает, что обе функции могут отобразить только один объект.

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

В простейшем случае функцию printf() можно использовать вместо функции puts() для вывода строки:

#define MESSAGE "Привет!"main(){printf(MESSAGE);printf("Добро пожаловать в мой мир, а теперь убирайся");}

Так же как и puts(), функция printf() будет выводить на экран строки, заключенные в кавычки, и значения строковых констант и переменных.

Многогранная функция printf() - student2.ru
Си++ имеет дополнительное многоцелевое средство вывода cout. Вывод в Си++ рассматривается далее в этой главе.

Вывод чисел

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

Многогранная функция printf() - student2.ru
Рис. 4.5. Две части списка параметров функции printf()

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

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

%d целое число
%u беззнаковое целое число
%f вещественное число типа float или double
%e вещественное число в экспоненциальной форме
%g вещественное число, отображаемое по формату %f или %e, в зависимости от того, какая форма записи является более короткой
%c символ
%s строка

Таким образом, первая часть инструкции printf() записывается так:

printf("%d")

Знак процента говорит компилятору, что за ним последует указатель формата (чтобы отобразить сам символ процента, напишите его дважды: printf("%%");).

Буква d указывает компилятору, что следует отобразить целое число, записанное в десятичной системе счисления (рис.4.6).

____________________

* Буквальный перевод английских терминов control string или format string. (Прим.перев.)

** В оригинале format specifier. (Прим.перев.)

Многогранная функция printf() - student2.ru
Рис. 4.6. Составляющие указателя формата

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

Простейший пример использования функции printf() приведен ниже:

printf("%d", 12);

В процессе выполнения этой инструкции значение 12 будет подставлено на место указателя формата (рис.4.7). В нашем примере мы на самом деле передали

Многогранная функция printf() - student2.ru
Рис. 4.7. Значение подставляется на место указателя формата

библиотечной функции printf() два параметра: строку формата и числовой литерал12.

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

printf("Мне исполнилось %d лет", 12);

Многогранная функция printf() - student2.ru
Рис. 4.8. Использование указателя формата внутри строкового литерала

Строкой формата в этом примере является запись

"Мне исполнилось %d лет"

Указатель формата, %d, говорит о том, что мы хотим вставить число между словами "Мне исполнилось" и словом "лет" (рис.4.8). Когда компилятор подставит число12 на место указателя формата, мы увидим следующую фразу:

Мне исполнилось 12 лет

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

В данном случае тот же результат можно получить, передавая всю фразу целиком, как параметр, одной из функций:

printf("Мне исполнилось 12 лет"); puts("Мне исполнилось 12 лет");

Но чтобы комбинировать текст с числовыми константами или переменными, следует использовать именно функцию printf() и указатели формата, как, например, в программе:

main() { int age; age = 12; printf("Мне исполнилось %d лет", age); }

Эта программа отображает на экране строковый литерал и значение целочисленной переменной с помощью одной инструкции (рис.4.9).

Многогранная функция printf() - student2.ru
Рис. 4.9. Значение переменной подставляется на место указателя формата

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

main(){int lucky_1, lucky_2;lucky_1 = 12;lucky_2 = 21;printf("Моими счастливыми номерами являются \ %d и %d", lucky_1, lucky_2);}

Здесь мы определили две целочисленные переменные lucky_1 и lucky_2 и присвоили им начальные значения. Список данных функции printf() содержит два имени переменных (аргумента), которые мы хотим отобразить, так что строка формата тоже должна иметь два указателя формата. Так как обе переменные относятся к типу int, оба указателя формата одинаковы — %d, как показано на рис.4.10.

Многогранная функция printf() - student2.ru
Рис. 4.10. Использование двух указателей формата

Компилятор подставит значения на место указателей формата, и фраза будет выглядеть так:

Моими счастливыми номерами являются 12 и 21

Значение переменной lucky_1, первого пункта в списке данных, займет место первого указателя формата, а второй пункт списка данных (значение переменной lucky_2) будет подставлен на место второго указателя. Если пункты в списке данных поменять местами:

printf("Моими счастливыми номерами являются \ %d и %d", lucky_2, lucky_1);

то значения отобразятся в таком порядке:

Моими счастливыми номерами являются 21 и 12

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

main(){int count;float amount;count = 5;amount = 45.48;printf("Стоимость составляет %f за %d штук", amount, count);}

Первое значение из списка данных — число с плавающей точкой — подставляется на место первого указателя формата %f. Второе значение — целое число — подставляется на место второго указателя формата %d. Программа компилируется и выполняется без ошибок, так как типы переменных и указателей формата совпадают. Как показано на рис.4.11, значение типа float замещает указатель %f, а значение типа int — указатель %d. В результате имеем:

Стоимость составляет 45.580000 за 5 штук

Многогранная функция printf() - student2.ru
Рис. 4.11. Тип данных должен соответствовать указателю формата

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

printf("Стоимость составляет \ %f за %d штук", count, amount);

компилятор может не сообщить об ошибке, но в результате появится бессмысленная запись:

Стоимость составляет -2.002149Е37 за 16454 штук

К такому результату привело несоответствие типов числовых данных и указателей формата. При вызове функции printf() можно использовать несколько аргументов различных типов, но только при строгом соответствии типов данных и указателей формата.

Перевод строки

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

Если вы хотите перевести курсор на следующую строку, вы должны добавить в строку формата управляющий код «новая строка» \n:

printf("Стоимость составляет %f за %d штук\n", amount, count);

Управляющий код \n помещают там, где хотят начать новую строку (не обязательно в конце строки формата), например, в результате выполнения инструкции

printf("Стоимость составляет %f\n за %d штук\n", amount, count);

на экране появятся две строки:

Стоимость составляет 45.580000 за 5 штук иСтоимость составляет 45.580000 за 5 штук

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

Преобразование типов данных

В Си существует два дополнительных указателя формата, с помощью которых можно переводить данные типа int из десятичной в восьмеричную и шестнадцатеричную системы счисления:

%o перевод в восьмеричную систему, используйте только маленькую букву о, не цифру 0
%x перевод в шестнадцатеричную систему

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

main() {printf("%d равно %x в шестнадцатеричной и %o в \ восьмеричной системах счисления\n", 17, 17, 17); // так в Си и Си++ можно переносить // длинные строки символов, // заключенные в двойные кавычки (ред.) }

Результат работы программы выглядит следующим образом:

17 равно 11 в шестнадцатеричной и 21 в восьмеричной системах счисления

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

Двойственность символьных переменных

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

main() { int a; a = 'A'; putchar(a); putchar('\n'); printf("%c", a); }

При выполнении этой программы символ А появится дважды: один раз как символ, отображенный функцией putchar(), второй раз как символ, отображенный функцией printf() с использованием указателя формата %c. Независимо от того, определен тип переменной как char или int, можно преобразовать символ в его ASCII-код:

main() { char a; a = 'A'; printf("ASCII-код символа %c равен %d", a, a); }

В этом примере одно и то же значение переменной выводится на дисплей с использованием указателей формата %c и %d. В результате получаем следующее сообщение:

ASCII-код символа А равен 65

где присутствует символ А, отображенный с использованием указателя формата %c, и число 65, являющееся ASCII-кодом символа А, выведенное с помощью указателя формата %d.

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

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

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

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

printf("Стоимость составляет %f за %d штук", amount, count);

и появляется строка:

Стоимость составляет 45.580000 за 5 штук

В зависимости от особенностей системы и от того, как ведется расчет среднего значения, может появиться и что-нибудь в таком роде:

Стоимость составляет 45.579998 за 5 штук

Многогранная функция printf() - student2.ru
Рис. 4.12. Определение количества знаков после точки

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

Чтобы определить число знаков после точки, используется указатель %.nf, где число n определяет количество знаков (рис.4.12). Например, если написать:

printf("Стоимость составляет %.2f", amount);

то при выводе значения переменной с типом float оно будет иметь только два знака после точки:

Стоимость составляет 45.58

Сходным образом, если написать:

printf("Стоимость составляет %.3f", amount);

значение переменной будет представлено с тремя знаками после точки:

Стоимость составляет 45.580____________________

* Буквальный перевод английского термина field-width specifiers. (Прим.перев.)

На рис.4.13 приведено несколько примеров определения количества знаков в десятичной части переменной.

Многогранная функция printf() - student2.ru
Рис. 4.13. Примеры определения количества знаков в десятичной части

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

%N.nf

где N — это общая ширина поля.

Если задать инструкцию

printf("Стоимость составляет %8.2f", amount);

появится строка

Стоимость составляет 45.58

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

Многогранная функция printf() - student2.ru
Рис. 4.14. Указатель ширины поля определяет количество пробелов на экране

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

printf("Стоимость составляет %2.2f", amount);

приведет к появлению сообщения

Стоимость составляет 45.58

Можно также добавить лишнее пространство перед числом, но заполнить его нулями вместо пробелов, как на рис.4.15. Для этого перед числом, определяющим ширину поля, надо поставить символ 0:

Многогранная функция printf() - student2.ru
Рис. 4.15. Вывод нулей перед числом

printf("Стоимость составляет %08.2f", amount);

в результате мы увидим сообщение

Стоимость составляет 00045.58

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

%-8.2f

Лишние пробелы в этом случае появятся после выведенного значения. Инструкция

printf("Стоимость составляет %-8.2f в долларах США", amount);

выводит на экран сообщение

Стоимость составляет 45.58 в долларах США

Как показано на рис. 4.16, число 45.58 опять как бы помещается в «коробочку» из восьми символов, но теперь уже сдвигается к левому краю, а пустое пространство появляется за числом.

Указатель ширины поля может работать как с символьными, так и со строковыми данными. Дополнительные пробелы помещаются перед текстом, сдвигая строку к правому краю воображаемой «коробочки». Например, если строковая переменная, называемая message, имеет значение «Привет», то инструкция

Многогранная функция printf() - student2.ru
Рис. 4.16. Выравнивание по левому краю

printf("Я позвонил, чтобы сказать %8s", message);

отобразит на экране следующую строку

Я позвонил, чтобы сказать Привет

Как показано на рис. 4.17, при выводе значения строковой переменной message

Многогранная функция printf() - student2.ru
Рис. 4.17. Использование указателя ширины поля при выводе строки

перед ним появятся два дополнительных пробела.

Наши рекомендации