Смекни!
smekni.com

Методические указания к выполнению контрольных работ по дисциплине "Основы программирования" (стр. 11 из 40)

Упражнение 2-3. Преобразуйте программу перевода температур таким образом, чтобы она печатала заголовок к таблице.

Упражнение 2-4. Напишите программы печати соответствующей таблицы перехода от градусов Цельсия к градусам Фаренгейта.

2.3. Оператор for

Пример 2-3. Как и можно было ожидать, имеется множество различных способов написания каждой программы. Давайте рассмотрим такой вариант программы перевода температур:

main() // Напечатать таблицу Фаренгейт-Цельсий

{

int fahr;

for (fahr = 0; fahr <= 300; fahr = fahr + 20)

printf("%4d %6.1f&bsol;n",fahr,(5.0/9.0)*(fahr-32.0));

}

Эта программа выдает те же самые результаты, но выглядит безусловно по-другому. Главное изменение – исключение большинства переменных; осталась только переменная fahr , причем типа int (это сделано для того, чтобы продемонстрировать преобразование %d в функции printf). Нижняя и верхняя границы и размер щага появляются только как константы в операторе for , который сам является новой конструкцией, а выражение, вычисляющее температуру по Цельсию, входит теперь в виде третьего аргумента функции printf, а не в виде отдельного оператора присваивания.

Последнее изменение является примером вполне общего правила языка «C» – в любом контексте, в котором допускается использование значения переменной некоторого типа, вы можете использовать выражение этого типа. Так как третий аргумент функции printf должен иметь значение с плавающей точкой, чтобы соответствовать спецификации %6.1f, то в этом месте может встретиться любое выражение плавающего типа.

Сам оператор for - это оператор цикла, обобщающий оператор while. Его функционирование должно стать ясным, если вы сравните его с ранее описанным оператором while . Оператор for содержит три части, разделяемые точкой с запятой. Первая часть:

fahr = 0

выполняется один раз перед входом в сам цикл. Вторая часть – проверка, или условие, которое управляет циклом:

fahr <= 300


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

fahr =fahr + 20 ,

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

Выбор между операторами while и for произволен и основывается на том, что выглядит яснее. Оператор for обычно удобен для циклов, в которых инициализация и реинициализация логически связаны и каждая задается одним оператором, так как в этом случае запись более компактна, чем при использовании оператора while , а операторы управления циклом сосредотачиваются вместе в одном месте.

Упражнение 2-5. Модифицируйте программу перевода температур таким образом, чтобы она печатала таблицу в обратном порядке, т.е. От 300 градусов до 0.

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

Последнее замечание, прежде чем мы навсегда оставим программу перевода температур. Прятать «магические числа», такие как 300 и 20, внутрь программы – это неудачная практика; они дают мало информации тем, кто, возможно, должен будет разбираться в этой программе позднее, и их трудно изменять систематическим образом. К счастью в языке «C» предусмотрены два способа, позволяющие избежать таких «магических чисел».

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

#define lower 0 // Нижний предел таблицы

#define upper 300 // Верхний предел таблицы

#define step 20 // Размер шага

main () // Напечатать таблицу Фаренгейт-Цельсий

{

int fahr;

for (fahr =lower; fahr <= upper; fahr =fahr + step)

printf("%4d %6.1f&bsol;n",fahr,(5.0/9.0)*(fahr-32));

}

Величины lower, upper и step являются константами и поэтому они не указываются в описаниях. Символические имена обычно пишут прописными буквами, чтобы их было легко отличить от написанных строчными буквами имен переменных.

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

Второй способ. После появления стандарта ANSI на объектно-ориентированное программирование в языке «C++» появился новый спецификатор для задания констант – const. В «C++» он может использоваться вместо конструкции #define.

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

const int true = 1;

const double pl = 4*atan(1.0);

const int size = 5000;

char const *name1 = "Ричард С. Вайнер";

const char *name2 = "Лэвис Дж. Пинсон";

Четвертое объявление указывает, что name – это константный указатель на char, т.е. это адрес не может быть изменен.

Последнее объявление указывает, что строка «Лэвис Дж. Пинсон» является константой. Указатель name2 константой не является и может быть затем изменен.

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

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

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

Это значит, что после c=getchar() переменная c содержит следующий символ из входных данных. Символы обычно поступают с терминала, но это не должно нас касаться до главы 9.

Функция putchar(c) является дополнением к getchar: в результате обращения putchar(c) содержимое переменной c выдается на некоторый выходной носитель, обычно опять на терминал. Обращение к функциям putchar и printf могут перемежаться; выдача будет появляться в том порядке, в котором происходят обращения.

Как и функция printf, функции getchar и putchar не содержат ничего экстраординарного. Они не входят в состав языка «C», но к ним всегда можно обратиться.

2.5.2. Копирование файла. Имея в своем распоряжении только функции getchar и putchar вы можете, не зная ничего более об операциях ввода-вывода, написать удивительное количество полезных программ.

Пример 2-4. Простейшим примером может служить программа посимвольного копирования вводного файла в выводной. Общая схема имеет вид:

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

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

{

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

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

}

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

main() // Копировать ввод-вывод; 1-я версия

{

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. Как мы увидим в главе 3, эта величина действительно int, так как она должна быть в состоянии в дополнение ко всем возможным символам представлять и eof.

Программистом, имеющим опыт работы на «C», программа копирования была бы написана более сжато. В языке «C» любое присваивание, такое как

c = getchar()

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

Пример 2-5. Если присваивание символа переменной c поместить внутрь проверочной части оператора while , то программа копирования файла запишется в виде:

main() // Копировать ввод-вывод; 2-я версия

{

int c;

while ((c = getchar()) != eof)

putchar(c);

}

Программа извлекает символ, присваивает его переменной c, и затем проверяет, не является ли этот символ признаком конца файла. Если нет – выполняется тело оператора while, выводящее этот символ. Затем цикл while повторяется. Когда, наконец, будет достигнут конец файла ввода, оператор while завершается, а вместе с ним заканчивается выполнение и функции main .

В этой версии централизуется ввод – в программе только одно обращение к функции getchar – и ужимается программа. Вложение присваивания в проверяемое условие – это одно из тех мест языка «C», которое приводит к значительному сокращению программ. Однако, на этом пути можно увлечься и начать писать недоступные для понимания программы. Эту тенденцию мы будем пытаться сдерживать.