Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Керниган, Ричи. Язык C.docx
Скачиваний:
5
Добавлен:
05.05.2019
Размер:
377.71 Кб
Скачать

1.4. Символические константы

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

программу перевода температур. Прятать "магические числа",

такие как 300 и 20, внутрь программы - это неудачная практи-

ка; они дают мало информации тем, кто, возможно, должен бу-

дет разбираться в этой программе позднее, и их трудно изме-

нять систематическим образом. К счастью в языке "C" предус-

мотрен способ, позволяющий избежать таких "магических чи-

сел". Используя конструкцию #DEFINE , вы можете в начале

программы определить символическое имя или символическую

константу, которая будет конкретной строкой символов. Впос-

ледствии компилятор заменит все не заключенные в кавычки по-

явления этого имени на соответствующую строку. Фактически

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

не обязательно цифрами

#DEFINE LOWER 0/* LOWER LIMIT OF TABLE */

#DEFINE UPPER 300 /* UPPER LIMIT */

#DEFINE STEP 20 /* STEP SIZE */

MAIN () /* FAHRENHEIT-CELSIUS TABLE */

{

INT FAHR;

FOR (FAHR =LOWER; FAHR <= UPPER; FAHR =FAHR + STEP)

PRINTF("%4D %6.1F\N", FAHR, (5.0/9.0)*(FAHR-32));

}

величины LOWER, UPPER и STEP являются константами и поэ-

тому они не указываются в описаниях. Символические имена

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

чить от написанных строчными буквами имен переменных. отме-

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

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

именем, то это привело бы к слишком большому числу точек с

запятой в операторе FOR .

1.5. Набор полезных программ

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

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

над символьными данными. В дальнейшем вы обнаружите, что

многие программы являются просто расширенными версиями тех

прототипов, которые мы здесь обсуждаем.

1.5.1. Ввод и вывод символов

Стандартная библиотека включает функции для чтения и за-

писи по одному символу за один раз. функция GETCHAR() извле-

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

ются, и возвращает этот символ в качестве своего значения.

Это значит, что после

C = GETCHAR()

переменная 'C' содержит следующий символ из входных данных.

Символы обычно поступают с терминала, но это не должно нас

касаться до главы 7.

Функция PUTCHAR(C) является дополнением к GETCHAR : в

результате обращения

PUTCHAR (C)

содержимое переменной 'C' выдается на некоторый выходной но-

ситель, обычно опять на терминал. Обращение к функциям

PUTCHAR и PRINTF могут перемежаться; выдача будет появляться

в том порядке, в котором происходят обращения.

Как и функция PRINTF , функции GETCHAR и PUTCHAR не со-

держат ничего экстраординарного. Они не входят в состав язы-

ка "C", но к ним всегда можно обратиться.

1.5.2. Копирование файла

Имея в своем распоряжении только функции GETCHAR и

PUTCHAR вы можете, не зная ничего более об операциях вво-

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

рамм. Простейшим примером может служить программа посимволь-

ного копирования вводного файла в выводной. Общая схема име-

ет вид:

ввести символ

WHILE (символ не является признаком конца файла)

вывести только что прочитанный символ

ввести новый символ

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

зом:

MAIN() /* COPY INPUT TO OUTPUT; 1ST VERSION */

{

INT C;

C = GETCHAR();

WHILE (C != EOF) {

PUTCHAR (C);

C = GETCHAR();

}

}

оператор отношения != означает "не равно".

Основная проблема заключается в том, чтобы зафиксиро-

вать конец файла ввода. Обычно, когда функция GETCHAR натал-

кивается на конец файла ввода, она возвращает значение , не

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

может установить, что файл ввода исчерпан. Единственное ос-

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

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

кое значение фактически является признаком конца файла. Мы

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

имя EOF для этого значения, каким бы оно ни было. На практи-

ке EOF будет либо -1, либо 0, так что для правильной работы

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

#DEFINE EOF -1

либо

#DEFINE EOF 0

Использовав символическую константу EOF для представле-

ния значения, возвращаемого функцией GETCHAR при выходе на

конец файла, мы обеспечили, что только одна величина в прог-

рамме зависит от конкретного численного значения.

Мы также описали переменную 'C' как INT , а не CHAR , с

тем чтобы она могла хранить значение, возвращаемое GETCHAR .

как мы увидим в главе 2, эта величина действительно INT, так

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

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

Программистом, имеющим опыт работы на "C", программа

копирования была бы написана более сжато. В языке "C" любое

присваивание, такое как

C = GETCHAR()

может быть использовано в выражении; его значение - просто

значение, присваиваемое левой части. Если присваивание сим-

вола переменной 'C' поместить внутрь проверочной части опе-

ратора WHILE , то программа копирования файла запишется в

виде:

MAIN() /* COPY INPUT TO OUTPUT; 2ND VERSION */

{

INT C;

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

PUTCHAR(C);

}

Программа извлекает символ , присваивает его переменной

'C' и затем проверяет, не является ли этот символ признаком

конца файла. Если нет - выполняется тело оператора WHILE,

выводящее этот символ. Затем цикл WHILE повторяется. когда,

наконец, будет достигнут конец файла ввода, оператор WHILE

завершается, а вместе с ним заканчивается выполнение и функ-

ции MAIN .

В этой версии централизуется ввод - в программе только

одно обращение к функции GETCHAR - и ужимается программа.

Вложение присваивания в проверяемое условие - это одно из

тех мест языка "C", которое приводит к значительному сокра-

щению программ. Однако, на этом пути можно увлечься и начать

писать недоступные для понимания программы. Эту тенденцию мы

будем пытаться сдерживать.

Важно понять , что круглые скобки вокруг присваивания в

условном выражении действительно необходимы. Старшинство

операции != выше, чем операции присваивания =, а это означа-

ет, что в отсутствие круглых скобок проверка условия != бу-

дет выполнена до присваивания =. Таким образом, оператор

C = GETCHAR() != EOF

эквивалентен оператору

C = (GETCHAR() != EOF)

Это, вопреки нашему желанию, приведет к тому, что 'C'

будет принимать значение 0 или 1 в зависимости от того, на-

толкнется или нет GETCHAR на признак конца файла. Подробнее

об этом будет сказано в главе 2/.