Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Глава9.doc
Скачиваний:
1
Добавлен:
16.04.2019
Размер:
252.42 Кб
Скачать

9.4. Функции

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

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

Тип значения, вычисляемого функцией, задаётся в её заголовке, имеющем вид

function имя_функции (список формальных параметров):t;,

где t - тип вычисляемого значения.

Пример 9.4

Вычисление площади треугольника (см. пример 9.2) оформить в виде функции.

function tr1(ab, bc, ca : real ) : real ;

var

p : real ;

begin

p:=(ab + bc + ca) / 2;

tr1:=sqrt(p * (p - ab) * (p - bc) * (p - ca))

end;

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

П ример 9.5

Используя функцию tr1 (пример 9.4), решить задачу, приведённую в примере 9.3.

program example95;

var

a, b, c, d, e, f, s : real;

function tr1(ab, bc, ca : real ):real;

var

p : real;

begin

p:=(ab + bc + ca) / 2;

tr1:=sqrt (p * (p - ab) * (p - bc) * (p - ca))

end;

begin

readln (a, b, c, d, e, f);

s:=tr1 (a, b, c) + tr1 (a, d, e) + tr1(b, e, f) + tr1(c, f, d);

writeln ('s= ', s:10:2)

end.

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

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

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

9.5. Рекурсия

Под рекурсией (от лат. recursio - возвращение) понимают способ организации вычислительного процесса, который позволяет находить n-ный член какой-либо последовательности (чаще всего числовой), используя для этого один или несколько её предыдущих членов. Например, широко известный ряд чисел Фибоначчи 1, 1, 2, 3, 5, 8, ... для n > 2 вычисляется по рекуррентной формуле:

F(n) = F(n - 1) + F(n - 2)

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

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

Пример 9.6

Используя приведённую выше рекуррентную формулу, вычислить n!

program example96;

var

n, f : integer;

function factorial (m : integer) : integer ;

begin

if m=0 then factorial := 1

else factorial := factorial (m - 1) * m

end;

begin

readln (n); f:=fac (n);

write ('факториал ',n:2, '=',f:2)

end.

Замечание. Поскольку n! растет очень быстро, то при n > 7 полученные значения превышают максимально возможное значение типа integer (32767), поэтому рекомендуется n! считать как longint.

Программа содержит два обращения к функции factorial - одно в операторе вызова в главной программе, другое - в операторе присваивания в теле самой функции. Из главной программы функция вызывается один раз. При этом ей передаётся значение фактического параметра n. Для определённости допустим, что n = 3. Итак, функция начинает выполняться со значением формального параметра m = 3. Поскольку m  0, должна выполниться ветвь else оператора if, т.е. оператор присваивания factorial := factorial(2)*3. Но правая часть этого оператора содержит обращение к функции factorial, поэтому функция обратится сама к себе с параметром равным 2. Это в свою очередь приведёт к новому обращению к функции с фактическим параметром равным 1.

Таким образом, однократный вызов функции из главной программы приводит к цепочке последовательных незавершенных вызовов этой же функции самой себя. При этом в каждом последующем вызове используется значение формального параметра на 1 меньшее того, что использовалось в предыдущем. Все эти значения запоминаются в разных ячейках памяти. Так будет продолжаться до тех пор, пока значение функции не станет полностью определённым, что произойдёт при значении параметра m = 0. В этом случае будет выполнен оператор factorial := 1, после чего процесс вычисления факториала начнёт «раскручиваться» в обратную сторону, последовательно выполняя операторы:

factorial(1):=factorial (0)*1

factorial (2):=factorial (1)*2

factorial (3):=factorial (2)*3