![](/user_photo/_userpic.png)
книги / Программирование на языке Си
..pdf342 |
Программирование на языке Си |
•Если этот флаг используется с форматами "о", "х” или "X", то любое ненулевое значение выводится с предшествующим 0, Ох или ОХ соответственно. При использовании флага # с форматами " f, "g", "G" десятичная точка будет выводиться, даже если в числе нет дробной части.
Примеры использования флагов:
"%+d" - вывод знака '+' перед положительным целым де- L сятичным числом;
"% d" - добавление (вставка) пробела на месте знака пе ред положительным числом (использован флаг пробел после символа %);
"%#о" - печать ведущих нулей в изображениях восьме ричных чисел.
Ширина поля, задаваемая в спецификации преобразования положительным целым числом, определяет минимальное коли чество позиций, отводимое для представления выводимого зна чения. Если число символов в выводимом значении меньше, чем ширинаполя, выводимое значение дополняется пробелами до заданной минимальной длины. Если ширина поля задана с на чальным нулем, не занятые значащими цифрами выводимого значения позиции слева заполняются нулями.
Если число символов в изображении выводимого значения больше, чем определено в ширине_поля, или ширина поля не задана, печатаются все символы выводимого значения.
Точность указывается с помощью точки и необязательной последовательности десятичных цифр (отсутствие цифр эквива лентно 0).
Точность задает:
•минимальное число цифр, которые могут быть выведены при использовании спецификаторов d, i, о, и, х и л и X;
•число цифр, которые будут выведены после десятичной точки при спецификаторах е, Е и f;
•максимальное число значащих цифр при спецификаторах g и G;
Глава 7. Ввод и вывод |
343 |
•максимальное число символов, которые будут выведены при спецификаторе s.
Непосредственно за точностью может быть указан модифи катор, который определяет тип ожидаемого аргумента и зада ется следующими символами:
h- указывает, что следующий после h спецификатор d, i, о, х или X применяется к аргументу типа short или unsigned short;
I - указывает, что следующий после I спецификатор d, i, о, х или X применяется к аргументу типа long или unsigned long;
L- указывает, что следующий после L спецификатор е, Е, f, g или G применяется к аргументу типа long double.
Прим еры указания ширины поля и точности:
%d |
- |
вывод десятичного целого в поле, достаточном |
|
|
для представления всех его цифр и знака; |
%7d |
- |
вывод десятичного целого в поле из 7 позиций; |
%f |
- |
вывод вещественного числа с целой и дробной |
|
|
частями (выравнивание по правому краю; количе |
|
|
ство цифр в дробной части определяется реализа |
|
|
цией и обычно равно 6); |
%7f |
- вывод вещественного числа в поле из 7 позиций; |
|
%.3f |
|
вывод вещественного числа с тремя цифрами по |
|
|
сле десятичной точки; |
°/o7.3f |
|
вывод вещественного числа в поле из 7 позиций и |
|
|
тремя цифрами после десятичной точки; |
%.0f вывод вещественного числа без десятичной точки
ибез дробной части;
%15s печать в выводимой строке не менее 15 символов; %.12s печать строки длиной не более 12 символов
("лишние" символы не выводятся);
%12.12s печать всегда в поле из 12 позиций, причем лиш ние символы не выводятся, используется всегда 12 позиций. Таким образом, точное количество вы водимых символов можно контролировать, зада-
344 |
Программирование на языке Си |
|
вая и ширину поля, и точность (максимальное |
|
количество символов); |
% -15s |
- выравнивание выводимой строки по левому краю; |
%08f - вывод вещественного числа в поле из 8 позиций. Не занятые значащими цифрами позиции запол няются нулями.
Функция форматного вывода printf() предоставляет множе ство возможностей по форматированию выводимых данных, однако наибольший интерес представляют построение столбцов данных и их выравнивание по левому или правому краю задан ного поля.
В программе, приводимой ниже, на экран дисплея выводится список товаров в магазине. В каждой строке в отдельных полях указываются: номер товара (int), код товара (int), наименование товара (строка символов) и цена товара (float).
#include <stdio.h> int main()
{
int |
i ; |
int number[3]={1, 2, 3}; /* Номер товара */ |
|
int |
code[3]={10, 25670, 120}; /* Код товара */ |
/* Наименование товара: */ |
|
char |
design[3][30]={{"лампа"}, {"стол"}, |
|
{"очень большое кресло"}}; |
|
/* Цена: */ |
|
240.000, |
824.000}; |
|
|
float price[3]={52.700, |
||||
|
'for (i=0; |
i<=2; |
i++) |
|
|
|
printf("%-3d %5d %-20s %8.3f\n", |
||||
|
number[i], |
code[i], |
design[i], price[i]); |
||
} |
return 0; |
|
|
|
|
|
|
|
|
|
|
Результат выполнения программы: |
|
||||
1 |
10 |
лампа |
|
|
52.700 |
2 |
25670 |
стол |
большое |
кресло |
240.000 |
3 |
120 |
очень |
824.000 |
Форматная строка в параметрах функции printf() обеспечи вает следующие преобразования выводимых значений:
Глава 7. Ввод и вывод |
345 |
1)переменная number[i] типа int выводится в поле шириной 3 символа и прижимается к левому краю (%-3d);
2)переменная code[i] типа int выводится в поле шириной 5 символов и прижимается (по умолчанию) к правому краю (%5d);
3)строка из массива design[i] выводится в поле шириной 20 символов и прижимается к левому краю (%-20s). Если в данной спецификации преобразования будет указано меньшее, чем 20, количество позиций, то самая длинная строка будет все равно выведена, однако последний стол бец не будет выровнен;
4)переменная price[i] типа float выводится в поле шириной 8 символов, причем после десятичной точки выводятся 3 символа, и выводимое значение прижимается к правому
краю.
Между полями, определенными спецификациями преобразо ваний, выводится столько пробелов, сколько их явно задано в форматной строке между спецификациями преобразования. Та ким образом, добавляя пробелы между спецификациями преоб разования, можно производить форматирование всей выводи мой таблицы.
Напомним, что любые символы, которые появляются в фор матной строке и не входят в спецификации преобразования, ко пируются в выходной поток. Этим обстоятельством можно вос пользоваться для вывода явных разделителей между столбцами таблицы. Например, для этой цели можно использовать символ
или В последнем случае форматная строка в функции printf() будет выглядеть так: "%-3d | %5d | %-20s | %8.3Лп", и результат работы программы будет таким:
1 |
1 |
Ю |
I |
лампа |
| |
52.700 |
2 |
| 25670 |
| |
стол |
| |
240.000 |
|
3 |
1 |
120 |
| |
очень большое кресло |
| |
824.000 |
Форматный ввод из входного потока. Форматный ввод из входного потока осуществляется функцией scanf(). Прототип функции scanf() имеет вид:
346 |
Программирование на языке Си |
int scanf(const char * form at,. . .);
При обращении к функции scanf() возможны две формы за дания первого параметра:
int scanf ( форматная строка, список аргументов ); int scanf ( указатель на форматную_строку,
список аргументов)',
Функция scanf() читает последовательности кодов символов (байты) из входного потока и интерпретирует их в соответствии с форматной строкой как целые числа, вещественные числа, одиночные символы, строки. В первом варианте вызова функ ции форматная строка размещается непосредственно в списке фактических параметров. Во втором варианте вызова предпола гается, что первый фактический параметр - это указатель типа char *, адресующий собственно форматную строку. Форматная строка в этом случае должна быть определена в программе как обычная строковая константа или переменная.
После преобразования во внутреннее представление данные записываются в области памяти, определенные аргументами, которые следуют за форматной строкой. Каждый аргумент дол жен быть указателем на переменную, в которую будет записа но очередное значение данных и тип которой соответствует типу, указанному в спецификации преобразования из формат ной строки.
Если аргументов недостаточно для данной форматной стро ки, то результат зависит от реализации (от операционной систе мы и от системы программирования). Если аргументов больше, чем требуется в форматной строке, "лишние" аргументы игно рируются.
Последовательность кодов символов, которую функция scanf() читает из входного потока, как правило, состоит из по лей (строк), разделенных символами промежутка или обобщен ными пробельными символами. Поля просматриваются и вво дятся функцией scanf() посимвольно. Ввод поля прекращается, если встретился пробельный символ или в спецификации
Глава 7. Ввод и вывод |
347 |
преобразования точно указано количество вводимых символов (см. ниже).
Функция scanf( ) завершает работу, если исчерпана формат ная строка. При успешном завершении scanf( ) возвращает ко личество преобразованных и введенных полей (точнее, количество объектов, получивших значения при вводе). Значе ние EOF возвращается при возникновении ситуации "конец файла"; значение -1 - при возникновении ошибки преобразова ния данных.
Форматная строка ограничена двойными кавычками и мо жет включать: I
•пробельные символы, отслеживающие разделение входно го потока на поля. Пробельный символ указывает на то, что из входного потока надо считывать, но не сохранять все последовательные пробельные символы вплоть до появле ния непробельного символа. Один пробельный символ в форматной строке соответствует любому количеству по следовательных пробельных символов во входном потоке;
•обычные символы, отличные от пробельных и символа '%'. Обработка обычного символа из форматной строки сводит ся к чтению очередного символа из входного потока. Если прочитанный символ отличается от обрабатываемого сим вола форматной строки, функция завершается с ошибкой. Несовпавший символ и следующие за ним входные симво лы остаются непрочитанными;
•спецификации преобразования.
Спецификация преобразования имеет следующую форму:
% * ширина поля модификатор спецификатор
Все символы в спецификации преобразования являются не обязательными, за исключением символа '%', с которого она начинается (он и является признаком спецификации преобразо вания), и спецификатора, позволяющего указать ожидаемый тип элемента во входном потоке (табл. 7.2).
Необязательные элементы спецификации преобразования имеют следующий смысл:
348 |
Программирование на языке Си |
*- звездочка, следующая за символом процента, запрещает запись значения, прочитанного из входного потока по адресу, задаваемому аргументом. Последовательность кодов из входного потока прочитывается функцией scanfO, но не преобразуется и не записывается в пере менную, определенную очередным аргументом.
Ш иринаполя - положительное десятичное целое, опреде ляющее максимальное число символов, которое может быть прочитано из входного потока. Фактически может быть прочитано меньше символов, если встретится про бельный символ или символ, который не может быть преобразован по заданной спецификации.
Модификатор - позволяет задать длину переменной, в кото рую предполагается поместить вводимое значение. Мо дификатор может принимать следующие значения:
L - означает, что соответствующий спецификации пре образования аргумент должен указывать на объект типа long double;
I - означает, что аргумент должен быть указателем на переменную типа long, unsigned long или double;
h - означает, что аргумент должен быть указателем на тип short.
Приведем примеры ввода данных из входного потока с по мощью функции scanf().
Предположим, что необходимо ввести со стандартного ввода следующие данные: десятичное число, одиночный символ и строку. Пусть во входном потоке присутствует дополнительная информация, необходимая для пояснения или идентификации вводимых данных. Например, вводимые данные могут иметь такой формат:
code: цифра строка1 символ строка2
Набранные жирным шрифтом элементы (цифра, символ и строка2) должны быть введены в программу, а элементы, на бранные курсивом, будут использоваться для контроля (code:) и комментария (строка!).
Глава 7. Ввод и вывод |
349 |
||
|
|
Таблица 7.2 |
|
Спецификаторы форматной строки для функции форматного ввода |
|||
Спе |
Ожидаемый тип вводимых данных |
Тип |
|
цифи |
|||
аргумента |
|||
катор |
|
||
|
|
||
d |
Десятичное целое |
int * |
|
о |
Восьмеричное целое |
int * |
|
X |
Шестнадцатеричное целое |
int * |
iДесятичное, восьмеричное или шестнадцате int * ричное целое
350 |
Программирование на языке Си |
Контроль заключается в том, что во входном потоке должна присутствовать именно строка "code:" (без кавычек). Строка строка1 используется для комментирования вводимых данных, может иметь произвольную длину и пропускается при вводе. Отметим, что строка 1 и строка2 не должны содержать внутри себя пробелов. Текст программы приводится ниже:
#inciude <stdio.h> int main()
{
int i ;
int ret; /* Код возврата функции scanf() */ char c, is[80];
ret=scanf("code: %d %*s %c %s", &i, &c, s) ; printf("\n i=%d c=%c s=%s", i, c, s); printf("\n \t ret = %d\n", ret);
return 0;
>
Рассмотрим форматную строку функции scanf():
"code: %d %*s %c %s"
Строка "code:" присутствует во входном потоке для контроля вводимых данных и поэтому указана в форматной строке. Спе цификации преобразования задают следующие действия:
%d |
- ввод десятичного целого; |
%*s |
- пропуск строки (строка] в приведенной выше форме |
ввода); |
|
%с |
- ввод одиночного символа; |
%s |
- ввод строки. |
Приведем результаты работы программы для трех различных наборов входных данных.
1. Последовательность символов исходных данных:
code: 5 поле2 D asd
Результат выполнения программы:
i=5 c=D s=asd
ret=3
Глава 7.Ввод и вывод |
351 |
Значением переменной ret является код возврата функции scanf(). Число 3 говорит о том, что функция scanf() ввела данные без ошибки и было обработано 3 входных поля (строки "code:" и "поле2" пропускаются при вводе).
2. Последовательность символов исходных данных:
code: 5 D asd
Результат выполнения программы:
i=5 с=а s=sd ret=3
Обратите внимание на то, что во входных данных пропу щена строка перед символом D, использующаяся как ком ментарий. В результате символ D из входного потока был (в соответствии с форматной строкой) пропущен, а из строки "asd" в соответствии с требованием спецификации преобразования %с был введен символ 'а' в переменную с. Остаток строки "^sd" (sd) был введен в массив символов s. Код возврата (ret=3) функции scanf() говорит о том, что функция завершила свою работу без ошибок и обработала
3поля.
3.Последовательность символов исходных данных: cod: 5 поле2 D asd
Результат выполнения программы:
i=40 с= s= ) ret=0
Вместо предусмотренной в форматной строке последова тельности символов в данных входного потока допущена ошиб ка (набрано слово cod: вместо code:). Функция scanf() завершается аварийно (код возврата равен 0). Функция printf() в качестве результата напечатала случайные значения перемен ных i, с и s ("мусор").
Необходимо иметь в виду, что функция scanf(), обнаружив какую-либо ошибку при преобразовании данных входного по тока, завершает свою работу, а необработанные данные остают