Здесь 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;
¦ 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
Теперь можно эту функцию вызывать следующим образом:
а) Р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;
iF VALUE=0 then FACTORIAL:=1
else FACTORIAL:= VALUE*FACTORIAL(VALUE-1)
Теперь можно обращаться к этой функции в теле основной программы, как показано в следующем примере:
program FINDFACTORIAL;
var N:integer;
writeln('Введите число');
readln(N);
if N<0 then writeln('Нет факториала')
else writeln('Фактрориал',N,'равен',FACTORIAL(N))
Мы видим, что характерной особенностью построенной функции является наличие в ее теле оператора присваивания.
FACTORIAL:= VALUE*FACTORIAL(VALUE-1), где происходит вызов определяемой функции. Здесь идентификатор FACTORIAL в левой части оператора обозначает имя переменной для хранения значения функции, а в правой - имя вызываемой функции.
Важным моментом при составлении любой рекурсивной функции является организация выхода из рекурсии. В некоторых простых случаях должно существовать не рекурсивное решение. Рекурсивный процесс должен шаг за шагом так упрощать задачу, чтобы в конце концов для нее появилось не рекурсивное решение. В этих функциях должны проверяться значения аргумента для принятия решения о завершении. В нашем случае условием завершения рекурсии является VALUE=0.
При описании рекурсивных функций необходимо хорошо представлять процесс вычислений. Всякая рекурсия состоит из двух этапов: углубление (погружение) внутрь рекурсии и выход из нее. На первом этапе никаких вычислений не производится, а идет только настройка рабочей формулы на конкретные операнды. На втором этапе происходит процесс вычислений по настроенным формулам.
Рассмотрим рекурсивный процесс на примере вычисления факториала для N = 3. Получим следующие шаги:
1) N = 3, где N<>0, следовательно, FACTORIAL:=3*FACTORIAL(2);
2) N = 2, где N<>0, следовательно, FACTORIAL:=2*FACTORIAL(1);
3) N = 1, где N<>0, следовательно, FACTORIAL:=1*FACTORIAL(0);
4) N =0, следовательно, FACTORIAL:=1,
т.е. получили не рекурсивное значение. Углубление в рекурсию закончено, далее пойдет процесс выхода из нее с выполнением необходимых вычислений.
В выражение 1*FACTORIAL(0) вместо FACTORIAL(0) подставляется его значение 1, вычисляется произведение 1*1 и оно становится значением FACTORIAL(1). В выражение 2*FACTORIAL(1) вместо FACTORIAL(1) подставляется значение 1, вычисляется 2*1 и становится значением FACTORIAL(2). В выражение 3*FACTORIAL(2) вместо FACTORIAL(2) подставляется значение 2, вычисляется 3*2 и становится значением переменной FACTORIAL, которая возвращает в основную программу значение 3!.
Весь этот двухэтапный рекурсивный процесс реализуется в памяти ЭВМ с помощью организации в ней стека рекурсии. Дело в том, что для хранения значений переменной N (а значит, и переменной VALUE) отводится не одна ячейка, а стек с именем N. В этот стек последовательно заносятся значения 3, 2, 1, 0, причем значение 0 есть признак конца заполнения стека. Затем начинает работать цикл с телом FACTORIAL:= FACTORIAL * N, где значения N выбираются последовательно из стека в порядке 1,2,3. Исходным же значением переменной FACTORIAL является 1, как значение 0!.
Страницы: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39