Программирование на языке Delphi/§5

Материал из Викиверситета

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

var
 a:array[1..10] of integer;
 b:array[1..20] of char;

Одномерные массивы[править]

Элементами массива могут быть данные любого типа, включая структурированные. К необходимости применения массивов (прямого или опосредованного) мы приходим всегда, когда требуется связать и использовать ряд однотипных величин. При описания массива используются зарезервированные слова array и of. За словом array в квадратных скобках указывается диапазон или перечислимый(ordinal) тип, определяющий количество элементов массива. После слова of указывается тип элементов, образующих массив. Доступ к каждому элементу массива осуществляется с помощью индекса. Нельзя указывать значение индекса, не входящий в диапазон массива.

var
 a:array[1..10]of integer;
begin
a[7]:=14;
a[2]:=11;
a[0]:=20; //Ошибка!
end.

В отличие от C-подобных языков(C/C++/Java/C#), в которых начальным индексом массива всегда служит нулевое целое, в Delphi при объявлении переменной-массива или типа-массива, указывается диапазон значений индекса, а не количество элементов. Это означает, что первым элементом массива может быть элемент с индесом, отличным от нуля.

Заполнение массивов происходит поэлементно, обычно использую оператор for:

{$APPTYPE CONSOLE}
var
  a:array[1..100] of integer;
  i,j:integer;
begin
for i:=1 to 100 do   //Заполнение массива случайными числами.
   a[i]:=random(9)+1;  //ф-ция random возвращает псевдослучайное число в интервале 0..<параметр>-1
for i:=0 to 9 do begin   //Вывод по 10 чисел на строку
   for j:=1 to 10 do //Внутренний цикл
      write(a[i*10+j],' ');
   writeln(' ');
   end;
readln;
end.

Допускается инициализация не-локальных переменных-массивов:

  var t:array[1..3] of Integer=(1,2,3);
  type TRec=record
    s:string;
    v:integer;
  end;
  var ra:array[1..2] of TRec=((s:'test';v:3), (s:'test2';v:4));

Другие примеры объявления массивов

procedure test4();
type TWorkingDays=(Monday,Tuesday,Wednesday,Thursday, Friday);
var ar:array[boolean]of integer;
    ar2:array[TWorkingDays] of Cardinal;
    ar3:array[Tuesday..Thursday] of Cardinal;
   bl:boolean;
   wd:TWorkingDays;
begin
 RandSeed:=2;
 for bl  in [true,false] do begin
   ar[bl]:=random(13);
 end;
 for wd := Monday to Friday do ar2[wd]:=random(100);
 for wd  :=Tuesday to Thursday do ar3[wd]:=random(4);
end;

Переменные-массивы, имеющие аналогичный, но не идентичный тип, вообще говоря, не являются совместимыми.

  procedure test();
  var tt,tt2:array[1..3] of Integer;//=(1,2,3);
      tt3:array[1..3] of integer;
  begin
     tt[1]:=3;tt[2]:=4; tt[3]:=5;
     tt2:=tt;//OK
     tt3:=tt;//EROOR: Incompatible types
  end;

Многомерные массивы[править]

Если в тип элемента массива есть другой массив, то образуется структура, которую принято называть многомерным массивом.

var 
    a:array[1..10]of array[1..20]of integer;
    b:array[1..10,1..20]of integer;// то же, что и выше

Если при форме описания массива задан один индекс, массив называется одномерным, если два индекса — двумерным, если n индексов — n-мерным. Одномерный массив соответствует понятию линейной таблицы (вектора), двумерный — понятию прямоугольной таблицы (матрицы). Для доступа к элементам n-мерного массива нужно указывать n индексов:

var a:array[1..10,1..50]of integer;
begin
a[1,1]:=23;
a[4,25]:=0;
end.

Избегайте объявления (статических) массивов больших размерностей (общим размером более 4095 байт) в качестве локальных переменных, равно как и нескольких локальных массивов, общий размер которых превышает указанное значение.

Динамические массивы[править]

Бывают ситуации, когда заранее трудно предположить, какой размер должен быть у массива. Например если необходимо считать файл: если массив будет слишком малым, то файл может не поместиться в нем, а если массив будет слишком большим, то он будет занимать много лишней памяти. Динамические массивы позволяют создавать массивы с заранее неизвестным количеством элементов. Кроме того, в отличие от вышеупомянутых статических массивов, динамические массивы всегда распределены в динамически выделяемых областях памяти("куче"/heap либо виртуальной памяти процесса).

var a:array of integer;

Для работы с динамическим массивом необходимо выделить ему память. Для этого используется функция setLength

var a:array of integer;
begin
setLength(a,20);//массив длиной 20 элементов, скорей всего займет 20*4 байт, не считая служебной информации.
end.

Первый параметр функции SetLength - переменная типа "динамический массив", второй - количество элементов. Счет элементов начинается с 0. Другими словами, динамические массивы всегда индексируются с нуля(в отличие от статических, в которых нижняя граница индекса указывается явно). Также возможно создание многомерных динамических массивов.

{$APPTYPE CONSOLE}
var
 a:array of array of integer;
 l1,l2,i,j:integer;
begin
writeln("Введите размер массива");
readln(l1); //Ввод размеров массива
readln(l2);
setlength(a,l1);
for i:=0 to l1-1 do
  setLength(a[i],l2);  //Инициализация массивов
for i:=0 to l1-1 do
  for j:=0 to l2-1 do
    a[i,j]:=random(10);
end.

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

procedure Triangular();
var a:array of array of integer;//динамический двумерный массив
    i,j,v:integer;
begin
SetLength(a, 3);// массив a состоит из 3 элементов-массивов
v:=1;
writeln('Triangular');
for i:=Low(a) to High(a) do begin//Системная функция High, примененная к переменной массиву(динамическому или статическому), возвратит наибольший индекс массива
// (в нашем случае 2)
// а Low - наименьший индекс массива. Поскольку, нижней границей для динамического массива является 0, то для динамического массива Low всегда будет возвращать 0
   SetLength(a[i], i+1);// для первого элемента-массива размерность будет 1, то есть в нем будет лишь один элемент, для второго таких элементов будет 2 и так далее
   for j:=Low(a[i]) to High(a[i]) do  begin
         a[i,j]:=v;
         write(a[i,j],#$9);
         Inc(v);//v:=v+1;
        end;//for j
        writeln('');
end;//for i
a:=nil;
end;//proc

вывод функции будет таким:

Triangular
1
2 3
4 5 6

Узнать длину динамического массива, можно вызовом функции Length(a), где a- переменная-динамический массив. Очевидно, для дин. массивов, тождесвенно равенство:

Length(a)=High(a)+1

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

Удаление массива из памяти происходит тогда, когда разрешается последняя ссылка на массив: иными словами, когда переменной-дин. массиву присваивают значение nil, либо она выходит из области видимости(в случае локальных переменных), происходит неявное уменьшение счетчика ссылок на 1, и сравнение этого счетчика с 0. Если счетчик ссылок нулевой, то происходит финализация и освобождение памяти. Принудительно освободить занимаемую массивом память можно также посредством установки его длины в 0:

setLength(vAr,0);