Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
_Delphi_1курс лекции / Пр 6 Массивы.doc
Скачиваний:
48
Добавлен:
23.03.2015
Размер:
123.9 Кб
Скачать

Многомерные массивы

Можно объявлять и многомерные массивы, т.е. массивы, элементами которых являются массивы. Например, двумерный массив можно объявить таким образом:

Var

A2 : array [1..10] of array [1..3] of integer;

Этот оператор описывает двумерный массив, который можно представить себе как таблицу, состоящую из 10 строк и 3 столбцов. То же самое можно объявить более компактно:

Var A2: array[l..10,1. .3] of integer;

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

Доступ к значениям элементов многомерного массива обеспечивается через индексы, перечисляемые через запятую. Например, А2[4,3] — значение элемента, лежащего на пересечении четвертой строки и третьего столбца.

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

Например:

type

Ar3 = array[1. . 4 , 1. .3, 1. .2] of integer;

var

A1,A2: Ar3;

const

A3: Ar3=( ( (0,1) , (2, 3), (4, 5) ) ,

( ( 6 , 7 ) , (8, 9), (10,11)),

( ( 12 , 13 ) , (14,15), (16,17)),

( ( 18 , 19 ) , (20,21), ( 22, 23 ) ) ) ;

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

0 1 6 7 12 13 18 19

2 3 8 9 14 15 20 21

4 5 10 11 16 17 22 23

Например, элемент A3[1,2,1] равен 2, элемент А3[4,1,2] равен 19 и т.д.

Операции с массивами, передача массивов как параметров

Для массивов одного типа определена операция присваивания. Например, если массивы объявлены как

var A,B: array[1..3] of integer;

то в результате выполнения оператора

А := В;

значения элементов массива В присвоятся соответствующим элементам массива А.

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

Аналогично будет работать оператор присваивания, если переменные массивов объявлены следующим образом:

type

Ar = array[1..3] of integer;

var

A: Ar;

B: Ar;

Ho если объявить массивы следующим образом:

var

A: array[1..3] of integer;

В: array[1..3] of integer;

то при попытке присваивания А:=В компилятор выдаст синтаксическую ошибку с сообщением ‘Incompatible types’ — несовместимые типы. Дело в том, что компилятор считает, что переменные имеют один тип только в случаях, если они явным образом определены через некоторый поименованный тип, как сделано во втором примере, или если они объявлены в одном списке, как это имеет место в первом примере. А в третьем примере ни то, ни другое условие не соблюдается.

Для любого массива определены следующие функции:

Length

число элементов массива

High

наибольшее значение индекса

Low

наименьшее значение индекса

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

Для числовых массивов определены функции:

Функция

Тип аргумента

Тип результата

Описание

MaxIntValue

array of integer

integer

возвращает максимальное значение элемента массива целых чисел

MinIntValue

array of integer

integer

возвращает минимальное значение элемента массива целых чисел

MaxValue

array of double

double

возвращает максимальное значение элемента числового массива

MinValue

array of double

double

возвращает минимальное значение элемента числового массива

Sum

array of double

extended

возвращает сумму элементов массива

Эти функции определены в модуле math и этот модуль должен подключаться оператором uses, чтобы компилятор их понимал.

К символьным массивам применимы функции работы со строками.

Если вы хотите создать свою функцию или процедуру работы с массивами, то надо иметь в виду, что в ее объявление нельзя включать описание индексов. Например, объявление

procedure MyProc(A: array[1..10] of Integer);

будет расценено как синтаксическая ошибка и вызовет соответствующее сообщение компилятора. Правильным будет объявление

type

ta = array[l..10] of Integer;

procedure MyProc(A: ta) ;

Функции и процедуры в Object Pascal могут воспринимать в качестве параметров не только массивы фиксированного размера, но и так называемые открытые массивы, размер которых неизвестен. В этом случае в объявлении функции или процедуры они описываются как массивы базовых типов без указания их размерности.

В качестве примера использования открытых массивов рассмотрим процедуру, которая принимает два открытых одинакового размера массива целых чисел, суммирует их и заносит результат во второй из переданных массивов. Заголовок этой процедуры:

procedure SumArray(A:array of integer;

var B: array of integer);

При таком определении передаваемый в функцию первый массив будет копироваться и с этой копией - массивом A, будет работать процедура. Второй открытый массив определен как var. Этот массив передается по ссылке, т.е. он не копируется и процедура будет работать непосредственно с исходным массивом.

procedure SumArray(A:array of integer;

var B: array of integer);

var i:word;

begin

for i:=0 to High(A) do B[i]:=A[i]+B[i];

end;

Вызов этой процедуры может иметь вид:

var A1,A2: array [1..3] of integer;

begin

<операторы заполнения массивов>

SumArray(A1,A2);

end;

