Нетипизированные параметры
В Borland Pascal допускается использовать параметры, тип которых не указан. Такие параметры могут передаваться в подпрограмму только по ссылке, как параметры-переменные, так как в этом случае в подпрограмму реально передается адрес параметра.
Безусловно, для того чтобы подпрограмма могла выполнять какие-либо действия с этим параметром, она должна как-то назначить ему тип.
Для приведения нетипизированного параметра к определенному типу можно использовать:
§ автоопределенное преобразование типов;
§ наложенное описание переменной определенного типа.
При автоопределенном преобразовании типов тип выражения указывают явно, например:
Procedure Proc(Var:a);
... ...
b:= Integer (a)+10; ...
Для наложения переменной определенного типа используют описание с absolute, например:
Procedure Proc(Var:a);
...
Var
r:real absolute a;...
При этом переменная r оказывается в памяти размещенной в том же месте, что и нетипизированный параметр а, и, соответственно, любое изменение r приведет к изменению а.
Пример. Разработать подпрограмму, которая может суммировать как элементы массива целых чисел, так и элементы массива вещественных чисел.
Тип массива подпрограмма будет определять по значению третьего параметра, для которого объявим специальный перечисляемый тип. В разделе описаний подпрограммы определим шаблоны для каждого случая. Шаблон представляет собой описание массива соответствующего типа максимально возможного размера 64 Кб/<размер элемента>. Оба шаблона наложены по адресу нетипизированного параметра. Если значение третьего параметра подпрограммы treal, то используется шаблон mr, а если tinteger - шаблон mi.
Unit Summa4;
Interface
Type ttype=(treal, tinteger); {описание типа третьего параметра}
Function sum(var x;n:integer;t:ttype):real;
Implementation
Function sum;
Var mr:array[l..maxint*2 div sizeof(real)] of real absolute x;
mi:array[L.maxint*2 div sizeof(integer)J of integer absolute x;
s:real;
i:integer;
begin
s:=0;
if t=treal then
for i:=l to n do s:=s+mr[i] else
for i:-l to n do s:=s+mi[ij;
sum: =s;
end;
End.
Тестирующая программа вызывает одну и ту же функцию для суммирования массивов с разным типом элементов.
Program ex;
Uses Summa4;
Var a: array [1..10] of integer;
b:array[1..15] of real;
i,n: integer;
Begin
for i:=l to 10 do Read(a[i]);
ReadLn;
WriteLn('Cyммa= ',sum (a, 10, tinteger): 8: l);
for i:=l to 15 do Read(b[i]);
ReadLn;
WriteLn('Cyммa= ',sum (b, 15, treal):8:l);
end.
Вместо описания массива максимально возможного размера в подпрограмме можно описать массив длиной 1 элемент, но при работе с таким шаблоном необходимо отключать контроль индексов {$R-}.
Нетипизированные параметры можно применить для написания универсальных подпрограмм, использующих в качестве параметров многомерные массивы. Поскольку невозможно в подпрограмме определить универсальный шаблон многомерного массива, приходится обрабатывать многомерный массив как одномерный, учитывая то, что элементы многомерных массивов в памяти располагаются так, что чем правее индекс, тем быстрее он возрастает. Так элементы трехмерного массива В(2,3,2) будут расположены в памяти в следующем порядке:
b1,1,1, b1,1,2, b1,2,1, b1,2,2, b1,3,1, b1,3,,2, b2,1,1, b2,1,2, b2,2,1, b2,2,2, b2,3,1, b2,3,2.
Пример 2. Разработать универсальную подпрограмму транспонирования матрицы.
В одномерном массиве элемент с индексами i и j имеет индекс (i-l)*P+j, т.е. индекс этого элемента зависит от размера строки зарезервированной матрицы. В подпрограмму это значение передается через параметр Р.
Чтобы транспонировать матрицу, меняем местами элементы, расположенные ниже и выше главной диагонали.
При разработке алгоритма процедуры учтено, что при транспонировании матрицы по аналогии с переворотом строки количество перестановок равно n*n div 2. Если выполнить n*n перестановок, то матрица примет исходный вид, так как будет транспонирована дважды.
Unit Matrica;
Interface
Procedure tran(Var x;n,P:integer);
Implementation
Procedure Iran;
Var a:array[1..2*maxint div sizeof(real)] of real absolute x;
i,j:integer;
t:real;
begin
for i: =2 to n do
for j:=l to i-1 do
begin
t:=a[(i-l)*P+j];
a [(i-l) *P+j]. =a [j-l) *P+i],
a[(J-l)*P+i] := t;
end;
end;
End.
Тестирующая программа выглядит следующим образом:
Program ex;
Uses Matrica;
Var a: array [1 ..10,1. .10] of real;
i,j: integer;
Begin
WriteLn(‘Введите матрицу a(5*5):');
for i:=l to 5 do
begin
forj:=l to 5 do Read(afiJJ);
ReadLn;
end;
tran(a,5,10);•
WriteLn('Результат:');
for i:=I to 5 do
begin
forj:=l to 5 do Write(a[ij]:6:2);
WriteLn;
end;
End.
Процедурные типы
Параметры процедурного типа используют тогда, когда нужно передать в подпрограмму имена процедур и функций.
Для объявления процедурного типа используют заголовок подпрограммы, в котором отсутствует имя, например:
Type proc=procedure (a,b,c:real;Var d:real);
func=function(x:real) :real;
Значениями переменных процедурных типов являются идентификаторы процедур и функций с соответствующими заголовками:
Var f:func;
f:=funl;...
Процедуры или функции, идентификаторы которых будут передаваться в качестве параметров процедурного типа, по правилам языка необходимо компилировать в режиме дальнего вызова (с указанием директивы компилятора {$Р+}или служебного слова far). В этом режиме при вызове подпрограмм используются длинные 4-байтовые адреса в отличие от коротких 2-байтовых адресов, которые применяются для адресации подпрограмм, объявленных в основной программе или ее подпрограммах.
Если процедуры или функции описываются в интерфейсной части модуля, то по умолчанию они вызываются в режиме дальнего вызова, поэтому специально это оговаривать не надо.
2. Стандартные процедуры и функции, описанные в модуле System, по умолчанию являются функциями ближнего вызова. Если имена этих подпрограмм необходимо передавать через параметры, то надо описать собственную подпрограмму с указанием режима дальнего вызова, в теле которой будет находиться вызов стандартной подпрограммы, и использовать ее вместо стандартной подпрограммы.
Пример 3. Разработать подпрограмму, которая возвращает массив значений произвольной функции при заданных интервале изменения аргумента [а,b] и количестве точек n.
Имя функции будем передавать в подпрограмму через параметр процедурного типа. Массив значений будем описывать как открытый:
Unit SFun;
Interface
Typefunc=function(x:real):real;
Procedure TabFun(f:func;a, b:real;n: integer;Var Masf:array of real);
Implementation
Procedure TabFun;
Var
h,x:real;
r.integer;
Begin
h:=(b-a)/(n-l);
for i:=0 to n-1 do Masf[i]:=f(a+h*i);
End;
End.
Основная программа должна описать конкретную функцию как функцию дальнего вызова. Для функции sin создается специальная функция дальнего вызова.
Program ex;
Uses SFun;
Var
masFl :array[1.. 10] of real;
masF2: array [1.. 20] of real;
i: integer;
function Fl(x:real): real; far;
Begin
Fl:=sin(x);
end;
function F2(x:real) :real; far;
Begin
F2:=exp(x)+cos(x);
end;
Begin
WriteLn(' Таблица значений функции sin x:');
TabFun(Fl, 0,2,10,masFl);
for i:=l to 10 do Write(masFl[i]:7:l);
Writeln;
WriteLn(' Таблица значений функции ехр x+cos x:');
TabFun(F2, 0,2, 20, masF2); for i:=l to 20 do Write(masF2[i]:7:l);
Writeln;
End.
Рекурсия
В математике строгое определение некоторых понятий может опираться на то же понятие. Такие определения называют рекурсивными или индуктивными. Например, рекурсивно определяется факториал:
N! = 1, если N=0;
N*(N-l)!, если N>0.
Данное определение состоит из двух утверждений. Первое утверждение носит название базисного. Базисное утверждение нерекурсивно. Второе утверждение носит название рекурсивного или индуктивного. Оно строится так, чтобы полученная в результате повторных применений цепочка определений сходилась к базисному утверждению.
В программировании рекурсивной называется подпрограмма, которая в процессе выполнения вызывает, сама себя.
Дата добавления: 2015-12-01; просмотров: 1178;