Может ли в программе быть подпрограмма. Подпрограммы

| Подпрограммы. Практикум. Практическая работа № 3.5 "Программирование с использованием подпрограмм"

Уроки 45 - 47
Подпрограммы
Практикум
Практическая работа № 3.5
"Программирование с использованием подпрограмм"







Вспомогательные алгоритмы и подпрограммы

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

В языках программирования вспомогательные алгоритмы называются подпрограммами. В Паскале различаются две разновидности подпрограмм: процедуры и функции. Рассмотрим этот вопрос на примере следующей задачи: даны два натуральных числа а и b . Требуется определить наибольший общий делитель трех величин: а + b, а 2 + b 2 , а b.

Запишем это так: НОД(а + b, а 2 + b 2 , а b).

Идея решения состоит в следующем математическом факте: если х, у, z - три натуральных числа, то НОД(х, y, z ) = НОД(НОД(х, у ), z ). Иначе говоря, нужно найти НОД двух величин, а затем НОД полученного значения и третьего числа (попробуйте это доказать).

Очевидно, что вспомогательным алгоритмом для решения поставленной задачи является алгоритм получения наибольшего общего делителя двух чисел. Эта задача решается с помощью алгоритма Евклида, который подробно обсуждался в 9 классе. Напомним, что идея алгоритма Евклида основана на следующей формуле:

Приведем алгоритм решения поставленной задачи на учебном Алгоритмическом языке. Алгоритм состоит из процедуры «Евклид» и основного алгоритма «Задача», в котором присутствуют два обращения к процедуре:

Здесь М, N и К являются формальными параметрами процедуры. М и N - параметры-аргументы, К - параметр-результат.

Процедуры в Паскале. Основное отличие процедур в Паскале от процедур в Алгоритмическом языке (АЯ) состоит в том, что процедуры в Паскале описываются в разделе описания подпрограмм, а в АЯ процедура является внешней по отношению к вызывающей программе. Теперь посмотрим, как решение поставленной задачи программируется на Паскале.

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

Procedure <имя процедуры> [(список формальных параметров)]; <блок>

Квадратные скобки указывают на то, что список формальных параметров может отсутствовать, т. е. возможна процедура без параметров. Параметры могут быть параметрами-переменными и параметрами-значениями. Параметры-переменные записываются следующим образом:

Var <список переменных>: <тип>

Параметры-значения указываются так:

<список переменных>: <тип>

Чаще всего аргументы представляются как параметры-значения (хотя могут быть и параметрами-переменными). А для передачи результатов используются параметры-переменные. Процедура в качестве результата может передавать в вызывающую программу множество значений (в частном случае - одно), а может и ни одного. Теперь рассмотрим правила обращения к процедуре. Обращение к процедуре производится в форме оператора процедуры :

<имя процедуры>[(список фактических параметров)]

Если описана процедура с формальными параметрами, то обращение к ней производится оператором процедуры с фактическими параметрами. Правила соответствия между формальными и фактическими параметрами: соответствие по количеству , соответствие по последовательности и соответствие по типам .

Взаимодействие формальных и фактических параметров через параметры-переменные называется передачей по ссылке: при обращении к процедуре ей передается ссылка на переменную, заданную в качестве фактического параметра. Эта ссылка и используется процедурой для доступа к этой переменной.

Другой вариант взаимодействия формальных и фактических параметров называется передачей по значению: вычисляется значение фактического параметра (выражения), и это значение присваивается соответствующему формальному параметру.

В рассмотренном нами примере формальные параметры М и N являются параметрами-значениями. Это аргументы процедуры. При обращении к ней первый раз им соответствуют значения выражений А + В и abs(A - В) ; второй раз - С и А*В . Параметр К является параметром-переменной. В ней получается результат работы процедуры. В обоих обращениях к процедуре соответствующим фактическим параметром является переменная С . Через эту переменную основная программа получает результат.

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

Чтобы разобраться в этом примере, требуется объяснить новое для нас понятие: область действия описания .

Областью действия описания любого программного объекта (переменной, типа, константы и т. д.) является тот блок, на который это описание распространяется. Если данный блок вложен в другой (подпрограмма), то присутствующие во вложенном блоке описания являются локальными . Они действуют только в пределах внутреннего блока. Описания же, расположенные во внешнем блоке, называются глобальными по отношению к внутреннему блоку. Если глобально описанный объект используется во внутреннем блоке, то на него распространяется внешнее (глобальное) описание.

В программе NOD1 переменные М, N, К являются локальными внутри процедуры; переменные А, В, С - глобальные. Однако внутри процедуры переменные А, В, С не используются. Связь между внешним блоком и процедурой осуществляется через параметры.

В программе N0D2 все переменные являются глобальными. В процедуре Evklid нет ни одной локальной переменной (нет и параметров). Переменные М и N , используемые в процедуре, получают свои значения через оператор присваивания в основном блоке программы и изменяют значения в подпрограмме. Результат получается в глобальной переменной К , значение которой выводится на экран. Здесь обмен значениями между основной программой и процедурой производится через глобальные переменные .

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

Функции. Теперь выясним, что такое подпрограмма - функция. Обычно функция используется в том случае, когда результатом работы подпрограммы должна быть скалярная (простая) величина. Тип результата называется типом функции . Формат описания функции следующий:

Как и у процедуры, у функции в списке формальных параметров могут присутствовать параметры-переменные и параметры-значения. Всё это - аргументы функции . Параметры вообще могут отсутствовать, если аргументы передаются глобально.

Программа решения рассмотренной выше задачи с использованием функции будет выглядеть следующим образом:

Из примера видно, что тело функции отличается от тела процедуры только тем, что в функции результат присваивается идентификатору функции : Evklid:=M .

Обращение к функции является операндом в выражении. Оно записывается в следующей форме:

<имя функции> (<список фактических лараметров>)

Правила соответствия между формальными и фактическими параметрами все те же. Сравнивая приведенные выше программы, можно сделать вывод, что программа N0D3 имеет определенные преимущества перед другими. Функция позволяет получить результат путем выполнения одного оператора присваивания. Здесь также иллюстрируется возможность того, что фактическим аргументом при обращении к функции может быть эта же функция.

По правилам стандарта Паскаля, возврат в вызывающую программу из подпрограммы происходит, когда выполнение подпрограммы доходит до ее конца (последний End ). Однако в современных версиях Паскаля есть средство, позволяющее выйти из подпрограммы в любом ее месте. Это оператор-процедура Exit . Например, функцию определения большего из двух данных вещественных чисел можно описать так:

Модифицированный алгоритм Евклида. Подпрограмму алгоритма Евклида можно составить иначе, если воспользоваться операцией mod (получение остатка от деления), имеющейся в Паскале. Идея алгоритма исходит из справедливости следующих равенств:

В таком случае функцию Evklid можно переписать так:


Вопросы и задания

1. Для чего используются подпрограммы?

2. В чем различие между процедурами и функциями?

3. Какие существуют способы передачи данных между подпрограммой и вызывающей ее программой?

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

5. Составьте программу сложения двух простых дробей. Результат должен быть несократимой дробью. Используйте подпрограмму вычисления НОД по алгоритму Евклида. Простая дробь задается двумя целыми числами: числителем и знаменателем.

6. По координатам вершин треугольника вычислите его периметр, используя подпрограмму вычисления длины отрезка между двумя точками.

7. Даны три целых числа. Определите, у которого из них больше сумма цифр. Подсчет суммы цифр организуйте через подпрограмму.

Практикум

Работа 3.5. Программирование с использованием подпрограмм

Задание 1

Для решения всех задач сделать два варианта программы: с реализацией указанной подпрограммы в виде функции и в виде процедуры.

Уровень 1

1. Составить программу нахождения наибольшего общего делителя (НОД) и наименьшего общего кратного (НОК) двух натуральных чисел

.

Использовать подпрограмму алгоритма Евклида для определения НОД.

2. Вычислить площадь правильного шестиугольника со стороной а , используя подпрограмму вычисления площади треугольника.

3. Даны две дроби - (А, В, С, D - натуральные числа).

Составить программу деления дроби на дробь. Ответ должен быть несократимой дробью. Использовать подпрограмму алгоритма Евклида для определения НОД.

4. Даны две дроби - (А, В, С, D - натуральные числа).

Составить программу умножения дроби на дробь. Ответ должен быть несократимой дробью. Использовать подпрограмму алгоритма Евклида для определения НОД.

5. Даны две дроби - (А, В, С, D - натуральные числа).

Составить программу вычитания из первой дроби второй. Ответ должен быть несократимой дробью. Использовать подпрограмму алгоритма Евклида для определения НОД.

6. Написать программу вычисления суммы - для заданного числа n . Результат представить в виде несократимой дроби (р, q - натуральные). Использовать подпрограммы алгоритма Евклида для определения НОД и сложения двух простых дробей.

7. Даны числа X, Y, Z, Т - длины сторон четырехугольника. Вычислить его площадь, если угол между сторонами длиной X и Y - прямой. Использовать две подпрограммы для вычисления площадей: прямоугольного треугольника и прямоугольника.

Задание 2

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

Уровень 2

1. Дано простое число. Найти следующее за ним простое число.

2. Для заданного натурального числа п найти наименьший нечетный натуральный делитель k (k ≠ 1) .

3. Заменить данное натуральное число на число, которое получается из исходного записью его цифр в обратном порядке (например, дано число 156, нужно получить 651).

4. Найти все натуральные числа, не превосходящие заданного п, которые делятся на каждую из своих цифр.

5. Имеется часть катушки с автобусными билетами. Номер билета шестизначный. Составить программу, определяющую количество счастливых билетов на катушке, если меньший номер билета - N , больший - М (билет является счастливым, если сумма первых трех его цифр равна сумме последних трех).

6. Из заданного числа вычли сумму его цифр. Из результата вновь вычли сумму его цифр и т. д. Через сколько таких действий получится нуль?

7. На отрезке (2 10 < N < 2 31 ) найти количество чисел, составленных из цифр а, b, с .

8. Найти все натуральные n-значные числа, цифры в которых образуют строго возрастающую последовательность (например, 1234,5789).

Уровень 3

9. Два простых числа называются «близнецами», если они отличаются друг от друга на 2 (например, 41 и 43). Напечатать все пары «близнецов» из отрезка , где n - заданное натуральное число, большее 2.

10. Дано четное число n > 2. Проверить для него гипотезу Гольдбаха: каждое четное п представляется в виде суммы двух простых чисел.

11. Составить программу разложения данного натурального числа на простые множители. Например, 200 = 2 3 . 5 2 .

12. Дано натуральное число n. Найти все меньшие п числа Мерсенна. (Простое число называется числом Мерсенна, если оно может быть представлено в виде 2 p - 1, где р - тоже простое число. Например, 31 = 2 5 - 1 - число Мерсенна.)

13. Два натуральных числа называются «дружественными», если каждое из них равно сумме всех делителей (кроме его самого) другого (например, числа 220 и 284). Найти все пары «дружественных» чисел, которые не больше данного числа N .

14. Натуральное число, в записи которого n цифр, называется числом Армстронга, если сумма его цифр, возведенная в степень n , равна самому числу. Найти все числа Армстронга от 1 до k .

15. Найти все простые натуральные числа, не превосходящие n , двоичная запись которых представляет собой палиндром, т. е. читается одинаково слева направо и справа налево.

16. Составить программу для нахождения чисел из интервала [М, N] , имеющих наибольшее количество делителей.

17 Дано натуральное число n > 1. Определить длину периода десятичной записи дроби 1/n.

Содержащая описание определённого набора действий. Подпрограмма может быть многократно вызвана из разных частей программы. В языках программирования для оформления и использования подпрограмм существуют специальные синтаксические средства.

Назначение подпрограмм

Подпрограммы изначально появились как средство оптимизации программ по объёму занимаемой памяти - они позволили не повторять в программе идентичные блоки кода, а описывать их однократно и вызывать по мере необходимости. К настоящему времени данная функция подпрограмм стала вспомогательной, главное их назначение - структуризация программы с целью удобства её понимания и сопровождения.

  • Выделение набора действий в подпрограмму и вызов её по мере необходимости позволяет логически выделить целостную подзадачу, имеющую типовое решение. Такое действие имеет ещё одно (помимо экономии памяти) преимущество перед повторением однотипных действий: любое изменение (исправление ошибки, оптимизация, расширение функциональности), сделанное в подпрограмме, автоматически отражается на всех её вызовах, в то время как при дублировании каждое изменение необходимо вносить в каждое вхождение изменяемого кода.
  • Даже в тех случаях, когда в подпрограмму выделяется однократно производимый набор действий, это оправдано, так как позволяет сократить размеры целостных блоков кода, составляющих программу, то есть сделать программу более понятной и обозримой.

Преимущества

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

  • Декомпозиция комплексной программной задачи на простые шаги: это один из двух основных инструментов структурированного программирования и структур данных
  • Уменьшение дублированного кода
  • Возможность повторного использования кода в других программах
  • Разделение крупной программной задачи между различными программистами, или различными стадиями проекта
  • Сокрытие деталей реализации от пользователей подпрограммы
  • Улучшение прослеживания (большинство языков предоставляют способ получить след вызова который включает в себя имена задействованных подпрограмм и возможно даже больше такой информации как имена файлов и номера строк). Без декомпозиции кода на подпрограммы, отладка была бы серьезно затруднена.

Механизм подпрограмм, их описание и вызов

В следующем примере на языке Паскаль подпрограмма subprog вызывается из основной программы трижды:

Program SubProgExample ; procedure subprog ; begin // начало тела подпрограммы WriteLn ("Bye" ) ; end ; // конец тела подпрограммы begin WriteLn ("Hello" ) ; subprog ; // 1-й вызов subprog ; // 2-й вызов subprog ; // 3-й вызов end .

Результатом выполнения такой программы станет вывод строки «Hello» и трёх строк «Bye».

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

Некоторые языки программирования (например, Паскаль, Ада, Модула-2) допускают описание вложенных подпрограмм, то есть помещение подпрограмм внутрь других подпрограмм. Такие вложенные подпрограммы могут использоваться только в той подпрограмме, в которой они описаны. В иных случаях (например, в языке Си) вложение подпрограмм не допускается. Никаких принципиальных преимуществ вложение подпрограмм не даёт, но может быть удобно для более логичной структуризации программы (если какая-то подпрограмма используется только в некоторой другой подпрограмме, логично поместить первую во вторую).

Параметры подпрограмм

Назначение параметров

Подпрограммы часто используются для многократного выполнения стереотипных действий над различными данными. Подпрограмма обычно имеет доступ к объектам данных, описанным в основной программе (по крайней мере, к некоторым из них), поэтому для того, чтобы передать в подпрограмму обрабатываемые данные, их достаточно присвоить, например, глобальным переменным. Но такой путь не особенно удобен и чреват ошибками.

Для обеспечения контролируемой передачи параметров в подпрограмму и возврата результатов из неё используется механизм параметров . Параметры описываются при описании подпрограммы (в её заголовке) и могут использоваться внутри процедуры аналогично переменным , описанным в ней. При вызове процедуры значения каждого из параметров указываются в команде вызова (обычно после имени вызываемой подпрограммы).

Program SubProgExample2 ; // Описание подпрограммы subprog procedure subprog (Line : String ) ; // Заголовок, включающий имя подпрограммы begin // начало тела подпрограммы WriteLn (Line ) ; end ; // конец тела подпрограммы begin WriteLn ("Hello" ) ; subprog ("Good bye," ) ; // 1-й вызов subprog ("my love," ) ; // 2-й вызов subprog ("good bye!" ) ; // 3-й вызов end .

В приведённом примере параметр Line подпрограммы subprog в каждом вызове получает различное значение, благодаря чему выводятся не одинаковые строки, а разные.

Формальные и фактические параметры

Чтобы отличать параметры подпрограммы, описанные в её заголовке и теле, от параметров, указываемых при вызове подпрограммы, используются формальные и фактические параметры. Формальные параметры указываются при объявлении или определении подпрограммы, а фактические - непосредственно при её вызове. Так, в последнем примере параметр Line в заголовке и теле подпрограммы subprog - это формальный параметр, а строка "Good bye" , использованная в первом вызове этой подпрограммы - фактический параметр. При вызове подпрограммы фактические параметры, указанные в команде вызова, становятся значениями соответствующих формальных параметров, чем и обеспечивается передача данных в подпрограмму.

Способ передачи параметров в подпрограмму

Существует несколько способов передачи параметров в подпрограмму.

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

int func1(int x)

