Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
LR4-6.doc
Скачиваний:
80
Добавлен:
10.03.2016
Размер:
474.11 Кб
Скачать

Тема: Процедуры и функции

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

Название «подпрограмма» означает, что она подобна и подчинена программе.

Подпрограммы решают очень важные задачи, значительно облегчая программирование:

  1. избавляют от необходимости многократно повторять в тексте программы аналогичные фрагменты;

  2. улучшают структуру программы, облегчая ее понимание при разборе;

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

Подпрограммы могут быть:

  1. стандартными, т.е. определенными системой Паскаль;

  2. пользовательскими, т.е. разработанными собственно пользователем.

Существует два способа объединения подпрограмм и программ:

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

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

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

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

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

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

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

  • Полезно разбить длинную программу на составные части – просто как книгу разбивают на главы. При этом основная программа становится похожа на оглавление.

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

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

Структура текста подпрограммысоответствует структуре текста основной программы:

<заголовок подпрограммы>;

<раздел описаний>;

begin

<тело подпрограммы>

end;

Следует обратить внимание на два отличия в описании основной программы и подпрограммы:

  1. подпрограмма начинается с заголовка, содержащего имя подпрограммы, передаваемые в нее и возвращаемые от нее параметры. Заголовок подпрограммы отличается от заголовка основной программы;

  2. подпрограмма заканчивается точкой с запятой, а не точкой.

Чем отличаются процедуры и функции?

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

Заголовки процедуры и функции имеют вид:

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

Function<имя_функции> (<список формальных параметров>): <тип результата>;

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

Пример заголовков процедуры и функции:

Procedure primer1 (x, y: real; z: integer);

Function primer2 (n, m: byte): integer;

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

Отличия процедуры от функции связаны со способом вызова.

Для вызова процедурыприводится ее имя и в скобках приводится список передаваемых и получаемых параметров. Вызов процедуры – оператор(это важно!).

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

Пример обращения к процедуре и функции:

Primer1 (sin(2),k, 3); {обращение к процедуре, используется как оператор}

F:=primer2 (i, 2*j); {обращение к функции, используется как операнд выражения}

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

Передача параметров по ссылке и по значению

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

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

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

Пример описания формальных параметров, передаваемых по значению:

Procedure primer (x, y: integer; z: real);

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

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

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

Пример описания формальных параметров, передаваемых по ссылке:

Procedure primer1 (var k,l: byte; var d: integer);

Решение задачи с использованием подпрограмм

Задача: треугольник задан координатами своих вершин. Составить программу вычисления его площади.

Решение этой задачи удобно представить в виде следующих этапов:

  1. Ввод последовательно координат трех вершин: x1,y1,x2,y2,x3,y3.

  2. Вычисление длины первой стороны

  3. Вычисление длины второй стороны

  4. Вычисление длины третьей стороны

  5. Вычисление площади по формуле Герона

  6. Вывод на экран полученного значения площади.

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

Итак, пусть наша функция называется storona. Для вычисления стороны треугольника нужно передать в подпрограмму координаты двух вершин. Пусть формальные параметры называютсяa1,b1,a2,b2 и имеют вещественный тип (real). Тип результата функции также будет вещественным.

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

Programtreugolnik;

Var

S,a,b,c,p:real; {описываем переменные для вычисления площади (S), сторон (a,b,c), периметра (p)}

X1,y1,x2,y2,x3,y3:real; {описываем переменные – координаты вершин}

Functionstorona(a1,b1,a2,b2:real):real; {заголовок функции, в которой будет вычисляться длина стороны треугольника}

Begin

End; {конец функции. Пока тело функции пусто, детали вычислений запишем чуть позже. Зато к этой функции уже можно обращаться из основной программы}

Begin{начало основной программы}

Writeln(‘Введите координаты первой вершины’);

Readln (x1, y1);

Writeln(‘Введите координаты второй вершины’);

Readln (x2, y2);

Writeln(‘Введите координаты третьей вершины’);

Readln (x3, y3);

A:=storona(x1,y1,x2,y2); {вычисляем длину первой стороны}

B:=storona(x2,y2,x3,y3); {вычисляем длину второй стороны}

C:=storona(x3,y3,x1,y1); {вычисляем длину третьей стороны}

P:=a+b+c; {вычисляем периметр}

S:= sqrt(p/2*(p/2-a)*(p/2-b)*(p/2-c));

Writeln(‘площадь треугольника равна:’,s);

End.

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

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

Function storona (a1, b1, a2, b2: real): real;

Vard:real; {описание переменной, которая будет использоваться исключительно внутри функции}

Begin

D:= sqrt(sqr(a1- a2) +sqr(b1-b2));

Storona:=d; {обязательный в теле функции оператор присваивания, когда с именем функции связывается вычисленное значение}

End;

Вот теперь наша задача полностью решена.

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

Пусть наша процедура называется dlina. Для вычисления длины стороны треугольника в процедуру необходимо передать значения координат двух вершин, поэтому в списке формальных параметров в заголовке процедуры нужно описать 4 параметра-значения вещественного типа:a1,b1,a2,b2. Для передачи полученного значения в основную программу нужно описать в заголовке параметр-переменную, принимающий ссылку, назовем этот параметрd(необходимо помнить, что в заголовке процедуры перед этим параметром ставится служебное словоvar).

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

Programtreugolnik;

Var

S,a,b,c,p:real; {описываем переменные для вычисления площади (S), сторон (a,b,c), периметра (p)}

X1,y1,x2,y2,x3,y3:real; {описываем переменные – координаты вершин}

Proceduredlina(a1,b1,a2,b2:real;vard:real); {заголовок процедуры, в которой будет вычисляться длина стороны треугольника}

Begin

End; {конец процедуры. Пока тело процедуры пусто, детали вычислений запишем чуть позже. Зато к этой процедуре уже можно обращаться из основной программы}

Begin{начало основной программы}

Writeln(‘Введите координаты первой вершины’);

Readln (x1, y1);

Writeln(‘Введите координаты второй вершины’);

Readln (x2, y2);

Writeln(‘Введите координаты третьей вершины’);

Readln (x3, y3);

dlina(x1,y1,x2,y2,a); {вычисляем длину первой стороны, при этомx1,y1,x2,y2 будут передавать копии своих значений в процедуру, а переменнаяaбудет принимать полученный результат}

dlina(x2,y2,x3,y3,b); {вычисляем длину второй стороны, при этомx2,y2,x3,y3 будут передавать копии своих значений в процедуру, а переменнаяbбудет принимать полученный результат }

dlina(x3,y3,x1,y1,c); {вычисляем длину третьей стороны, при этомx3,y3,x1,y1 будут передавать копии своих значений в процедуру, а переменнаяcбудет принимать полученный результат}

P:=a+b+c; {вычисляем периметр}

S:= sqrt(p/2*(p/2-a)*(p/2-b)*(p/2-c));

Writeln(‘площадь треугольника равна:’,s);

End.

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

Теперь можно наполнить содержанием саму процедуру:

Procedure dlina (a1, b1, a2, b2: real; var d: real);

Begin

D:= sqrt(sqr(a1- a2) +sqr(b1-b2));

End;

Область действия переменных, взаимодействие блоков

В программе может быть описано сколько угодно блоков (подпрограмм). Внутри этих блоков могут быть описания других блоков. Важно знать, откуда и какие блоки могут быть вызваны.

«Блок – это дом с зеркальными стенами. Изнутри видно все, что делается снаружи. Внутрь заглянуть нельзя».

Рассмотрим программу с процедурами различного уровня вложенности. Мы получим иерархию описаний:

Program osnovn;

Procedure A;

Procedure A1;

……….

Begin…… end; {A1}

Procedure A2;

………..

begin ……end; {A2}

begin

………

end; {A}

procedure B;

procedure B1;

………

begin ……. end; {B1}

procedure B2;

procedure B21;

………..

begin ..end; {B21}

begin …….. end; {B2}

begin …………end; {B}

begin{начало основной программы}

………end. {конец основной программы}

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

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

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

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

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

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

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

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

Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]