Для чего используются подпрограммы
Подпрограмма
Подпрограмма (англ. subroutine ) — поименованная или иным образом идентифицированная часть компьютерной программы, содержащая описание определённого набора действий. Подпрограмма может быть многократно вызвана из разных частей программы. В языках программирования для оформления и использования подпрограмм существуют специальные синтаксические средства.
Содержание
Назначение подпрограмм.
Подпрограммы изначально появились как средство оптимизации программ по объёму занимаемой памяти — они позволили не повторять в программе идентичные блоки кода, а описывать их однократно и вызывать по мере необходимости. К настоящему времени данная функция подпрограмм стала вспомогательной, главное их назначение — структуризация программы с целью удобства её понимания и сопровождения.
Механизм подпрограмм, их описание и вызов
В простейшем случае (в ассемблерах) подпрограмма представляет собой последовательность команд (операторов), отдельную от основной части программы и имеющую в конце специальную команду выхода из подпрограммы. Обычно подпрограмма также имеет имя, по которому её можно вызвать, хотя ряд языков программирования допускает использование и неименованных подпрограмм. В языках высокого уровня описание подпрограммы обычно состоит по меньшей мере из двух частей: заголовка и тела. Заголовок подпрограммы описывает её имя и, возможно, параметры, то есть содержит информацию, необходимую для вызова подпрограммы. Тело — набор операторов, который будет выполнен всякий раз, когда подпрограмма будет вызвана.
Вызов подпрограммы выполняется с помощью команды вызова, включающей в себя имя подпрограммы. В большинстве современных языков программирования команда вызова представляет собой просто имя вызываемой подпрограммы, за которым могут следовать фактические параметры (см. ниже).
В следующем примере на языке Паскаль подпрограмма subprog вызывается из основной программы трижды:
Результатом выполнения такой программы станет вывод строки «Hello» и трёх строк «Bye».
Некоторые языки программирования (например, Паскаль, Ада, Модула-2) допускают описание вложенных подпрограмм, то есть помещение подпрограмм внутрь других подпрограмм. Такие вложенные подпрограммы могут использоваться только в той подпрограмме, в которой они описаны. В иных случаях (например, в языке Си) вложение подпрограмм не допускается. Никаких принципиальных преимуществ вложение подпрограмм не даёт, но может быть удобно для более логичной структуризации программы (если какая-то подпрограмма используется только в некоторой другой подпрограмме, логично поместить первую во вторую).
Параметры подпрограмм
Назначение параметров
Подпрограммы часто используются для многократного выполнения стереотипных действий над различными данными. Подпрограмма обычно имеет доступ к объектам данных, описанным в основной программе (по крайней мере, к некоторым из них), поэтому для того, чтобы передать в подпрограмму обрабатываемые данные, их достаточно присвоить, например, глобальным переменным. Но такой путь не особенно удобен и чреват ошибками.
Для обеспечения контролируемой передачи параметров в подпрограмму и возврата результатов из неё используется механизм параметров. Параметры описываются при описании подпрограммы (в её заголовке) и могут использоваться внутри процедуры аналогично переменным, описанным в ней. При вызове процедуры значения каждого из параметров указываются в команде вызова (обычно после имени вызываемой подпрограммы).
В приведённом примере параметр Line подпрограммы subprog в каждом вызове получает различное значение, благодаря чему выводятся не одинаковые строки, а разные.
Формальные и фактические параметры
Способ передачи параметров в подпрограмму
Существует несколько способов передачи параметров в подпрограмму.
Язык программирования может предоставлять возможность передавать параметры в подпрограммы либо только по значению (так сделано в языке Си), либо по значению и по ссылке (это реализовано в Паскале, Аде, C++), либо по имени и значению (это реализовано в языках Алгол и Алгол 68). В последних двух случаях для различения способов передачи параметра используются отдельные синтаксическая конструкции (в Паскале это ключевое слово var при описании параметра). В действительности, если язык содержит понятие ссылки (указателя), то можно обойтись и без передачи параметра по ссылке (её всегда можно смоделировать, описав параметр типа «ссылка»), но эта возможность удобна, так как позволяет работать с формальным параметром-ссылкой без разыменования, а также повышает надёжность и безопасность программы.
На параметры, передаваемые по ссылке, накладываются естественные ограничения: фактический параметр, подставляемый на место такого параметра при вызове, обязан быть переменной (то есть иметь адрес), а в языках со строгой типизацией — ещё и иметь в точности такой же тип данных.
Виды подпрограмм
В языках программирования высокого уровня используется два типа подпрограмм: процедуры и функции.
Подпрограммы, входящие в состав классов в объектных языках программирования, обычно называются методами. Этим термином называют любые подпрограммы-члены класса, как функции, так и процедуры; когда требуется уточнение, говорят о методах-процедурах или методах-функциях.
Pascal | Лекция №6
Подпрограммы. Процедуры и функции
СОДЕРЖАНИЕ:
Подпрограммы (см. Рапаков стр.143-157!)
Понятие подпрограмма встречается во многих языках программирования, т.к. является основным средством структурирования языка. Очень часто в программах встречаются однотипные участки, которые выполняют одни и те же вычисления с различными данными. Такие части программ целесообразно выполнять с помощью подпрограмм.
Использование подпрограмм позволяет:
Таким образом, подпрограмма – это часть операторов программы, выделенных в группу, оформленную в виде отдельной конструкции.
Вызов подпрограммы, т.е. выполнение действий, заданных в подпрограмме, может быть произведен в некоторой точке программы посредством указания имени этой подпрограммы.
Структура подпрограмм
Структура подпрограмм почти в точности повторяет структуру всей Pascal-программы.
При описании подпрограммы в общем случае необходимо задать три основные компоненты:
Интерфейс подпрограммы содержится в заголовке и говорит о том, что именно делает подпрограмма.
Две остальные компоненты называются телом подпрограммы и содержат информацию о том, как выполняется подпрограммой то, что описано в ее заголовке.
В языке Pascal выделяют два вида подпрограмм: процедуры и функции. Различия процедур и функций заключается в назначении и способе их использования.
Функции нужны для вычисления нового значения некоторого выражения, и вызов функции должен быть операндом в выражении.
Процедуры служат для задания последовательности действий и определения новых значений переменных в программе. Вызов процедуры играет роль оператора.
Описание процедур и функций. Формальные параметры
Описание процедур и функций в общем виде:
Тело подпрограммы – это блок, состоящий из двух частей: описание объектов и группа операторов. Более полный общий вид процедуры (общий вид функции отличается только заголовком):
Здесь — имя процедуры.
Раздел описаний, как и в основной программе, может включать разделы Label, Const, Type, Var и раздел процедур и функций.
Формальные параметры представляют собой список переменных с указанием их типа, которые отделяются друг от друга «;». Эти переменные не описываются в разделе описания процедур. Допускается использование процедур без параметров.
Если в качестве параметров используется массив, то предварительно нужно описать имя типа массива в разделе Type, а затем использовать это имя при описании массива в качестве формального параметра.
Параметры процедур бывают двух типов:
Описание входных параметров процедуры в списке формальных параметров имеет также вид:
Список переменных1: тип1; список переменных2: тип2;
Соответственно описание выходных параметров выглядит следующим образом:
Var Список переменных1: тип1; Var список переменных2: тип2;
Вызов процедуры в основной программе имеет следующий вид:
(список фактических параметров);
Фактические параметры перечисляются через запятую, без указания их типа. Идентификаторы формальных параметров можно считать условными обозначениями в теле подпрограммы тех реальных, фактических параметров, с которыми будет вызвана подпрограмма. При этом должны выполняться требования:
Имена соответствующих фактических и формальных параметров могут быть одинаковыми или разными.
Входными фактическими параметрами могут быть константы, переменные или выражения, выходными фактическими параметрами могут быть только переменные.
Другой вид подпрограммы в языке Турбо-Паскаль – функция – оформляется аналогично процедуре и отличается от нее по структуре только заголовком, общий вид которого выглядит следующим образом:
Function (список формальных параметров): тип;
Функции имеют несколько отличительных особенностей:
Область действия имен
Переменные, представленные в разделе описания основной программы, могут быть использованы в теле основной программы и в любой ее подпрограмме. Эти переменные называются глобальными.
Переменные, описанные в подпрограмме, действуют только в теле данной подпрограммы и в любой, объявляемой внутри нее, подпрограмме. Такие переменные называются локальными. Они недоступны для операторов основной программы и др. подпрограмм.
Наглядно схему программы, имеющей некоторые вложенные подпрограммы, можно представить следующим образом:
Самый внешний блок программы обозначен буквой A (имена этого блока «видны» во всех остальных блоках), B и D – подпрограммы, описанные во внешнем блоке, C – подпрограмма, описанная в блоке B (объекты этого блока известны только внутри самого блока).
При написании программ, имеющих вложенные подпрограммы, необходимо соблюдать следующие правила:
Использование процедур и функций на примере
Пример 1: вычислить площадь выпуклого четырехугольника
В результате выполнения данной программы на экран будет выведено:
Подпрограммы
Вспомогательные алгоритмы и подпрограммы
Алгоритм, выполняющий некоторую относительно автономную, законченную часть основной задачи, называют вспомогательным алгоритмом, а соответствующую “вспомогательную программу” — подпрограммой (или процедурой). Во многих языках программирования процедура оформляется так же или почти так же, как головная программа.
Когда используют подпрограммы? Во-первых, если один и тот же алгоритм используется несколько раз по ходу решения задачи. Это вполне очевидно: зачем несколько раз писать одни и те же команды? Последовательность операторов, составляющих подпрограмму, определена и записана только в одном месте программы, однако их можно вызвать для выполнения из одной или нескольких точек программы. Одна и та же подпрограмма может обрабатывать различные данные, переданные ей в качестве аргументов. Это не просто выделенный кусок кода — для этого куска кода определены входные и выходные параметры, а от прочих данных он, в идеале, изолирован (хотя многие языки программирования позволяют использовать внутри кода подпрограммы и глобальные переменные).
Во-вторых, в разных программах часто используется большое количество однотипных, шаблонных действий — вывод данных на экран, сортировка чисел по возрастанию в числовых массивах или сортировка списков фамилий по алфавиту, различные алгоритмы поиска необходимых данных в массивах — этот перечень стереотипных работ можно продолжать долго. Совершенно очевидна целесообразность однократного составления таких часто употребляемых вспомогательных алгоритмов, хранение их и последующее использование в самых разнообразных задачах. Наборы таких часто употребимых подпрограмм обычно объединяют в библиотеки подпрограмм. Развитой системой библиотечных подпрограмм обладают такие языки программирования, как С++ и Java.
Но, оказывается, на практике подпрограммами гораздо чаще пользуются, чтобы упростить процесс разработки программы. По мере прогресса в искусстве программирования, как пишет автор языка Pascal Н.Вирт, программы стали создаваться методом последовательных уточнений. На каждом этапе программист разбивает задачу на некоторое число подзадач. Таким образом, подпрограммы — это реализация в языке программирования основного и вспомогательных алгоритмов, на которые, как правило, распадается решение общей задачи в процедурном программировании. Концепция процедур (т.е. подпрограмм) позволяет выделить подзадачу как отдельную подпрограмму, даже если вызываться она будет всего один раз. Допустим, нужно составить какую-нибудь достаточно сложную программу: она должна получать от человека исходные данные, проверяя при этом правильность ввода (чтоб не было ошибок, вроде “32 февраля”), затем выполнять несколько разных вычислений, наконец, — красиво выводить результаты на экран. Можно попытаться написать сразу всю программу целиком. Однако она скорее всего получится очень большой и настолько запутанной, что поиск любой самой простой ошибки займет много времени (а написать даже не очень большую программу сразу без ошибок практически невозможно). Но можно поступить по-другому. Сначала разобьем решение задачи на несколько этапов. Получится программа примерно такого вида:
Мы еще не знаем, как будут реализовываться эти этапы, но то, что они необходимы, нам известно; не возникает вопросов и с их последовательностью. Далее, каждый из этапов разбиваем на более мелкие, затем, при необходимости — еще. Так продолжаем, пока подзадачи не окажутся настолько мелкими, что каждую из них можно будет записать с помощью небольшой простой и понятной процедуры. Можно сказать, что подпрограммы являются основными строительными блоками программы. Такой способ разработки программ называют проектированием методом сверху вниз.
Каковы достоинства этого метода? Во-первых, сокращение времени разработки больших программ: на решение 10 простых задач обычно нужно гораздо меньше времени, чем на одну, в 10 раз более сложную. Во-вторых, локализация мест ошибок при отладке программ: разобраться в работе процедуры и найти возможную ошибку намного проще, если эта процедура — короткая. В-третьих, относительная автономность модификации программы: когда нужно будет что-либо изменить в программе, переделывать придется не всю ее, а только некоторые процедуры. Наконец, такой метод позволяет легко распределить работу между несколькими программистами: при разработке процедуры абсолютно не важно, что содержится внутри других.
Процедуры и функции
Во многих языках программирования явно (как в Pascal) или неявно (как в С и С++) различают два вида подпрограмм — процедуры и функции. Основное отличие функций от процедур заключается в том, что функция возвращает результат некоторого типа.
После описания функции ее, как лексическую единицу, можно использовать в выражениях наряду со стандартными функциями. Функция активируется только при вызове ее из тела основной программы или из другой уже вызванной подпрограммы (процедуры или функции). При вызове функции указывается имя функции и конкретные параметры (их называют фактические параметры), необходимые для вычисления функции.
В описании процедуры или функции задается список формальных параметров. Каждый параметр, описанный в этом списке, является локальным по отношению к описываемой процедуре или функции, т.е. на него можно ссылаться по его имени из данной подпрограммы, но не из основной программы.
Приведем пример программы на языке Pascal нахождения максимума из трех чисел, использующей описание функции max нахождения максимума из двух чисел:
function max(a, b: integer): integer;
if a > b then max := a
Процедура либо вообще не возвращает результат, либо делает это через параметры. Процедура активируется (вызывается) с помощью оператора процедуры. Он представляет собой то же имя, что и название процедуры, с перечислением в скобках фактических параметров (процедура параметров может и не содержать, например, процедура очистки экрана).
Приведем пример описания процедуры на языке Pascal, которая печатает первые N элементов массива. Используем эту процедуру для печати различных частей массива:
type aa = array[1..100] of integer;
procedure print(n: integer; var m: aa);
for i := 1 to 100 do a[i] := random(100);
for i := 1 to 100 do print(a,i)
Процедура или функция является рекурсивной, если она прямо или косвенно вызывает сама себя. То есть либо при описании функции или процедуры используется обращение к ней же самой, но с другим набором параметров, либо подпрограмма вызывает какую-либо другую подпрограмму, в описании которой содержится вызов исходной (например, процедура A вызывает процедуру В, а процедура В вызывает процедуру А).
Рекурсивный вариант реализации алгоритма обычно выглядит изящнее и дает более компактный текст программы, но исполняется медленнее. Приведем пример уместного использования рекурсивного алгоритма. Рассмотрим алгоритм эффективного возведения вещественного числа x в целую неотрицательную степень n, основанный на следующих очевидных соотношениях:
Зададим по данному описанию рекурсивную функцию на языке Pascal:
function power(x:real; n:integer):integer;
if n = 0 then power := 1
power := power(x*x,n div)
else power := power(x,n-1)*x
Данная функция для вычисления x n будет использовать не более 2log2n умножений, а ее нерекурсивный аналог написать и отладить существенно сложнее.
Процедурное программирование
Процедурное программирование — это одна из парадигм программирования.
Парадигма программирования представляет (и определяет) то, как программист подходит к реализации алгоритма и проектированию программы. Так, процедурное программирование основано на представлении программы, как определенной последовательности вызова процедур.
Процедурное программирование — оформившаяся в начале 70-х годов XX века идея разработки программ. Это фундаментальная концепция, являющаяся основой всех современных подходов к проектированию и реализации. В то же время суть ее проста и отражает широко известные методы, заключающиеся в поиске и реализации некоторого базового набора элементов, комбинация которых дает решение задачи.
Если концепция структурного программирования предлагает некоторый универсальный алгоритмический базис, то процедурное программирование состоит в разработке под конкретную задачу или круг задач (предметную область) собственного базиса в виде набора подпрограмм, позволяющего наиболее эффективно по целому ряду критериев построить программный комплекс. С применением процедурного программирования появились возможности коллективной разработки программ как набора “независимых” частей, последовательного уменьшения сложности методом разбиения сложной задачи на более простые подзадачи, наконец, возможности повторного использования созданного ранее кода.
Решение общей задачи даже в простейших случаях представляет собой многоступенчатый процесс расчленения на все более простые действия. Конечно, можно составить весь алгоритм без явного выделения вспомогательных действий, но такую программу будет не только неудобно составлять и отлаживать, ее будет чрезвычайно сложно читать и практически невозможно совершенствовать.
Обычно процедурная программа состоит из главной подпрограммы (она нужна для определения начала и конца общего алгоритма), которая что-то делает сама, а что-то поручает вызываемым на выполнение вспомогательным подпрограммам, которые, в свою очередь, делают что-то сами и, возможно, вызывают на выполнение другие вспомогательные подпрограммы и т.д. После завершения подпрограмма должна возвратить управление в точку вызова — точнее, на оператор, следующий за вызовом подпрограммы.
Процедуры и функции позволяют создавать большие структурированные программы, которые можно делить на части. Это дает преимущества в следующих ситуациях:
1. Если программа большая, разделение ее на части облегчает создание, тестирование и ее сборку.
2. Если программа большая и повторная компиляция всего исходного текста занимает много времени, разделение ее на части экономит время компиляции.
3. Если процедуру надо использовать в разных случаях разным образом, можно записать ее в отдельный файл и скомпилировать отдельно.
Более современная парадигма программирования — объектно-ориентированное программирование (см. статью “Объектно-ориентированное программирование”) — фактически включает в себя и процедурную парадигму.
Методические рекомендации
Данная тема возникает при изучении программирования на языках высокого уровня или на языке исполнителя, например, LOGO. Слово подпрограмма (routine) использовалось уже в 1949 г. при программировании на машине EDSAC, которую принято считать первой построенной машиной с хранением программ в памяти. Подпрограмма является основным строительным блоком в императивном программировании (такое программирование описывает процесс выполнения программы в виде инструкций, изменяющих состояние исполнителя, альтернативой императивному программированию служит декларативное — логическое или функциональное — программирование).
Подпрограммы используются главным образом для целей абстракции. Под абстракцией понимается действие, состоящее в выборе для дальнейшего изучения или использования небольшого числа свойств объекта и изъятии из рассмотрения остальных свойств, которые нам в данный момент не нужны. Основное свойство, которое выделяется при написании подпрограммы, — это то, что она делает. Главное свойство, которое опускается из рассмотрения, — как она это делает. В некотором смысле использование подпрограммы — в точности то же самое, что и использование любой другой операции, применимой в том или ином языке программирования, например, +. А написание подпрограммы — это расширение языка путем включения в него новой операции.
Существуют подходы к изучению языка программирования, в которых подпрограммы предлагается использовать на самых ранних этапах изучения языка, а в таких языках, как С, этого вообще практически не избежать. При этом допускается сначала не полное понимание того, что же представляют собой подпрограммы, какую память они используют и как происходит передача параметров при их вызове. Возможно, такой подход позволяет сразу вырабатывать правильный стиль написания структурированных программ. Однако учебные программы, которые ученикам приходится писать на первых этапах обучения, зачастую не требуют детализации с помощью процедур и функций, поэтому изучение последних можно отложить и на более поздний срок (или опустить совсем, если курс программирования является чисто ознакомительным).
В некоторых языках программирования, например в языке Pascal, достаточно сложным является механизм передачи параметров и следующие из него правила разделения параметров на параметры-значения и параметры-ссылки. Попробуйте объяснить учащимся этот механизм, только в этом случае они смогут грамотно и без ошибок выбирать тип параметров при описании процедур и функций.
Подробное изучение данной темы в 10–11-х профильных классах заканчивается рассмотрением рекурсии, ее применением и механизмом реализации в тех языках программирования, в которых она разрешена.
Подпрограммы
В практике программирования часто складываются ситуации, когда одну и ту же группу операторов, реализующих определённую цель, требуется повторить без изменений в нескольких местах программы. Для избавления от столь нерациональной траты времени была предложена концепция подпрограммы.
4.1 Общие сведения о подпрограммах. Локальные и глобальные переменные
Для правильного определения области действия идентификаторов (переменных) необходимо придерживаться следующих правил:
4.2 Формальные и фактические параметры. Передача параметров в подпрограмму
Обмен информацией между вызываемой и вызывающей функциями осуществляется с помощью механизма передачи параметров. Переменные, указанные в списке в заголовке функции, называются формальными параметрами, или просто параметрами подпрограммы. Все переменные из этого списка могут использоваться внутри подпрограммы. Список переменных в операторе вызова подпрограммы — это фактические параметры, или аргументы.
Механизм передачи параметров обеспечивает обмен данных между формальными и фактическими параметрами, что позволяет выполнять подпрограмму с различными данными. Между фактическими параметрами в операторе вызова и формальными параметрами в заголовке подпрограммы устанавливается взаимно однозначное соответствие. Количество, типы и порядок следования формальных и фактических параметров должны совпадать.
Формальные параметры процедуры можно разделить на два класса: параметры-значения и параметры-переменные.
При передаче данных через параметры-значения в подпрограмму передаются значения фактических параметров, и доступа к самим фактическим параметрам из подпрограммы нет. При передаче данных параметры-переменные заменяют 1 Реально в подпрограмму передаются адреса фактических параметров. формальные параметры, и, следовательно, в подпрограмме есть доступ к значениям фактических параметров. Любое изменение параметров-переменных в подпрограмме приводит к изменению соответствующих им формальных параметров. Следовательно, входные данные следует передавать через параметры-значения, для передачи изменяемых в результате работы подпрограммы данных следует использовать параметры-переменные.
От общетеоретических положений перейдём к практическому использованию подпрограмм при решении задач. Изучение подпрограмм начнем с процедур.
4.3 Процедуры
Описание процедуры имеет вид:
procedure name_1( r : real; i : integer; c : char );
Однотипные параметры могут быть перечислены через запятую:
procedure name_2( a, b : real; i, j, k : integer );
Список формальных параметров необязателен и может отсутствовать:
Если в заголовке процедуры будут применяться параметры-переменные, то перед ними необходимо указывать служебное слово var :
procedure name_4( x, y : real; var z : real );
Для обращения к процедуре необходимо использовать оператор вызова:
Фактические параметры в списке оператора вызова отделяются друг от друга запятой:
a : = 5. 3; k : = 2; s := ’ a ’;
Если в описании процедуры формальные параметры отсутствовали, то и при вызове их быть не должно:
Алгоритм решения этой задачи был подробно описан в задаче 3.3 (рис. 3.14). Однако там не была рассмотрена ситуация некорректного ввода значений коэффициентов. Например, если пользователь введёт , то уравнение из квадратного превратится в линейное. Алгоритм решения линейного уравнения тривиален:
, при условии, что
. Чтобы не усложнять уже составленный алгоритм решения квадратного уравнения, запишем его в виде подпрограммы-процедуры. Далее приведён фрагмент программы с комментариями: