Процедуры в языке Pascal

 

п. 1. Что такое процедура и зачем она нужна

Часто некоторую последовательность действий требуется повторить в нескольких местах программы. Чтобы не тратить время и усилия на копирование, в языке программирования Pascal предусмотрены средства для организации подпрограмм. Программист имеет возможность присвоить последовательности операторов некоторое имя и использовать это имя в качестве сокращенной записи в тех местах, где встречается соответствующая последовательность действий. Таким образом, ПРОЦЕДУРА - это именованная последовательность операторов.

Использование процедур позволяет:

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

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

3) Разбиение программы на отдельные связанные процедуры позволяет также вести разработку коллективу программистов. Наконец, если в нескольких местах программы последовательности операторов близки, но не идентичны, то задавая параметры в процедуре, ее можно настроить на конкретное выполнение.

В сущности вы уже пользовались процедурами, когда записывали команды ввода и вывода. Read, Readln, WriteиWriteln–этотоже процедуры. Но они уже готовы и мы пользуемся ими, даже незадумываясь, как они реализованы. Это так называемые стандартные процедуры, которые поставляются вместе с транслятором языка PASCAL. Кроме стандартных процедур в языке предусмотрено создание своих (пользовательских) процедур.

 

п. 2. Описание процедуры

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

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

Program Name;

...

{Разделы описания меток, констант, типов и переменных}

...

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

{Раздел описаний}

Begin

{Раздел операторов};

end;

 

Begin {Начало тела программы}

 

... {Тело программы, операторы};

 

End.

 

За заголовком могут идти такие же разделы, что и в основной программе (описание констант, типов, переменных, процедур...).В отличие от основной программы процедура завершается не точкой,а точкой с запятой.

 

п. 3. Примеры процедуры

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

Пр. Найти максимальное из 4 чисел. Закончить программу когда все числа равны 0.

 

program MAX4;

var A,B,C,D,R1,R2,R3:integer;

{ ОПИСАHИЕПPОЦЕДУPЫ MAX }

procedure MAX(N1,N2:integer; Var R:integer);

{ Пpоцедуpа находит максимальное из двух заданных чисел }

{ ПАPАМЕТPЫ пpоцедуpы }

{ Входные паpаметpы: N1 и N2 - заданные числа }

{ Выходной паpаметp: R - значение максимального числа }

begin

if N1>N2 then R:=N1 else R:=N2

end;

{ - начало тела главной программы}

begin

writeln('<<< НАХОЖДЕНИЕ МАКСИМАЛЬНОГО ИЗ ЧЕТЫPЕХ ЦЕЛЫХ ЧИСЕЛ >>>');

writeln;

writeln(' программа закончит работу, если все числа равны 0');

writeln;

repeat

write('Первоечисло =? '); readln(A);

write('Втоpоечисло =? '); readln(B);

write('Тpетьечисло =? '); readln(C);

write('Четвеpтоечисло =? '); readln(D);

if (A=B) and (B=C) and (C=D) then writeln(' всечисла pавны')

else

begin

Max(A,B,R1); |

Max(C,D,R2); | вызовы процедур

Max(R1,R2,R3); |

writeln('Максимальное число = ',R3);

writeln

end

until (A=0) and (B=0)and (c=0) and(d=0);

end.

 

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

Program Name;

...

{Разделы описания меток, констант, типов и переменных}

...

Procedure Line(ch:char;ln:integer);

var

symbol:integer;

Begin {Началотелапроцедуры}

For symbol:=1 to ln do

Write (ch);

end; {Конец тела процедуры}

 

Begin {Начало тела программы}

...

read(a,b); {Задаются символ и длина строки}

line(a,b); {Вызовпроцедуры}

...

End.

 

 

п.4. Параметры процедуры

 

Procedure <имя>(список парам1:тип1;список парам2:тип2,...;

var список перем1:тип1; var список перм2:тип2,...);

 

Параметры, описанные в заголовке процедуры, называются ФОРМАЛЬНЫМИ. Они указывают, с какими параметрами можно обращаться к этой процедуре (количество, их последовательность, типы). В заголовке процедуры они задаются в виде списка.Параметры, задающиеся при вызове процедуры в самой программе называются ФАКТИЧЕСКИМИ. Каждый из формальных параметров может принадлежать к одной из следующих категорий:

- 1) параметры-значения (эти параметры в подпрограмме не могут меняться, их называют входными параметрами);

- 2) параметры-переменные (эти параметры могут изменить свое значение в процедуре, поэтому их используют для результатов работы процедуры и называют выходными);

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

Списку параметров-переменных должно предшествовать ключевое слово Var. Действие слова Var распространяется до ближайшей точки с запятой. Рекомендуется сначала в списке параметров указывать входные параметры, затем выходные. Отделяются эти группы друг от друга точкой с запятой.

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

Рассмотрим примеры заголовков процедур.

 

Procedure Ar(A:integer;B,C:real; Var d:boolean);

Этот заголовок указывает, что в процедуре три входных параметра и один выходной.

 

Procedure Br(A:integer);

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

 

Procedure Gr(Var G:real);

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

 

Procedure Cr;

Это процедура без параметров. Примером процедуры без параметров может служить процедура чистки экрана.

 

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

ProcedureMix(A:array[1..100] ofreal);

Для того, чтобы правильно записать заголовок, потребуется восновной программе ввести новый тип:

Type mas=array[1..100] of real;

После чего заголовок будет иметь вид:

Procedure Mix(A:mas);

 

п.5. Глобальные и локальные описания

При использовании процедур возникает разделение данных на

1) глобальные и 2) локальные. Глобальные константы, типы, переменные -это те, которые объявлены в программе вне процедур. Локальные -это те описания, которые описаны внутри процедуры. Обмен информацией между основной программой и процедурой может осуществляться только с помощью глобальных параметров.

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

 

п.6. Вызов процедуры

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

Например, если мы имеем процедуру, которая вычисляет значение заданного числа в заданной степени и имеет заголовок:

Procedure ST(A:real; N:integer; Var Rez:real);

где A - заданное число;

N - степень числа;

REZ - значение N-ой степени числа А.

 

Вызов процедуры может иметь вид:

 

ST(10.5,9,D);

Эта запись означает, что требуется вычислить девятую степень числа 10.5 Входные параметры задаются в виде значений. Результат вычисления будет записан в переменную D, которая должна иметь тип real.

Вызов процедуры может иметь и следующий вид:

ST(A1,A2,A3);

ST(A1,7,A3);

ST(Num,S+1,R);

 

Подчеркиваем еще раз, что количество фактических параметров, их последовательность и тип должны совпадать со списком формальных параметров.

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

 

п.7. Опережающее описание

Можно ли использовать ранее описанную подпрограмму в другой подрограмме?? Да можно. Так как она описана выше, то след подпрограмма ее видит. А вот можно ли сделать наоборот,т.е. использовать в подпрограмме еще не описанную подпрограмму, которая будет потом описана ниже? Выход из этого затруднения предоставляет так называемое опережающее описание.

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

Пример. Составить в программе процедуры, кот. могут использовать сами

себя.

 

Program K;

var i:integer: j:real;

procedure a(x:integer); forward; {Опережающееописание}

procedure b(y:real);

begin {Началотелапроцедуры}

...

a(i); {Вызов еще не определенной процедуры}

end; {Конецтелапроцедуры}

 

procedure a;

begin {Начало тела процедуры}

...

b(j);

end; {Конец тела процедуры}

 

Begin {Начало тела программы}

...

read(c,d);

a(c);

b(d);

...

End.

Пример.

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

 

Program Krug;

 

Var

Rad,S:real;

Procedure ploschad(r:real;var pl:real);

begin

pl:=pi*r*r;

end;

Begin

Write('введитезначениеRad: ');

Readln(Rad);

ploschad(Rad,S);

Writeln('площадькругаравна: ',S:6:3);

Writeln('для выхода нажми ввод');

Readln;

End.

 

ПОДПРОГРАММЫ-ФУНКЦИИ

 

п.1. Описание подпрограммы-функции

 

В математике понятие функции хорошо известно - с помощью функций задаются зависимости одних значений (значений функций) от других значений, называемых аргументами. В языке Pascal вводится понятие подпрограммы-функции, которые часто называют просто функциями. Вы уже знакомы с этим на практике, т.к. наверняка использовали стандартные функции, такие как sin(x), cos(x), abs(x) ит.д.

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

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

 

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

 

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

1)любого порядкового,

2) любого вещественного,

3) стандартного типа String,

4) любого указателя (рассмотрим позднее).

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

 

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

