Смекни!
smekni.com

Алгоритмический язык Паскаль (стр. 7 из 31)

var J,K: integer;

begin

for J:=1 to N do write('*'); writeln;

for J:=1 to N-2 do

begin

write('*'); for K:=1 to N-2 do write(' ');

writeln('*');

end;

for J:=1 to N do write('*');

end;

begin { Основная программа }

write('Введите длину стороны - ');

readln(I); clrscr; KVADRAT(I);

end.

ПРИМЕР 2. Вычисление площади четырехугольника с применением процедуры с параметрами-значениями:

program PLOCHAD_2;

var AB,BC,CD,AD,AC,S1,S: real;

procedure GERON_2(a,b,c: real);

var P: real;

begin

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

end;

begin {*ОСНОВНАЯПРОГРАММА*}

read (AB,BC,CD,AD,AC); GERON_2(AB,BC,AC); S1:= S;

GERON_2(AD,AC,CD); write ('S = ', S1+S)

end.

В данной программе определена процедура GERON_2 с тремя параметрами-значениями и локальной переменной P. Значение же площади треугольника помещается в глобальную переменную S. При вызове этой процедуры формальные параметры a, b, c замещаются на фактические параметры AB, BC, AC при первом обращении, и на AD, AC, CD - при втором.

Заметим также, что здесь фактические параметры представлены переменными, которые получают свое значение с помощью процедуры READ. Однако, если известны длины сторон треугольника, например, 6, 7, 4, то можно вычислить площадь этого треугольника, вызвав процедуру GERON_2(6,7,4), и получить ответ в переменной S.

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

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

Например:

PROCEDURE PRIMER(VAR a,b,c:INTEGER; VAR m:CHAR; VAR i,j:REAL);

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

ПРИМЕР 1. Обмен значениями переменных A и B

program ZERKALO;

var A,B: integer;

procedure OBMEN(var X,Y: integer);

begin X:= B; Y:= A end;

begin

A:= 1; B:= 2; writeln(A,B);

OBMEN(A,B); write(A,B);

end.

ПРИМЕР 2. Вычисление площади четырехугольника

program PLOCHAD_3;

var AB,BC,CD,AD,AC,S1,S2,a,b,c: real;

procedure GERON_3(var S: real);

var P: real;

begin

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

end;

begin { Основнаяпрограмма }

read (AB,BC,CD,AD,AC);

a:=AB; b:= BC; c:= AC; GERON_3(S1);

a:=AD; b:= AC; c:= CD; GERON_3(S2);

write ('S = ', S1+S2)

end.

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

НАПРИМЕР:

PROCEDURE PRIMER(VAR a,b,c:INTEGER; m:CHAR; VAR i,j:REAL);

Здесь a,b,c,i,j - параметры-результаты (переменные);

m - пераметр-аргумент (значение).

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

program PLOCHAD_4;

var AB,BC,CD,AD,AC,S1,S2: real;

procedure GERON_4(a,b,c:real; var S: real);

var P: real;

begin

P:= (a+b+c)/2;

S:= sqrt(P*(P-a)*(P-b)*(P-c));

end;

begin {*ОСНОВНАЯПРОГРАММА*}

read (AB,BC,CD,AD,AC);

GERON_4(AB,BC,AC,S1);

GERON_4(AD,AC,CD,S2);

write ('S = ', S1+S2)

end.

ПРИМЕЧАНИЕ. Для более полного усвоения введенных ранее терминов перечислим на базе последнего примера все виды параметров и переменных:

- глобальные переменные AB, BC, CD, AD, AC, S1, S2;

- локальные переменные a, b, c, S, P;

- формальные параметры a, b, c, S;

a) параметры-значения (аргументы) a,b,c;

б) параметр-переменная (результат) S;

- фактические параметры AB, BC, CD, AD, AC, S1, S2;

a) параметры-значения (аргументы) AB, BC, CD, AD, AC;

б) параметры-переменные (результаты) S1,S2.

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

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

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

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

5.2 Функции пользователя. Рекурсивные функции

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

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

FUNCTION имя (список параметров: тип): тип;

или

FUNCTION имя: тип;

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

Итак, заголовок функции отличается от заголовка процедуры не только сменой слова PROCEDURE на FUNCTION, но и удалением из списка параметров параметра-результата с присвоением его типа имени функции:

PROCEDURE <имя процедуры>(аргументы; VAR параметр-результат: тип);

| |

¾¾¾¾¾¬¾¾¾¾¬¾¾¾¾

FUNCTION <имя функции> (аргументы): тип;

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

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

Известно, что Паскаль имеет набор стандартных функций. Однако этот набор ограничен. Пользователь может по желанию расширить список функций, создав свои функции - функции пользователя. Так, например, в Паскале есть SQR(X) = X2, а вот функции F(X)= Xn, где n принадлежит множеству целых чисел Z, нет. Используя определенное ранее понятие функции, можно создать для этого универсальную функцию, которая давала бы степени произвольного вещественного числа с любым целым показателем.

Определим вещественную функцию POWER, которая должна иметь два параметра-аргумента - для показателя и для основания степени:

function POWER (FACTOR:real;EXPONENT:integer):real;

var COUNT: integer; TFACTOR: real;

begin

¦ if EXPONENT = 0 then POWER:= 1

¦ else begin

¦ ¦ TFACTOR:= FACTOR;

¦ ¦ for COUNT:= 2 to ABS(EXPONENT) do

¦ ¦ TFACTOR:= TFACTOR*FACTOR;

¦ ¦ if EXPONENT<0 then POWER:= 1/TFACTOR

¦ ¦ else POWER:= TFACTOR

¦ end

end;

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

а) РI:=POWER(3.14,1);

б) WRITELN("PI=",POWER(3.14,1):5:2);

в) IF X > 2*POWER(6.2,3) THEN WRITE('ДА');

г) A:= POWER(X,2) + POWER(X,3) + POWER(X,4).

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

В математике известно рекурсивное определение факториала:

n! = 1, при n = 0;

n! = (n-1)!×n, при n > 0.

Это рекурсивное определение можно реализовать с помощью соответствующей рекурсивной функции:

function FACTORIAL(VALUE:integer):integer;

begin

iF VALUE=0 then FACTORIAL:=1

else FACTORIAL:= VALUE*FACTORIAL(VALUE-1)

end;

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

program FINDFACTORIAL;

var N:integer;

begin

writeln('Введитечисло');

readln(N);

if N<0 then writeln('Нетфакториала')

else writeln('Фактрориал',N,'равен',FACTORIAL(N))

end.

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

FACTORIAL:= VALUE*FACTORIAL(VALUE-1), где происходит вызов определяемой функции. Здесь идентификатор FACTORIAL в левой части оператора обозначает имя переменной для хранения значения функции, а в правой - имя вызываемой функции.

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