Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Turbo Pascal / Stud_1_1 / LecRus / MainPart.doc
Скачиваний:
116
Добавлен:
03.03.2016
Размер:
5.03 Mб
Скачать

Обработка в процедуре одномерных массивов с различными именами типов

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

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

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

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

Program Middle1;

Type Xar = array[1..50] of real;

Yar = array[1..500] of real;

Zar = array[1..5000] of real;

Var i,nx,ny,nz : integer;

Sx,Sy,Sz : real;

X : Xar;

Y : Yar;

Z : Zar;

Procedure MiddleAr(Var Buf:Xar; Var S:real; n:integer);

Var i : integer;

Begin

S:=0;

For i:=1 to n do

S:=S+Buf[i];

S:=S/n;

End { MiddleAr };

Begin

Ввод и печать nx, ny, nz, X, Y, Z

MiddleAr(X,Sx,nx);

MiddleAr(Y,Sy,ny);

MiddleAr(Z,Sz,nz);

Печать Sx, Sy, Sz

End.

Здесь при трансляции программы будет правильно воспринято лишь первое обращение к процедуре MiddleAr; для остальных обращений будет выдано сообщение о несоответствии типов фактических параметров Y, Z и формального параметра Buf.

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

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

Формальному параметру без типа имеет смысл передавать лишь адрес, а не значение фактической переменной, поскольку адрес переменной всегда имеет постоянную длину (4 байта), а значение переменной имеет длину, зависящую от типа этой переменной. Следовательно, формальный параметр без типа обязательно должен иметь слово Var в заголовке процедуры (это так называемый нетипизированный параметр-переменная).

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

Program Middle2;

Type Xar = array[1..50] of real;

Yar = array[1..500] of real;

Zar = array[1..5000] of real;

Var i,nx,ny,nz : integer;

Sx,Sy,Sz : real;

X : Xar;

Y : Yar;

Z : Zar;

{ ---------------------------------------------- }

Procedure MiddleAr(Var Buf; Var S:real; n:integer);

Type RealAr = array[1..10000] of real;

Var i : integer;

Begin

S:=0;

For i:=1 to n do

S:=S+RealAr(Buf)[i];

S:=S/n;

End { MiddleAr };

{ ---------------------------------------------- }

Begin

Ввод и печать nx, ny, nz, X, Y, Z

MiddleAr(X,Sx,nx);

MiddleAr(Y,Sy,ny);

MiddleAr(Z,Sz,nz);

Печать Sx, Sy, Sz

End.

Хотя "интерпретирующее" поле RealAr, накладываемое на формальную переменную Buf без типа, длиннее фактических переменных X, Y или Z, в процедуре MiddleAr выхода за пределы реальных массивов не произойдет, если переменные nx, ny, nz не превышают соответственно значений 50, 500, 5000.

Более предпочтительным для RealAr является объявление вида

RealAr = array[1..(2*MaxInt) div SizeOf(real)] of real.

Здесь компилятор определяет для RealAr максимально возможный размер, самостоятельно вычисляя количество элементов такого массива ( 2  32767 div 6 = 10992 ).

Тип RealAr в процедуре MiddleAr накладывается на формальный параметр Buf без имени типа, который при обращении к процедуре заменяется именем фактического массива. Так как RealAr - это имя типа, а не описание переменной, то объекту с именем RealAr никакой памяти не выделяется. Как и любое имя типа, RealAr определяет множество значений, которые может принимать переменная с этим именем типа.

Как уже было отмечено, для формального параметра Buf в процедуре MiddleAr не указано никакого имени типа. Если бы в этой процедуре было записано S := S + Buf[i], то транслятор выдал бы сообщение об ошибке, поскольку в списке формальных параметров нет информации о том, что собой представляет идентификатор Buf (простая переменная, массив и т.п.). Можно было бы возразить, что эту информацию транслятор мог бы получить из обращения к процедуре MiddleAr. Но ведь описание процедуры предшествует разделу операторов. Следовательно, при трансляции этой процедуры еще не прочитаны обращения к ней, и тип переменной Buf остается неопределенным.

Запись приведенного выше оператора в форме S := S + RealAr(Buf)[i] снимает такое недоразумение, поскольку транслятору в этом случае указано, что имя Buf следует рассматривать как имя одномерного массива с вещественными компонентами.

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

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

Вначале составим отдельную программу обработки одного массива.

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

Program DelElem;

Const Nmax = 500;

Type Ar = array[1..Nmax] of integer;

Var X,Y : Ar;

i, { параметр цикла }

n, { реальный размер массива X }

m : word; { реальный размер массива Y }

{ ---------------------------------------- }

Function FindElem(r:integer):boolean;

{ Определение признака включения элемента в массив Y }

Var i : word;

Begin

FindElem:=false;

For i:=1 to m do

If r=y[i] then

Begin

FindElem:=true; Exit

End;

End { FindElem };

{ ---------------------------------------- }

Begin

Ввод и печать n, X

m:=1; y[1]:=x[1];

For i:=2 to n do

If not FindElem(x[i]) then { элемент x[i] записывается }

Begin { в массив Y, если в этом }

Inc(m); y[m]:=x[i] { массиве еще нет такого }

End; { элемента }

X:=Y; n:=m;

Печать n,X

End.

В программе DelElem создается буферный (временный) массив Y, необходимый лишь на период обработки массива X в соответствии с использованным здесь алгоритмом. Размер массива Y в соответствии с его объявлением равен размеру массива X (учитывается частный случай, когда в массиве X нет одинаковых элементов). Если программу DelElem оформлять в виде процедуры, то массив Y должен создаваться в процессе работы этой процедуры, т.е. переменная Y должна быть локальной. Но, как было оговорено в условии задачи, процедура DelElem должна обрабатывать массивы с различными именами типов, имеющими в общем случае различные размеры. Поскольку локальный массив, объявляемый в процедуре, должен иметь вполне определенное, заранее указанное в тексте программы, имя типа, то обеспечить размер такого массива равным размеру обрабатываемого массива X, невозможно. Следовательно, алгоритм, использованный в программе DelElem, не позволяет оформить эту программу в виде процедуры для обработки массивов с различными именами типов. В данном случае необходимо разработать такой алгоритм решения задачи, для реализации которого не требуется дополнительный буферный массив.

В процедуре DelElems, приведенной ниже, производится последовательный просмотр элементов массива A, совмещенного по адресу с формальным массивом U, и, в случае обнаружения повторяющегося элемента, производится его удаление путем сдвига оставшейся части массива на один элемент влево.

Program Delar;

Type Xar = array[1..50] of integer;

Yar = array[1..500] of integer;

Zar = array[1..5000] of integer;

RealAr = array[1..2*MaxInt div SizeOf(integer)]

of integer;

Var i,nx,ny,nz : word;

X : Xar; Y : Yar; Z : Zar;

FileX,FileY,FileZ : text;

{ ---------------------------------------------- }

Procedure ReadVector(Var F:text; Var U; Var n:word);

Var A : RealAr absolute U;

Begin { Чтение массива }

Reset(F); { из текстового файла }

n:=0;

While not eof(F) do

Begin

Inc(n); Read(F,a[n])

End;

End { ReadVector };

{ ---------------------------------------------- }

Procedure WriteVector(Var U; n:word);

Var i,k : word;

A : RealAr absolute U;

Begin

k:=0; { Вывод массива }

For i:=1 to n do { на экран }

Begin

Inc(k);

If k<10 then

Write(a[i]:6,' ')

Else

Begin

k:=0; Writeln(a[i]:6);

End;

End;

If k>0 then Writeln;

End { WriteVector };

{ ---------------------------------------------- }

Procedure DelElems(Var U; Var n:word);

Var i,j,k,R : integer;

A : RealAr absolute U;

Begin

i:=1;

While i<n do { Удаление всех }

Begin { повторяющихся }

R:=a[i]; j:=i+1; { элементов, кроме }

While j<=n do { первого такого }

If R=a[j] then { элемента }

Begin

For k:=j to n-1 do

a[k]:=a[k+1];

Dec(n);

End

Else

Inc(j);

Inc(i);

End;

End { DelElems };

{ ---------------------------------------------- }

Begin

ReadVector(FileX,X,nx);

WriteVector(X,nx);

DelElems(X,nx);

WriteVector(X,nx);

ReadVector(FileY,Y,ny);

WriteVector(Y,ny);

DelElems(Y,ny);

WriteVector(Y,ny);

ReadVector(FileZ,Z,nz);

WriteVector(Z,nz);

DelElems(Z,nz);

WriteVector(Z,nz);

End.

Соседние файлы в папке LecRus