Страница 56 из 69
цикла). Это похоже на цикл repeat...until в Паскале с одним, од-
нако, различием: цикл repeat выполняется дотехпор, пока его усло-
вие не станет истинным; а цикл do...while выполняется пока исти-
на.
Функции.
-----------------------------------------------------------------
Вы изучили, как выполняются программы, содержащие условные и
итеративные операторы. Сейчас настало время задать нам вопрос: а
что же делать, если я вдруг захочу выполнить различные группы
операторов, использующие различные наборы данных или находящиеся
в различных частях программы? Ответ прост: объединяйте эти группы
операторов в подпрограммы, к которым вы будете обращаться по не-
обходимости.
В Си все подпрограммы рассматриваются как функции. Теорети-
чески, каждая функция возвращает некоторое значение. Практически
же, значения, возвращаемые большинством функций игнорируются и
целое семейство новых определений языка Си (включая проект стан-
дарта Си, предложенный ANSI, и Турбо Си) позволяют описывать и
использовать в языке функции типа void, которые никогда не возв-
ращают значений. Никогда.
В Си вы можете и описывать и определять функцию. Когда вы
описываете функцию, то даете всем остальным программам (включая
главный модудь main) информацию о том, каким образом должно осу-
- 461,462 -
ществляться обращение к этой функции. Когда вы определяете функ-
цию, вы присваиваете ей имя, по которому к ней будет осущест-
вляться обращение, и указываете, какие конкретно действия она
будет выполнять. Внимательно изучите этот модифицированный вари-
ант RATIO.C:
#include
else
printf("Результат деления двух чисел: %f\n",ratio);
}
Анализ программы.
-----------------------------------------------------------------
Первые три строки программы - описание функций; они вводятся
для того, чтобы описать как тип функций, так и порядок следования
их параметров с целью контроля ошибок.
Следующая строка описывает константу с плавающей точкой, ко-
торой присваивается имя INFINITY (в соответствии с принятым в Си
соглашением имена констант состоят из заглавных букв). Эта конс-
танта имеет очень большое положительное значение - близкое к наи-
большему из допустимых для типа float, и используется как флаг
возникновения ситуации деления на ноль (divide-by-zero).
Заметьте, что несмотря на то, что константа описана здесь,
она доступна внутри всех функций (включая главную функцию).
Далее следует функция main (главная функция), которая явля-
ется основным телом вашей программы. Каждая программа на Си обя-
зательно содержит функцию с именем main. Когда ваша программа на-
чинает выполняться, вызывается функция main и дальнейшее
выполнение программы продолжается под ее управлением. Когда вы-
полнение функции с именем main заканчивается, то завершается и
вся программа, после чего управление передается интегрированной
среде Турбо Си или, если вы выполняли программу непосредственно в
DOS, то монитору DOS.
Функция main может быть расположена в любом месте программы,
наиболее часто - это первая функция программы. Это обусловлено
- 465,466 -
тем, что расположение функции main в начале программы облегчает
ее чтение, описание прототипов функций и различных глобальных пе-
ременных. Это, в свою очередь, позволяет облегчить поиск и доку-
ментирование функций во всей программе.
После main следует фактическое определение трех функций,
прототипы которых были описаны выше: get_parms, get_ratio и
put_ratio. Рассмотрим отдельно каждое из определений.
Функция get_parms.
-----------------
Функция get_parms не возвращает никакого значения, так как
ее тип мы определили как void. Это было сделано в связи с тем,
что функция служит лишь для чтения двух значений и сохранения их
в некотором месте. В каком? Сейчас дадим некоторые пояснения.
Итак, мы передаем в get_parms два параметра. Эти параметры суть
адреса, по которым должны быть размещены считанные функцией зна-
чения. Обратите внимание! Оба параметра не являются данными типа
float, но являются указателями на переменные типа float. Другими
словами, мы работаем непосредственно с адресами памяти по которым
размещены переменные типа float.
В соответствии с этим и организовано обращение к функции из
main: когда мы вызываем get_parms из main, параметрами функции
являются &a и &b (адреса), а не текущие значения a и b. Заметьте
также, что вся информация, используемая при обращении к функции
scanf, находится непосредственно внутри функции get_parms и перед
параметрами p1 и p2 не стоят знаки операций адресации. Почему?
Потому, что p1 и p2 уже сами по себе адреса; они являются адреса-
ми переменных a и b.
Функция get_ratio.
-----------------
Функция get_ratio возвращает результат (типа float) обработ-
ки двух значений типа float, передаваемых ей (divident и
divisor). Возвращенный функцией результат зависит от того, равно
значение переменной divisor нулю или нет. Если значение divisor
равно нулю, get_ratio возвращает константу INFINITY. Если нет -
- 467,468 -
действительное значение частного двух чисел. Обратите внимание на
вид оператора return.
Функция put_ratio.
-----------------
Функция put_ratio не возвращает значение, т.к. ее тип объяв-
лен как void. Она имеет ровно один параметр - ratio, который ис-
пользуется для того, чтобы определить, какое именно сообщение
следует выводить на экран дисплея. Если ratio равно INFINITY,
значит значение частного двух чисел считается неопределенным, в
противном случае значение ratio выводится на экран дисплея как
результат работы программы.