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 в заголовке процедуры) приведет к тому, что результат работы процедуры не будет возвращен в основную программу. Это происходит потому, что характер "поведения" параметров-значений и параметров-переменных в процессе работы процедуры различен. Разница эта состоит в том, что преобразования, которые претерпевают формальные параметры-значения в процедуре, не вызывают изменения соответствующих им фактических параметров, в то время как изменения параметров-переменных может изменять значения соответствующих фактических параметров.
Причиной этого феномена является неодинаковое распределение памяти под хранение параметров процедуры. Формальному параметру-значению отводится некоторая область (ячейка) памяти, куда заносится значение соответствующего фактического параметра, вычисленного на момент обращения к процедуре. На этом связь между ними обрывается. Действительно, если фактическим параметром является константа или выражение, как изменения в формальном параметре-значении (а это есть всегда переменная) могут повлиять, например, на выражение.
Фактическим же параметром, соответствующим формальному параметру-переменной, является всегда переменная. На время выполнения процедуры эти параметры отождествляются, им соответствует одна и та же область памяти. Вполне понятно, что в этой ситуации изменения формального параметра влекут адекватные изменения фактического параметра, и после завершения процедуры его значение может отличаться от его первоначального значения.
Именно поэтому, объявив в процедуре параметр-результат как параметр-значение, этот результат так и останется в формальном параметре-переменной без его передачи в соответствующий фактический параметр.
Функция как объект языка Паскаль является другой версией реализации технологии построения программ с использованием структуры группирования. Можно также сказать, что функция есть частный вид определенного типа процедур, а именно, процедур с одним параметром - переменной.
Функция отличается от процедуры только тем, что всегда возвращает в точку вызова одно скалярное значение. При этом функция, как процедура, может содержать параметры-значения или быть без оных. Общая форма записи заголовка функции:
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.