Program Stepen;

...

{Разделы описания меток, констант, типов и переменных}

...

Function power(num,pow:integer):integer;

var

i:integer;

a:real;

Begin {Начало тела функции}

a:=1;

for i:=1 to pow do

a:=a*num;

power:=num

end; {Конецтелафункции}

...

Begin {Начало тела программы}

...

read(a,b);

x:=power(a,b)+y; {Вызовфункции}

...

End.

 

Рассмотрим пример вычисления факториала числа N. Известно, что N! = N*(N-1)*(N-2)*(N-3)*...*2*1

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

 

Function Factorial(N:Byte):Longint;

var Fact:Longint;

i:Byte;

begin

Fact:=N;

for i:=N-1 downto 2 do

Fact:=Fact*i;

Factorial:=Fact

end;

 

п. 2. Вызов подпрограммы-функции

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

Так вызов вышеописанной функции Factorial может иметь следующийвид:

 

Part:=Factorial(20)/b;

Вызывается функция Factorial с фактическим параметром 20 (параметр-значение)

 

Part:=Factorial(M)+c/2;

Вызывается функция Factorial с фактическим параметром М(параметр-переменная)

 

Part:=Factorial(M+L);

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

 

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

program Energy;

var

m,v,f:real;

function En(a,b:real):real;

Begin

En:=a*sqr(b)/2;

end;

begin

writeln('Вводмассытела');

readln(m);

writeln('Ввод скорости тела');

readln(v);

f:=En(m,v);

writeln('Значение кинетической энергии');

writeln(f:4:1,'Дж');

Readln;

End.

 

 

п.3. Рекурсивные процедуры и функции

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

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

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

Function Factorial(N:Byte): Longint;

begin

if N in [0..1]

then Factorial:=1

else Factorial:=N*Factorial(N-1)

end.

Рассмотрим работу данной функции на примере вызова функции Factorial(3) в основной программе.

При входе в подпрограмму-функцию по этому вызову фактический параметр равен 3. При выполнении функции выполняется оператор Factorial:=3*Factorial(2). При этом происходит вызов функции Factorial c фактическим параметром 2 (Factorial(2)) При выполнении функции выполняется оператор Factorial:=2*Factorial(1). При этом происходит вызов функции Factorial с фактическим параметром 1 (Factorial(1)). При выполнении функции

выполняется оператор Factorial:=1. После этого завершается выполнение оператора Factorial:=2*Factorial(1), что дает значение Factorial(2)=2 и,наконец, завершается выполнение оператора Factorial(3):=3*Factorial(2), чтодаетзначениеFactorial(3)=3*6=18.

Как вы видите на данном примере, рекурсивный алгоритм выглядит короче и нагляднее.

Отрицательные стороны рекурсивных функций:

1) на вычисление рекурсивной функции уходит больше машинного времени (за счет повторных обращений к подпрограмме);

2)требуется больше времени (за счет дублирования локализованных в процедуре переменных);

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

чему отдать предпочтение - эффективности или ее компактности.

 

Пример. Составить программу вычисления и печати таблицы значений двух заданных функций при указанных с клавиатуры начальном и конечном значениях и шаге изменения аргумента. Вычисление первой функции Y=sin2x оформить при помощи процедуры, второй y=1.5*x^3 --- при помощи финкции.

 

program pr;

var

a,b,c,y,m:real;

procedure F1(x:real;var y:real);

Begin

y:=sin(2*x);

end;

function F2(x:real):real;

begin

F2:=1.5*sqr(x)*x;

end;

Begin

writeln('Ввод начального значения параметра');

readln(a);

writeln('Ввод конечного значения параметра');

readln(b);

writeln('Ввод шага функции');

readln(c);

m:=a;

writeln('==================================');

writeln('Функцияномер 1');

while m<=b do begin

F1(m,y);

writeln('при x=',m:3:1,' y=',y:8:3);

m:=m+c;

end;

m:=a;

writeln('=================================');

writeln('Функцияномер 2');

while m<=b do begin

y:=F2(m);

writeln('при x=',m:3:1,' y=',y:8:3);

m:=m+c;

end;

writeln('================================');

end.

 

 

 


Понравилась статья? Добавь ее в закладку (CTRL+D) и не забудь поделиться с друзьями:  



double arrow
Сейчас читают про: