Возможность применения подпрограмм относит язык программирования к классу процедурных языков.
Наличие подпрограмм позволяет вести проектирование и разработку приложения сверху вниз — такой подход называется нисходящим проектированием. Сначала выделяется несколько подпрограмм, решающих самые глобальные задачи (например, инициализация данных, главная часть и завершение), потом каждый из этих модулей детализируется на более низком уровне, разбиваясь в свою очередь на небольшое число других подпрограмм, и так происходит до тех пор, пока вся задача не окажется реализованной.
Такой подход удобен тем, что позволяет человеку постоянно мыслить на предметном уровне, не опускаясь до конкретных операторов и переменных^ Кроме того, появляется возможность некоторые подпрограммы не реализовывать сразу, а временно откладывать, пока не будут закончены другие части. Например, если имеется необходимость вычисления сложной математической функции, то выделяется20.4. Структурное программирование 601
отдельная подпрограмма такого вычисления, но реализуется она временно одним оператором, который просто присваивает заранее выбранное значение (например, 5). Когда все приложение будет написано и отлажено, тогда можно приступить к реализации этой функции.
Немаловажно, что небольшие подпрограммы значительно проще отлаживать, что существенно повышает общую надежность всей программы.
Очень важная характеристика подпрограмм — это возможность их повторного использования. С интегрированными системами программирования поставляются большие библиотеки стандартных подпрограмм, которые позволяют значительно повысить производительность труда за счет использования чужой работы по созданию часто применяемых подпрограмм.
Рассмотрим пример, демонстрирующий методику нисходящего проектирования. Имеется массив Ocenki, состоящий из N (N> 2) судейских оценок (каждая оценка положительна). В некоторых видах спорта принято отбрасывать самую большую и самую маленькую оценки, чтобы избежать влияния необъективного судейства, а в зачет спортсмену идет среднее арифметическое из оставшихся оценок. Решим эту задачу, постепенно детализируя алгоритм (без привязки к конкретному языку программирования).
1. Процесс решения наиболее просто описывается подпрограммами:
Ввести_оценки_в_массив; Удалить_самую_большую_оценку; Удалить_самую_маленьк?ую__оценку; Рассчитать_среднее_арифметическое_оставшихся_оценок; Вывести_результаты;Теперь можно приступить к детализации каждой их этих подпрограмм.
2. Удалить_самую_большую_оценку;
Как удалить самую большую оценку из статического массива? Вместо нее можно просто записать значение 0, а при подсчете среднего арифметического нулевые значения не учитывать.
I
= Номер_самого_большого_элемента_в_массиве; ' Ocenki[ I ] = 0;3. Удалить_самую_маленькую_оценку;
I
= Номер_самого_маленького_элемента_в_массиве; Ocenki( I ) = 0;При реализации подпрограммы Номер_самого_маленького_элемента_в_массиве надо учесть, что искать придется самое маленькое из положительных значений (больших нуля).
4. Рассчитать_среднее_арифметическое_оставшихся_оценок;
Глава 20. Основы программирования
Здесь потребуется оператор цикла, вычисляющий сумму всех элементов массива Ocenki. SUM = 0 FOR I = 1 ТО N SUM = SUM + Ocenki( I )NEXT
SUM = SUM / (N - 2)
В последнем операторе происходит вычисление среднего арифметического всех оценок. Сумма элементов массива делится на число элементов, уменьшенное
•• на 2, потому что две оценки, самую большую и самую маленькую, учитывать не надо.
Если бы эта задача решалась последовательно, то уже на этапе удаления оценок могли возникнуть определенные проблемы.
Реализацию подпрограмм Номер_самого_большого_элемента_в_массивеи Номер_ самого_маленького_элемента_в_массиве выполните самостоятельно.Подпрограммы бывают двух видов — процедуры и функции. Отличаются они тем, что процедура просто выполняет группу операторов, а функция вдобавок вычисляет некоторое значение и передает его обратно в главную программу (возвращает значение). Это значение имеет определенный тип (говорят, что функция имеет такой-то тип).
В Си++ понятия «процедура» нет — там имеются только функции, а если никакого значения функция не вычисляет, то считается, что она возвращает значение типа «никакое» (void).
Подпрограммы вызываются, как правило, путем простой записи их названия с нужными параметрами. В Бейсике есть оператор CALL для явного указания того, что происходит вызов подпрограммы.
Подпрограммы активизируются только в момент их вызова. Операторы, находящиеся внутри подпрограммы, выполняются, только если эта подпрограмма явно вызвана. Пока выполнение подпрограммы полностью не закончится, оператор главной программы, следующий за командой вызова подпрограммы, выполняться не будет.
Подпрограммы могут быть вложенными — допускается вызов подпрограммы не только из главной программы, но и из любых других подпрограмм.
В некоторых языках программирования допускается вызов подпрограммы из себя самой. Такой прием называется рекурсией и потенциально опасен тем, что может привести к зацикливанию — бесконечному самовызову.
Подпрограмма состоит из нескольких частей: заголовка с параметрами, тела подпрограммы (операторов, которые будут выполняться при ее вызове) и завершения подпрограммы.
Локальные переменные, объявленные внутри подпрограммы, имеют областью действия только ее тело.
ФункцииБейсик | Паскаль | Си++ | |
Заголовок функции | FUNCTION имя (список_параметров) Тип возвращаемого значения определяется специальным символом после имени функции | function имя (список_параметров): тип_функции; | тип функции имя(список_параметров) |
Тело | Последовательность операторов | begin последовательность операторов end; | { последовательность операторов }; |
Завершение | END FUNCTION | нет | нет |
После того как функция рассчитала нужное значение, ей требуется явно вернуть его в вызывающую программу. Для этого может использоваться специальный оператор (return в Си++) или особая форма оператора присваивания, когда в левой части указывается имя функции, а справа — возвращаемое значение.
' Глава 20. Основы программирования
Далее приведены примеры функции, вычисляющей значение квадрата аргумента. Бейсик:
FUNCTION SQR% (X AS INTEGER) SQR% = X*X
END FUNCTION Паскаль:
function SQR(X: integer): integer;
begin SQR := X*X end; Си++: int SQR(int x)
{
return x*x;
} ;
Во время создания подпрограммы заранее не известно, какие конкретно параметры она может и будет получать. Поэтому в качестве переменных, выступающих в роли ее аргументов в заголовке, могут использоваться произвольные допустимые названия, даже совпадающие с уже имеющимися. Компилятор все равно поймет, что это не одно и то же.
Параметры, которые указываются в заголовке подпрограммы, называются формальными. Они нужны только для описания тела подпрограммы. А параметры (конкретные значения), которые указываются в момент вызова подпрограммы, называются фактическими параметрами. При выполнении операторов подпрограммы формальные параметры как бы временно заменятся на фактические.
Пример. i n t а, у; а = 5; у = SQR(a);