Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Информатика 2 семестр.doc
Скачиваний:
5
Добавлен:
01.04.2025
Размер:
609.28 Кб
Скачать

1.3.5. Массивы и строки открытого типа

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

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

Пример 8. Применить параметр массив открытого типа к примеру 7.

program Otkr_Massiv;

const {Задаем исходные массивы}

a : array[6..10] of real = (1, 2, 3, 4, 5);

b : array[1..4] of real = (6, 7, 8, 9);

function Sum_Otkr(z : array of real) : real; {z - массив открытого типа}

var i : byte; s : real;

begin s := 0;

for i := 0 to High(z) do {Нумерация элементов z от нуля!}

s := s + z[i];

Sum_Otkr := s end; {Sum_Otkr}

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

writeln(‘Сумма элементов вектора a = ’, Sum_Otkr(a) : 2 : 0);

writeln(‘Сумма элементов вектора b = ’, Sum_Otkr(b) : 2 : 0);

end.

Итак, массив открытого типа позволяет сократить число передаваемых в подпрограмму параметров.

Для описания в заголовке подпрограммы строки открытого типа используется специально введенный тип данных - OpenString. Можно также применять тип String в сочетании с ключом {$P+}, указываемым перед заголовком подпрограммы. Данный параметр также может быть параметром-константой, параметром-значением и параметром-переменной.

1.4. Рекурсивные подпрограммы

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

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

procedure Q(y : tt);

… {Описание локальных объектов процедуры Q}

begin

… {Набор действий}

P(a);

… {Набор действий}

end; { Q }

procedure P; {Сокращенный заголовок }

… {Описание локальных объектов процедуры P}

begin

… {Набор действий}

Q(b);

… {Набор действий}

end; { P }

Рассмотрим прямую рекурсию более подробно. Начнем с классического примера рекурсии – функции вычисления факториала. Воспользуемся очевидным представлением: k! = k(k-1)! = … = k(k-1)0!. При описании действий в рекурсивной подпрограмме обязательно должна присутствовать терминальная ситуация, в которой результат получается без рекурсивного обращения, т.е. он известен либо по определению, либо из логики вычислительного процесса. В нашем случае в качестве терминальной выступает ситуация, когда значение факториала числа известно – это 0! = 1.

Function fac(k : byte) : longint;

begin

if k = 0 then fac := 1 {Терминальная ситуация}

else fac := k * fac(k-1)

end;

Заметим, что с помощью этой функции можно вычислить факториалы чисел, не превышающих 12, т.к. результат будет соответствовать диапазону значений типа longint. Для больших значений аргумента k следует использовать тип real для описания значений, возвращаемых функцией fac. Следует обратить внимание на то, что все промежуточные значения k будут помещаться в стек (k – это параметр-значение), откуда они начнут извлекаться по достижении терминальной ситуации. Если таких значений много, то стек может переполняться.

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

program preobrazovanie;

uses Crt;

var

n : longint;

procedure dvb(k : longint);

begin

if K > 0 then { k = 0 – это терминальная ситуация }

begin

dvb(k div 2); { Рекуpсивное обpащение пpоцедуpы к самой себе }

write(k mod 2)

end

end; {dvb}

begin

clrscr;

writeln('Введите натуральное число');

readln(n);

writeln('Двоичный код этого числа:');

dvb(n);

writeln;

writeln('Нажмите ENTER');

readln

end.

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

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

Пример 9. Уточнить с погрешностью 0,0001 корень уравнения

ln(x)-x + 1,8 = 0 на отрезке [2, 3] методом дихотомии.

program rec_dih;

const

e = 0.0001;

var a, b, x : real;

function f(s : real) : real;

begin f := ln(s) - s + 1.8 end; {Решаемое уравнение}

function R_Dihotom(x : real) : real; {Рекуpсивная функция}

begin

if abs(f(x)) < e then R_Dihotom := x

else begin

x := (a + b)/2; {Делим отрезок пополам }

if f(a) * f(x) < 0 then b := x {и выбираем ту его половину,}

else a := x; {на которой функция меняет знак}

R_Dihotom := R_Dihotom(x) {Рекурсивное обращение}

end

end;

begin

writeln('Введите гpаницы отpезка');

readln(a, b);

x := R_Dihotom((a + b)/2);

writeln('коpень = ', x : 6 : 4);

writeln('Пpи этом функция = ', f(x) : 6 : 4);

writeln('Нажмите ENTER');

readln

end.