Смекни!
smekni.com

помещающей символ 'с' в “стандартный ввод”, который по умол-

чанию является терминалом. Вывод можно направить в некоторый

файл с помощью обозначения > : если PROG использует PUTCHAR,

то командная строка

PROG>OUTFILE

приведет к записи стандартного вывода в файл OUTFILE, а не

на терминал. На системе UNIX можно также использовать поточ-

ный механизм. Строка

PROG \! ANOTHERPROG

помещает стандартный вывод PROG в стандартный ввод ANOTHERPROG. И опять PROG не будет осведомлена об изменении направления.

Вывод, осуществляемый функцией PRINTF, также поступает в

стандартный вывод, и обращения к PUTCHAR и PRINTF могут пе-

ремежаться.

Поразительное количество программ читает только из одно-

го входного потока и пишет только в один выходной поток; для

таких программ ввод и вывод с помощью функций GETCHAR,

PUTCHAR и PRINTF может оказаться вполне адекватным и для на-

чала определенно достаточным. Это особенно справедливо тог-

· 154 -

да, когда имеется возможность указания файлов для ввода и

вывода и поточный механизм для связи вывода одной программы

с вводом другой. Рассмотрим, например, программу LOWER, ко-

торая преобразует прописные буквы из своего ввода в строч-

ные:

#INCLUDE <STDIO.H>

MAIN() /* CONVERT INPUT TO LOWER CASE */

&bsol;(

INT C;

WHILE ((C = GETCHAR()) != EOF)

PUTCHAR(ISUPPER© ? TOLOWER© : C);

&bsol;)

“Функции” ISUPPER и TOLOWER на самом деле являются макроса-

ми, определенными в STDIO.H . Макрос ISUPPER проверяет, яв-

ляется ли его аргумент буквой из верхнего регистра, и возв-

ращает ненулевое значение, если это так, и нуль в противном

случае. Макрос TOLOWER преобразует букву из верхнего регист-

ра в ту же букву нижнего регистра. Независимо от того, как

эти функции реализованы на конкретной машине, их внешнее по-

ведение совершенно одинаково, так что использующие их прог-

раммы избавлены от знания символьного набора.

Если требуется преобразовать несколько файлов, то можно

собрать эти файлы с помощью программы, подобной утилите CAT

системы UNIX,

CAT FILE1 FILE2 ... &bsol;! LOWER>OUTPUT

и избежать тем самым вопроса о том, как обратиться к этим

файлам из программы. (Программа CAT приводится позже в этой

главе).

Кроме того отметим, что в стандартной библиотеке вво-

да/вывода “функции” GETCHAR и PUTCHAR на самом деле могут

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

обращение к функции для обработки каждого символа. В главе 8

мы продемонстрируем, как это делается.

7.3. Форматный вывод - функция PRINTF

Две функции: PRINTF для вывода и SCANF для ввода (следу-

ющий раздел) позволяют преобразовывать численные величины в

символьное представлEние и обратно. Они также позволяют ге-

нерировать и интерпретировать форматные строки. Мы уже всюду

в предыдущих главах неформально использовали функцию PRINTF;

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

PRINTF(CONTROL, ARG1, ARG2, ...)

·
155 -

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

стандартный вывод под управлением строки CONTROL. Управляю-

щая строка содержит два типа объектов: обычные символы, ко-

торые просто копируются в выходной поток, и спецификации

преобразований, каждая из которых вызывает преобразование и

печать очередного аргумента PRINTF.

Каждая спецификация преобразования начинается с символа

% и заканчивается символом преобразования. Между % и симво-

лом преобразования могут находиться:

· знак минус, который указывает о выравнивании преобразован-

ного аргумента по левому краю его поля.

· Строка цифр, задающая минимальную ширину поля. Преобразо-

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

ширины, а если необходимо, то и в более широком. Если пре-

образованный аргумент имеет меньше символов, чем указанная

ширина поля, то он будет дополнен слева (или справа, если

было указано выравнивание по левому краю)заполняющими сим-

волами до этой ширины. Заполняющим символом обычно являет-

ся пробел, а если ширина поля указывается с лидирующим ну-

лем, то этим символом будет нуль (лидирующий нуль в данном

случае не означает восьмеричной ширины поля).

· Точка, которая отделяет ширину поля от следующей строки

цифр.

· Строка цифр (точность), которая указывает максимальное

число символов строки, которые должны быть напечатаны, или

число печатаемых справа от десятичной точки цифр для пере-

менных типа FLOAT или DOUBLE.

· Модификатор длины L, который указывает, что соответствую-

щий элемент данных имеет тип LONG, а не INT.

Ниже приводятся символы преобразования и их смысл:

D - аргумент преобразуется к десятичному виду.

O - Аргумент преобразуется в беззнаковую восьмеричную форму

(без лидирующего нуля).

X - Аргумент преобразуется в беззнаковую шестнадцатеричную

форму (без лидирующих 0X).

U - Аргумент преобразуется в беззнаковую десятичную форму.

C - Аргумент рассматривается как отдельный символ.

S - Аргумент является строкой: символы строки печатаются до

тех пор, пока не будет достигнут нулевой символ или не бу-

дет напечатано количество символов, указанное в специфика-

ции точности.

E - Аргумент, рассматриваемый как переменная типа FLOAT или

DOUBLE, преобразуется в десятичную форму в виде

[-]M.NNNNNNE[+-]XX, где длина строки из N определяется

указанной точностью. Точность по умолчанию равна 6.

F - Аргумент, рассматриваемый как переменная типа FLOAT или

DOUBLE, преобразуется в десятичную форму в виде

[-]MMM.NNNNN, где длина строки из N определяется указанной

точностью. Точность по умолчанию равна 6. отметим, что эта

точность не определяет количество печатаемых в формате F

значащих цифр.

· 156 -

G - Используется или формат %E или %F, какой короче; незна-

чащие нули не печатаются.

Если идущий за % символ не является символом преобразования,

то печатается сам этот символ; следовательно,символ % можно

напечатать, указав %%.

Большинство из форматных преобразований очевидно и было

проиллюстрировано в предыдущих главах. Единственным исключе-

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

Следующая таблица демонстрирует влияние задания различных

спецификаций на печать “HELLO, WORLD” (12 символов). Мы по-

местили двоеточия вокруг каждого поля для того, чтобы вы

могли видеть его протяженность.

:%10S: :HELLO, WORLD:

:%10-S: :HELLO, WORLD:

:%20S: : HELLO, WORLD:

:%-20S: :HELLO, WORLD :

:%20.10S: : HELLO, WOR:

:%-20.10S: :HELLO, WOR :

:%.10S: :HELLO, WOR:

Предостережение: PRINTF использует свой первый аргумент

для определения числа последующих аргументов и их типов. Ес-

ли количество аргументов окажется недостаточным или они бу-

дут иметь несоответственные типы, то возникнет путаница и вы

получите бессмысленные результаты.

Упражнение 7-1.

Напишите программу, которая будет печатать разумным об-

разом произвольный ввод. Как минимум она должна печатать

неграфические символы в восьмеричном или шестнадцатеричном

виде (в соответствии с принятыми у вас обычаями) и склады-

вать длинные строки.

7.4. Форматный ввод - функция SCANF

Осуществляющая ввод функция SCANF является аналогом

PRINTF и позволяет проводить в обратном направлении многие

из тех же самых преобразований. Функция

SCANF(CONTROL, ARG1, ARG2, ...)

читает символы из стандартного ввода, интерпретирует их в

соответствии с форматом, указанном в аргументе CONTROL, и

помещает результаты в остальные аргументы. Управляющий аргу-

мент описывается ниже; другие аргументы, каждый из которых

должен быть указателем, определяют, куда следует поместить

соответствующим образом преобразованный ввод.

Управляющая строка обычно содержит спецификации преобра-

зования, которые используются для непосредственной интерпре-

тации входных последовательностей. Управляющая строка может

содержать:

· пробелы, табуляции или символы новой строки (“символы пус-

тых промежутков”), которые игнорируются.

·
157 -

· Обычные символы (не %), которые предполагаются совпадающи-

ми со следующими отличными от символов пустых промежутков

символами входного потока.

· Спецификации преобразования, состоящие из символа %, нео-

бязательного символа подавления присваивания *, необяза-

тельного числа, задающего максимальную ширину поля и сим-

вола преобразования.

Спецификация преобразования управляет преобразованием

следующего поля ввода. нормально результат помещается в пе-

ременную, которая указывается соответствующим аргументом.

Если, однако , с помощью символа * указано подавление прис-

ваивания, то это поле ввода просто пропускается и никакого

присваивания не производится. Поле ввода определяется как

строка символов, которые отличны от символов простых проме-

жутков; оно продолжается либо до следующего символа пустого

промежутка, либо пока не будет исчерпана ширина поля, если

она указана. Отсюда следует, что при поиске нужного ей вво-

да, функция SCANF будет пересекать границы строк, поскольку

символ новой строки входит в число пустых промежутков.

Символ преобразования определяет интерпретацию поля вво-

да; согласно требованиям основанной на вызове по значению

семантики языка “с” соответствующий аргумент должен быть

указателем. Допускаются следующие символы преобразования:

D - на вводе ожидается десятичное целое; соответствующий ар-

гумент должен быть указателем на целое.

O - На вводе ожидается восьмеричное целое (с лидирующим ну-

лем или без него); соответствующий аргумент должен быть

указателем на целое.

X - На вводе ожидается шестнадцатеричное целое (с лидирующи-

ми 0X или без них); соответствующий аргумент должен быть

указателем на целое.

H - На вводе ожидается целое типа SHORT; соответсвующий ар-

гумент должен быть указателем на целое типа SHORT.

C - Ожидается отдельный символ; соответствующий аргумент