{ x=x+2; return x;

  • Передача параметров по ссылке. В формальный параметр может быть помещён сам фактический параметр (обычно это реализуется путём помещения в формальный параметр ссылки на фактический). При этом любое изменение формального параметра в подпрограмме отразится на фактическом параметре - оба параметра во время вызова подпрограммы суть одно и то же. Параметры, передаваемые по ссылке, дают возможность не только передавать параметры внутрь подпрограммы, но и возвращать вычисленные значения в точку вызова. Для этого параметру внутри подпрограммы просто присваивается нужное значение, и после возврата из подпрограммы переменная, использованная в качестве фактического параметра, получает это значение.
  • Передача параметров по имени. В формальный параметр может быть помещено произвольное выражение. При этом вычисление этого выражения произойдёт внутри подпрограммы в тот момент, когда потребуется его значение. Если это значение фигурирует несколько раз, то и вычисляться оно будет тоже несколько раз. Параметры, передаваемые по имени, дают возможность писать довольно универсальные подпрограммы. Такой способ передачи параметров используется, к примеру в языках Алгол или Алгол 68 .
  • Передача параметров через стек. Это фактически разновидность передачи параметра по значению «с ручным приводом», в данном случае отсутствует понятие формальных и фактических параметров. Все параметры лежат на стеке, причём их типы, количество и порядок не контролируются компилятором. Данный подход реализован в языке Форт .

Язык программирования может предоставлять возможность передавать параметры в подпрограммы либо только по значению, либо по значению и по ссылке, либо по имени и значению. В последних двух случаях для различения способов передачи параметра используются отдельные синтаксическая конструкции (в Паскале это ключевое слово var при описании параметра). В действительности, если язык содержит понятие ссылки (указателя), то можно обойтись и без передачи параметра по ссылке (её всегда можно смоделировать, описав параметр типа «ссылка»), но эта возможность удобна, так как позволяет работать с формальным параметром-ссылкой без разыменования, а также повышает надёжность и безопасность программы.

Это подпрограмма специального вида, которая, кроме получения параметров, выполнения действий и передачи результатов работы через параметры имеет ещё одну особенность- она всегда должна возвращать результат. Вызов функции является, с точки зрения языка программирования, выражением, он может использоваться в других выражениях или в качестве правой части присваивания.

  • Процедура - это независимая именованная часть программы, которую после однократного описания можно многократно вызвать по имени из последующих частей программы для выполнения определенных действий.
  • В -подобных языках подпрограмма всегда описывается как функция. Процедура реализуется как функция типа void , то есть имеющая «пустой» тип и, соответственно, не возвращающая никакого значения.

    Подпрограммы, входящие в состав классов в объектных языках программирования, обычно называются методами . Этим термином называют любые подпрограммы-члены класса, как функции, так и процедуры; когда требуется уточнение, говорят о методах-процедурах или методах-функциях .

    Методология структурного программирования основывается на использовании подпрограмм и независимых структур данных.

    Подпрограмма (англ. subprogram) - поименованная или иным образом идентифицированная часть компьютерной программы, содержащая описание определённого набора действий. Подпрограмма может быть многократно вызвана из разных частей программы.

    Назначение подпрограмм . Подпрограммы изначально появились как средство оптимизации программ по объёму занимаемой памяти - они позволили не повторять в программе идентичные блоки кода, а описывать их однократно и вызывать по мере необходимости. К настоящему времени данная функция подпрограмм стала вспомогательной, главное их назначение - структуризация программы с целью удобства её понимания и сопровождения

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

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

    В простейшем случае (в ассемблерах) подпрограмма представляет собой последовательность команд (операторов), отдельную от основной части программы и имеющую в конце специальную команду выхода из подпрограммы. Обычно подпрограмма имеет имя, по которому её можно вызвать, хотя ряд языков программирования допускает использование и неименованных подпрограмм. В языках высокого уровня описание подпрограммы обычно состоит по меньшей мере из двух частей: заголовка и тела. Заголовок подпрограммы описывает её имя и, возможно, параметры, то есть содержит информацию, необходимую для вызова подпрограммы. Тело - набор операторов, который будет выполнен всякий раз, когда подпрограмма будет вызвана.

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

    Формальные и фактические параметры. Чтобы отличать параметры подпрограммы, описанные в её заголовке и теле, от параметров, указываемых при вызове подпрограммы, первые принято называть формальными параметрами, вторые - фактическими параметрами.


    Подпрограмма – это блок кода между операторами Sub и End Sub или Function и end Function .

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

    Подпрограмма-процедура Sub и End Sub . Обычно подпрограмму-процедуру принято называть процедурой.

    При написании программы нужно учесть одно правило: «Внутри одной процедуры не может быть описана другая процедура».

    Процедура - это любая подпрограмма, которая не является функцией.

    Подпрограмма-функция – это блок кода, заключенный между операторами Function и End Function. Она выполняет какую-то операцию, но при этом обязательно возвращает какое-нибудь значение. Значение возвращается через имя функции.

    Функция - это подпрограмма специального вида, которая, кроме получения параметров, выполнения действий и передачи результатов работы через параметры имеет ещё одну возможность - она может возвращать результат. Вызов функции является, с точки зрения языка программирования, выражением, он может использоваться в других выражениях или в качестве правой части присваивания. Подробнее см. в статье Функция (программирование).

    Подпрограммы, входящие в состав классов в объектных языках программирования, обычно называются методами . Этим термином называют любые подпрограммы-члены класса, как функции, так и процедуры; когда требуется уточнение, говорят о методах-процедурах или методах-функциях.

    6.2.4 Принцип проектирования программ сверху-вниз и снизу–вверх.

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

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

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

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

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

    Программирование «сверху вниз », или пошаговая детализация. Суть метода заключается в разбиении исходной задачи на последовательность нескольких меньших подзадач. Эти подзадачи, в свою очередь, тоже распадаются на подзадачи и т. д. до тех пор, пока не останутся только элементарные алгоритмы.

    Пример. Чтобы написать число 512, сначала пишут цифру 5, затем 1 и, наконец, 2. При этом цифры рисуют, последовательно прорисовывая линии, из которых они состоят. Принтер напечатает это число точками.

    При разработке программы пошагово, методом «сверху вниз » сначала пишется текст основной программы, в котором, вместо каждого связного логического фрагмента текста, вставляется вызов подпрограммы, которая будет выполнять этот фрагмент. Вместо настоящих, работающих подпрограмм, в программу вставляются «заглушки», которые ничего не делают. Полученная программа проверяется и отлаживается. После того, как программист убедится, что подпрограммы вызываются в правильной последовательности (то есть общая структура программы верна), подпрограммы-заглушки последовательно заменяются на реально работающие, причём разработка каждой подпрограммы ведётся тем же методом, что и основной программы. Разработка заканчивается тогда, когда не останется ни одной «затычки», которая не была бы удалена. Такая последовательность гарантирует, что на каждом этапе разработки программист одновременно имеет дело с обозримым и понятным ему множеством фрагментов, и может быть уверен, что общая структура всех более высоких уровней программы верна. При сопровождении и внесении изменений в программу выясняется, в какие именно процедуры нужно внести изменения, и они вносятся, не затрагивая части программы, непосредственно не связанные с ними. Это позволяет гарантировать, что при внесении изменений и исправлении ошибок не выйдет из строя какая-то часть программы, находящаяся в данный момент вне зоны внимания программиста.

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

    Программирование «вширь» - ориентиром провозглашается набор однородных модулей. В одной программе может быть выявлено несколько однородных наборов. После того как однородные модули выявлены, приступают к непосредственному программированию, которое, собственно, и разбивается на этапы. На первом этапе создается лишь минимальное число представителей каждого из выделенных однородных наборов. Если поиск однородности проводился достаточно энергично, то обычно оказывается, что объем работ первого этапа реализации сравнительно невелик.

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

    Использование подпрограммы позволяет, во-первых, сократить объем программы, во-вторых, улучшает структуру программы с точки зрения ее читаемости и наглядности, в-третьих, уменьшает вероятность ошибок и облегчает процесс отладки.

    В языке Паскаль механизм подпрограмм реализуется в виде ПРОЦЕДУР и ФУНКЦИЙ, которые вводятся в программе с помощью своего описания, но их способом их использования.

    Процедура- это независимая часть программы, которую можно вызвать по имени для выполнения определенных действий. Процедура не может выступать как операнд в выражении. Упоминание имени процедуры в тексте программы приводит к активизации процедуры и называется ее вызовом. Например,

    Delay (10); вызывает задержку выполнения программы на 10мс.

    Функция аналогична процедуре, но имеются два отличия: функция передает в точку вызова скалярное значение; имя функции в выражении может выходить как операнд. Например, функция SQR(x)-возведет в квадрат значение целого или вещественного значения X и передаст в точку вызова вычисленное значение квадрата переменной X.

    Все процедуры и функции языка Паскаль делятся на две группы:

    à Встроенные (стандартные) - входят в состав языка и вызываются для выполнения по строго фиксированному имени.

    à Определенные пользователем – разрабатываются и имеются самим пользователем.

    При вызове подпрограммы, определенной программистом, работа главной программы на время приостанавливается и начинает выполняться вызванная подпрограмма.

    В программе процедуры и функции описываются после раздела ее переменных, но до начала ее основной части, то есть до Begin, начинающего эту часть.

    Передача данных из главной программы в подпрограмму и возврат результата выполнения функции осуществляется с помощью параметров.

    Параметром называется переменная, которой присваивается какое-либо значение в рамках указанного применения.

    Фактические параметры - это параметры, которые передаются подпрограмме при общении с ней.

    Формальные параметры – это переменные, фиктивно присутствующие в процедуре и определение тип и место подстановки фактических параметров, над которыми производятся действия.

    Параметры – переменные - это те формальные параметры, перед которыми стоит служебные слово Var. Они передаются по ссылке (передается адрес фактического параметра) тогда, когда необходимо передать некоторые новые значения в точку вызова процедуры из программы, то есть когда нужно, чтобы изменения в теле процедуры значений формальных параметров приводило к изменению соответствующих фактических параметров, таким образом, они и получают новое значение.

    Параметры – значения - перед ними слово Var не ставится и идет передача по значению, то есть передается только копия значения этих параметров, внутри процедуры можно производить любые действия с данными формальными параметрами (допустимы для его типа), но их любые изменения никак не отражаются на значениях соответствующих фактических параметров, никак не отражаются на значениях соответствующих фактических параметров, то есть какими они были до вызова процедуры, то такими же и останутся после завершения ее работы.

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

    Подпрограмма - именованная, логически законченная группа операторов языка, которую можно вызвать для выполнения любое количество раз из различных мест программы. В языке Free Pascal существуют два вида подпрограмм: процедуры и функции. Главное отличие процедуры от функции заключается в том, что результатом исполнения операторов, составляющих тело функции , всегда является некоторое значение , поэтому функцию можно использовать непосредственно в выражениях, наряду с переменными и константами.

    4.1 Общие сведения о подпрограммах. Локальные и глобальные переменные

    Итак, подпрограмма - это поименованный набор описаний и операторов, выполняющих определенную задачу. Информация , передаваемая в подпрограмму для обработки, называется параметрами, а результат вычислений - значениями. Обращение к подпрограмме называют вызовом. Перед вызовом подпрограмма должна быть обязательно описана в разделе описаний. Описание подпрограммы состоит из заголовка и тела. В заголовке объявляется имя подпрограммы, и в круглых скобках её параметры, если они есть. Для функции необходимо сообщить тип возвращаемого ею результата. Тело подпрограммы следует за заголовком и состоит из описаний и исполняемых операторов.

    Любая подпрограмма может содержать описание других подпрограмм. Константы , переменные, типы данных могут быть объявлены как в основной программе, так и в подпрограммах различной степени вложенности. Переменные, константы и типы, объявленные в основной программе до определения подпрограмм, называются глобальными, они доступны всем функциям и процедурам. Переменные, константы и типы, описанные в какой-либо подпрограмме, доступны только в ней и называются локальными.

    Для правильного определения области действия идентификаторов (переменных) необходимо придерживаться следующих правил:

    • каждая переменная, константа или тип должны быть описаны перед использованием;
    • областью действия переменной, константы или типа является та подпрограмма, в которой они описаны;
    • все имена в пределах подпрограммы, в которой они объявлены, должны быть уникальными и не должны совпадать с именем самой подпрограммы;
    • одноимённые локальные и глобальные переменные - это разные переменные, обращение к таким переменным в подпрограмме трактуется как обращение к локальным переменным (глобальные переменные недоступны);
    • при обращении к подпрограмме доступны объекты, которые объявлены в ней и до её описания.

    4.2 Формальные и фактические параметры. Передача параметров в подпрограмму

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

    Механизм передачи параметров обеспечивает обмен данных между формальными и фактическими параметрами, что позволяет выполнять подпрограмму с различными данными. Между фактическими параметрами в операторе вызова и формальными параметрами в заголовке подпрограммы устанавливается взаимно однозначное соответствие. Количество, типы и порядок следования формальных и фактических параметров должны совпадать.

    Передача параметров выполняется следующим образом. Вычисляются выражения, стоящие на месте фактических параметров. В памяти выделяется место под формальные параметры в соответствии с их типами. Выполняется проверка типов, и при их несоответствии выдается диагностическое сообщение . Если количество и типы формальных и фактических параметров совпадают, то начинает работать механизм передачи данных между фактическими и формальными параметрами.

    Формальные параметры процедуры можно разделить на два класса: параметры-значения и параметры-переменные.

    При передаче данных через параметры-значения в подпрограмму передаются значения фактических параметров, и доступа к самим фактическим параметрам из подпрограммы нет. При передаче данных параметры-переменные заменяют 1Реально в подпрограмму передаются адреса фактических параметров. формальные параметры, и, следовательно, в подпрограмме есть доступ к значениям фактических параметров. Любое изменение параметров-переменных в подпрограмме приводит к изменению соответствующих им формальных параметров. Следовательно, входные данные следует передавать через параметры-значения, для передачи изменяемых в результате работы подпрограммы данных следует использовать параметры-переменные.

    От общетеоретических положений перейдём к практическому использованию подпрограмм при решении задач. Изучение подпрограмм начнем с процедур.

    4.3 Процедуры

    Описание процедуры имеет вид:

    procedure имя_процедуры(список_формальных_параметров); label список_меток; const список_констант; type список_типов; var список_переменных; begin //Тело процедуры. end;

    Описание начинается с заголовка процедуры, где procedure - ключевое слово языка, имя_процедуры - любой допустимый в языке Free Pasacal идентификатор , список_формальных_параметров - имена формальных параметров и их типы, разделённые точкой с запятой. Рассмотрим примеры заголовков процедур с параметрами-значениями:

    procedure name_1(r: real ; i: integer ; c: char );

    Однотипные параметры могут быть перечислены через запятую:

    procedure name_2(a, b: real ; i, j, k: integer );

    Список формальных параметров необязателен и может отсутствовать:

    procedure name_3;

    Если в заголовке процедуры будут применяться параметры-переменные, то перед ними необходимо указывать служебное слово var :

    procedure name_4(x, y: real ; var z: real );

    //x, y - параметры-значения,

    //z - параметр - переменная .

    После заголовка идет тело процедуры , которое состоит из раздела описаний 2Раздел описаний в процедуре может отсутствовать, если в нём нет необходимости. ( константы , типы, переменные, процедуры и функции, используемые в процедуре) и операторов языка, реализующих алгоритм процедуры.

    Для обращения к процедуре необходимо использовать оператор вызова:

    имя_процедуры(список_фактических_параметров);

    Фактические параметры в списке оператора вызова отделяются друг от друга запятой:

    a: = 5. 3; k: = 2; s:= ’ a ’;

    name_1(a, k, s);

    Если в описании процедуры формальные параметры отсутствовали, то и при вызове их быть не должно:

    ЗАДАЧА 4.1. Найти действительные корни квадратного уравнения .

    Алгоритм решения этой задачи был подробно описан в задаче 3.3 (рис. 3.14). Однако там не была рассмотрена ситуация некорректного ввода значений коэффициентов. Например, если пользователь введёт , то уравнение из квадратного превратится в линейное. Алгоритм решения линейного уравнения тривиален: , при условии, что . Чтобы не усложнять уже составленный алгоритм решения квадратного уравнения, запишем его в виде подпрограммы-процедуры. Далее приведён фрагмент программы с комментариями:

    //Процедура для вычисления действительных //корней квадратного уравнения. procedure korni (a, b, c: real; var x1, x2: real; var pr: boolean); //Входные параметры процедуры: //a,b,c - коэффициенты квадратного уравнения; //Выходные параметры процедуры: //x1,x2 - корни квадратного уравнения, //pr - логическая переменная, //принимает значение "ложь", если в уравнении нет корней, //и значение "истина" в противном случае. var d: real; begin d:=b * b-4 * a * c; if d<0 then pr:= false else begin pr:= true; x1:=(-b+sqrt (d)) / 2 / a; x2:=(-b-sqrt (d)) / (2 * a); end end; //Конец подпрограммы //Основная программа var a_, b_, c_, x1_, x2_, x_ : real; pr_ : boolean; begin write (’a_:= ’); readln (a_); write (’b_:= ’); readln (b_); write (’c_:= ’); readln (c_); if a_=0 then //Если а=0, то уравнение //квадратным не является. begin //Решение линейного уравнения bx+c=0. if b_<>0 then begin x_:=-c_/b_; writeln (’ x= ’,x_); end else writeln (’Нет корней ’); end else //Решение квадратного уравнения ax^2 + bx + c = 0. begin korni (a_, b_, c_, x1_, x2_, pr_); //Вызов процедуры. if pr_=false then writeln (’Нет корней ’) else writeln (’ x1= ’,x1_, ’ _x2= ’,x2_); end; end.

    ЗАДАЧА 4.2. Вводится последовательность из целых положительных чисел. В каждом числе найти наибольшую и наименьшую цифры.

    Для решения задачи создадим процедуру max_min , результатом работы которой будут два значения: минимальная и максимальная цифры в заданном числе.

    Текст программы:

    //Процедура возвращает //max наибольшую и min наименьшую цифры в числе M. //В списке параметров: //M параметр-значение (входной параметр), //max и min параметры-переменные (выходные параметры). procedure max_min(M: longint; var max: byte; var min: byte); var i: byte; begin i: = 1; while M div 10>0 do begin if i =1 then begin //Предположим, что первая цифра является max:=M mod 10; //наибольшей или min:=M mod 10; //наименьшей. i:= i +1; end; //Поиск цифры больше max или меньше min. if M mod 10 > max then max:=M mod 10; if M mod 10 < min then min:=M mod 10; M:=M div 10; end; end; var X: longint; N, i,X_max, X_min: byte; begin //Количество элементов в последовательности. write (’N= ’); readln (N); for i:=1 to N do begin write (’X= ’); readln (X); //Элемент последовательности. if X>0 then //Если элемент положительный, то begin max_min(X,X_max, X_min); //вызов процедуры. //Печать результатов. writeln (’ max= ’,X_max, ’ min= ’,X_min); end; end; end.