Обратите внимание на то, что массивы A1 и A2, передаваемые в качестве аргументов, имеют значения индексов от 1 до 3, а процедура оперирует с индексами в диапазоне 0 - 2. Однако никакой путаницы не возникнет. Просто, например, элемент A[0] в теле процедуры будет соответствовать элементу A1[1] в массиве A1.

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

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

Sum([1.2,4.45,0.1]);

Пример использования открытых массивов для заполнения одномерных массивов, вывода их в компоненты Memo, суммирования элементов одномерного массива целых чисел, использования функций суммирования и поиска максимального элемента из модуля math.

Двумерный открытый массив объявлять нельзя.

type

TarrInt=array [1..3,1..5] of integer;

TForm1 = class(TForm)

Button1: TButton;

Memo1: TMemo;

Memo2: TMemo;

Memo3: TMemo;

Panel1: TPanel;

Label1: TLabel;

Memo4: TMemo;

procedure Button1Click(Sender: TObject);

private

{ Private declarations }

public

procedure InputOpenArrInt(var A : array of integer);

procedure OutputOpenArrInt(var A : array of integer);

procedure OutputOpenArrFloat(var A : array of double);

procedure InputOpenArrFloat(var A : array of double);

function SumOpenArrInt(A : array of integer):integer;

procedure InputArr(var A :TarrInt);

procedure OutputArr(var A :TarrInt);

function SumArr(var A :TarrInt): integer;

{ Public declarations }

end;

var

Form1: TForm1;

implementation

var

a : array[1..5] of integer;

c : array[1..3] of double;

b : TarrInt;

A2: array of array of integer;

{$R *.dfm}

procedure TForm1.InputOpenArrInt(var A : array of integer);

var

i : integer;

begin

randomize;

for i:=0 to high(A) do // Можно for i:=low(A) to high(A) do

A[i]:=random(11);

end;

procedure TForm1.OutputOpenArrInt(var A : array of integer);

var

i : integer;

begin

for i:=0 to high(A) do

memo1.Lines.Add(intToStr(A[i]));

end;

procedure TForm1.InputOpenArrFloat(var A : array of double);

var

i : integer;

begin

randomize;

for i:=low(A) to high(A) do A[i]:=random;

end;

procedure TForm1.OutputOpenArrFloat(var A : array of double);

var

i : integer;

begin

for i:=0 to high(A) do

memo3.Lines.Add(floatToStr(A[i]));

end;

function TForm1.SumOpenArrInt(A : array of integer):integer;

var

i: integer;

begin

result:=0;

for i:=0 to high(A) do

result:=result+a[i];

end;

procedure TForm1.InputArr(var A :TarrInt);

var

i,j : integer;

begin

randomize;

for i:=1 to 3 do

for j:=1 to 5 do

B[i,j]:=random(11);

end;

procedure TForm1.OutputArr(var A :TarrInt);

var

i,j : integer;

str : string;

begin

for i:=1 to 3 do

begin

str:='';

for j:=1 to 5 do

str:=str+intToStr(B[i,j])+' ';

memo2.lines.Add(str);

end;

end;

function TForm1.SumArr(var A :TarrInt): integer;

var

i,j : integer;

begin

result:=0;

for i:=1 to 3 do

for j:=1 to 5 do

result:=result+B[i,j];

end;

//нельзя объявлять двумерный открытый массив!!!

// function SumB(b :array of array of integer): integer;

// Ошибка : ERROR Identifier expected but 'ARRAY' found

procedure TForm1.Button1Click(Sender: TObject);

var

i,j,N, m : integer;

str : string;

s: integer;

begin

InputOpenArrInt(A);

OutputOpenArrInt(A);

memo1.Lines.Add('S='+intToStr(SumOpenArrInt(A)));

memo1.Lines.Add('Max='+ intToStr(MaxIntValue(A))); //MaxIntValue - стандартная ф-ция,

// описанная в моделе math

InputOpenArrFloat(C);

OutputOpenArrFloat(C);

memo3.Lines.Add('S='+floatToStr(Sum(C))); //Sum - стандартная ф-ция,

// описанная в моделе math

InputArr(B);

OutputArr(B);

memo2.Lines.Add('S='+intToStr(SumArr(B)));

end;

end.

Открытые массивы специального вида, объявляемые как array of const, разрешают, в отличие от всех других массивов, передавать в процедуру или функцию массив различных по типу значений.

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

Динамические массивы

В версии Delphi 4 впервые введены так называемые динамические массивы. При объявлении таких массивов в программе не следует указывать границы индексов:

var

A: array of Integer;

В: array of array of Char;

C: array of array of array of Real;

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

SetLength(А,3);

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

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

var

А,В: array of Integer;

begin

// Распределяем память:

SetLength(A,10) ;

SetLength(B,20) ;

// Используем массивы:

// Освобождаем память:

А := NIL;

Finalize(В);

end;

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

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

Один из способов отвести память под такой массив - передать в процедуру SetLength в качестве параметров несколько размеров. Например

var

A: array of array of Integer;//Двумерный динамический массив

begin

SetLength(A,3,4);

задает размерность массива 3 на 4.

Можно задавать размерность для каждого столбца отдельно. Например:

var

A: array of array of Integer;//Двумерный динамический массив

begin

//Устанавливаем длину первого измерения (количество строк):

SetLength(A,3) ;

//Задаем длину каждой строки:

SetLength(A[0],3) ;

SetLength(A[l],3) ;

SetLength(A[2] ,3) ;

end;

Обратите внимание: в отличие от обычных массивов стандартного Паскаля (и Object Pascal), динамические массивы могут иметь разную длину по второму и следующим измерениям. В предыдущем примере определен квадратный массив 3х3. Однако ничто не мешает нам создать, например, треугольный массив:

SetLength(A,3) ;

//Задаем длину каждой строки:

SetLength(A[0],3) ;

SetLength(A[l],4) ;

SetLength(A[2],5) ;

В многомерных динамических массивах каждый элемент любого из N-1 измерений (N - количество измерений) представляет собой динамический массив и, следовательно, нуждается в инициации. Вот как, например, можно инициировать вещественный кубический массив 3х3х3:

var

A: array of array of array of Real;

i, j: Integer;

begin

SetLength(A,3) ;

for i := 0 to 2 do

begin

SetLength(A[i],3) ;

for j := 0 to 2 do

SetLength(A[i,j],3) ;

end;

end;

Пример. Рассмотрим программу построения и заполнения нижней треугольной матрицы произвольного размера N.

var A2: array of array of integer;

N,i1,i2,m: integer;

begin

N:=3;

m:=1;

SetLength(A2,N); {Задание числа строк = N}

for i:=0 to N-1 do {Цикл по строкам}

begin

s:='';

SetLength(A2[i],i+1); {Число столбцов равно номеру строки}

for j:=0 to i do

begin

A2[i,j]:=m; {Заполнение строки}

Inc(m); {Увеличение m на 1}

s:=s+IntToStr(a2[i,j])+' ';

end;

memo1.lines.Add(s);

end;

Программа формирует двумерный массив, в котором число строк равно значению N, а число столбцов в каждой строке равно номеру строки.

Пример (приведен в файле 'Тема 6 Таблицы строк.doc') считывания и записи матрицы из/в компонент StringGrid. На форме расположены 3 компонента StringGrid: strgrdA, strgrdB, strgrdResult; 2 кнопки btnRead и btnWrite. При нажатии на кнопку btnRead выполняется считывание 2-х массивов из компонент StringGrid .

type

TMatrix = array of array of integer;

TfrmMatrices = class(TForm)

strgrdB: TStringGrid;

strgrdA: TStringGrid;

strgrdResult: TStringGrid;

btnRead: TButton;

btnWrite: Tbutton;

procedure btnRead(Sender: TObject);

procedure btnWrite(Sender: TObject);

private

{ Private declarations }

procedure ReadMatrix(var fg: TMatrix; StringGrid: TStringGrid);

procedure WriteMatrix(var fg: TMatrix; StringGrid: TStringGrid);

public

{ Public declarations }

end;

var

frmMatrices: TfrmMatrices;

A, B: TMatrix;

implementation

{$R *.dfm}

procedure TfrmMatrices.ReadMatrix(var fg: TMatrix; StringGrid: TStringGrid);

var

i, j: integer;

begin

SetLength(fg, StringGrid.RowCount, StringGrid.ColCount);

with StringGrid do

begin

for i:= 0 to RowCount-1 do

for j:= 0 to ColCount-1 do

begin

fg[i, j] := StrToInt(Cells[j, i]);

end;

end;

end;

procedure TfrmMatrices.WriteMatrix(var fg: TMatrix; StringGrid: TStringGrid);

var

i, j: integer;

begin

StringGrid.ColCount := Length(fg[0]);

StringGrid.RowCount := Length(fg);

for i:= 0 to Length(fg)-1 do

for j:= 0 to Length(fg[i])-1 do

StringGrid.Cells[j, i] := IntToStr(fg[i, j]);

end;

procedure TfrmMatrices.btnRead(Sender: TObject);

begin

try

ReadMatrix(A, strgrdA);

ReadMatrix(B, strgrdB);

except

on EConvertError do

begin

MessageDlg('Ошибка конвертирования. В поля можно вводить только числа.' +

#13#10 + 'Все ячейки должны быть заполнены', mtError, [mbOK], 0);

exit;

end;

end;

Задание. Напишите обработчик нажатия кнопки btnWrite в котором выведите элементы массива А в StringGrid.