Мы поможем в написании ваших работ!



ЗНАЕТЕ ЛИ ВЫ?

proceduremy(i: integer); begin ... end; function f: integer; begin

Поиск

Массивы

Массив представляет собой набор элементов одного типа, каждый из которых имеет свой номер, называемый индексом (индексов может быть несколько, тогда массив называется многомерным).

Массивы в PascalABC.NET делятся на статические и динамические.

При выходе за границы изменения индекса в PascalABC.NET всегда генерируется исключение.

Статические массивы

Тип статического массива конструируется следующим образом:

array [тип индекса1, ..., тип индексаN] of базовый тип

Тип индекса должен быть порядковым. Обычно тип индекса является диапазонным и представляется в виде a..b, где a и b - константные выражения целого, символьного или перечислимого типа. Например:

type
MyEnum = (w1,w2,w3,w4,w5);
Arr = array [1..10] of integer;
var
a1,a2: Arr;
b: array ['a'..'z',w2..w4] of string;
c: array [1..3] of array [1..4] of real;

При описании можно также задавать инициализацию массива значениями:

var
a: Arr := (1,2,3,4,5,6,7,8,9,0);
cc: array [1..3,1..4] of real := ((1,2,3,4), (5,6,7,8), (9,0,1,2));

Статические массивы одного типа можно присваивать друг другу, при этом будет производиться копирование содержимого одного массива в другой:

a1:=a2;

При передаче статического массива в подпрограмму по значению также производится копирование содержимого массива - фактического параметра в массив - формальный параметр:

procedure p(a: Arr);
...
p(a1);

Как правило, в этой ситуации копирование не требуется, поэтому статический массив рекомендуется передавать по ссылке:

procedure p1(var a: Arr);
...
r(a1);

 

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

Тип динамического массива конструируется следующим образом:

array of тип элементов (одномерный массив)
array [,] of тип элементов (двумерный массив)
и т.д.

Переменная типа динамический массив представляет собой ссылку. Поэтому динамический массив нуждается в инициализации (выделении памяти под элементы).

Для выделения памяти под динамический массив используется два способа. Первый способ использует операцию new в стиле вызова конструктора класса:

var
a: array of integer;
b: array [,] of real;
begin
a := new integer[5];
b := new real[4,3];
end.

В этом случае можно также задавать инициализацию массива значениями:

a := new integer[3](1,2,3);
b := new real[4,3] ((1,2,3),(4,5,6),(7,8,9),(0,1,2));

Второй способ использует стандартную процедуру SetLength:

SetLength(a,10);
SetLength(b,5,3);

Процедура SetLength обладает тем преимуществом, что при ее повторном вызове старое содержимое массива сохраняется.

Если объявлен массив массивов

var с: array of array of integer;

то его инициализацию можно провести только с помощью SetLength:

SetLength(с,5);
for i := 0 to 4 do
SetLength(c[i],3);

Для инициализации такого массива с помощью new следует ввести имя типа для array of integer:

typeIntArray = array of integer;
var
с: array ofIntArray;
...
c := new IntArray[5];
for i := 0 to 4 do
c[i] := new integer[3];

При описании инициализацию динамического массива можно проводить в сокращенной форме:

var
a: array of integer := (1,2,3);
b: array [,] of real := ((1,2,3),(4,5,6),(7,8,9),(0,1,2));
c: array of array of integer := ((1,2,3),(4,5),(6,7,8));

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

Динамические массивы одного типа можно присваивать друг другу, при этом обе переменные-ссылки будут указывать на одну память:

var a1: array of integer;
var a2: array of integer;
a1 := a2;

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

Чтобы одному динамическому массиву присвоить копию другого массива, следует воспользоваться стандартной функцией Copy:

a1 := Copy(a2);

Длина массива (количество элементов в нем) возвращается стандартной функцией Length или свойством Length:

l := Length(a);
l := a.Length;

Для многомерных массивов длина по каждой размерности возвращается стандартной функцией Length с двумя параметрами или методом GetLength(i):

l := Length(a,0);
l := a.GetLength(0);

Указатели

Указатель - это ячейка памяти, хранящая адрес. В PascalABC.NET указатели делятся на типизированные (содержат адрес ячейки памяти данного типа) и бестиповые (содержат адрес оперативной памяти, не связанный с данными какого-либо определенного типа).

Тип указателя на тип T имеет форму ^T, например:

type pinteger = ^integer;
var p: ^record r,i: real end;

Бестиповой указатель описывается с помощью слова pointer.

Для доступа к ячейке памяти, адрес которой хранит типизированный указатель, используется операция разыменования ^:

var
i: integer;
pi: ^integer;
...
pi := @i; // указателю присвоили адрес переменной i
pi^ := 5; // переменной i присвоили 5

Операция разыменования не может быть применена к бестиповому указателю.

Типизированный указатель может быть неявно преобразован к бестиповому:

var
p: pointer;
pr: ^real;
...
p := pr;

Обратное преобразование также может быть выполнено неявно:

pr := p;
pr^ := 3.14;

Указатели можно сравнивать на равенство (=) и неравенство (<>). Для того чтобы отметить тот факт, что указатель никуда не указывает, используется стандартная константа nil (нулевой указатель) : p :=nil.

Внимание! Ввиду особенностей платформы .NET тип T типизированного указателя не должен быть ссылочным или содержать ссылочные типы на каком-то уровне (например, запрещены указатели на записи, у которых одно из полей имеет ссылочный тип). Причина такого ограничения проста: указатели реализуются неуправляемым кодом, который не управляется сборщиком мусора. Если в памяти, на которую указывает указатель, содержатся ссылки на управляемые переменные, то они становятся недействительными после очередной сборки мусора. Исключение составляют динамические массивы и строки, обрабатываемые особым образом. То есть, можно делать указатели на записи, содержащие в качестве полей строки и динамические массивы.

Записи

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

record
список полей
список методов
end

Приведем пример записи, содержащей только поля:

type
SexType = (male, female);
Person = record
Name: string;
Age, Weight: integer;
Sex: SexType;
end;

При описании переменной или константы типа запись можно использовать инициализатор записи (как и в Object Pascal):

const p: Person = (Name: 'Петрова'; Age: 18; Weight: 55; Sex: female);

var p: Person := (Name: 'Иванов'; Age: 20; Weight: 80; Sex: male);

Присваивание записей копирует содержимое полей одной переменной-записи в другую:

d2 := d1;

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

В отличие от Object Pascal, в PascalABC.NET отсутствуют записи с вариантами.

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

Список отличий между записями и классами приводятся ниже:

1. Запись представляет собой размерный тип (переменные типа запись располагаются на стеке).

2. Записи нельзя наследовать; от записей также нельзя наследовать (отметим, что записи, тем не менее, могут реализовывать интерфейсы). В .NET тип записи неявно предполагается наследником типа System.ValueType и реализуется struct-типом.

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

По умолчанию процедура write для переменной типа запись выводит ее тип. Чтобы изменить это поведение, в записи следует переопределить метод ToString класса Object.

Например:

type
SexType = (male, female);
Person = record
private

Name: string;
Age, Weight: integer;
Sex: SexType;
public
constructor Create(Name: string; Age, Weight: integer; Sex: SexType);
begin
Self.Name := Name;
Self.Age := Age;
Self.Weight := Weight;
Self.Sex := Sex;
end;
function ToString: string; override;
begin
Result := string.Format('Имя: {0} Возраст: {1} Вес: {2} Пол: {3}',
Name, Age, Weight, Sex);
end
end;
...
var p: Person := new Person('Иванов',20,70,Sex);
writeln(p);

Множества

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

set ofбазовый тип

В качестве базового может быть любой тип, в том числе строковый и классовый.

Например:

type
ByteSet = set of byte;
StringSet = set of string;
Digits = set of '0'..'9';
SeasonSet = set of(Winter,Spring,Summer,Autumn);
PersonSet = set of Person;

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

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

[список значений]

где в списке могут перечисляться через запятую либо выражения базового типа, либо (для порядковых типов) их диапазоны в виде a..b, где a и b - выражения базового типа. Например:

var
bs: ByteSet := [1,3,5,20..25];
fios: StringSet := ['Иванов','Петров','Сидорова'];

Значения в списке могут отсутствовать, тогда множество является пустым: bs:=[];

Пустое множество совместимо по присваиванию с множеством любого типа.

Для множеств имеет место структурная эквивалентность типов.

Множества целых и множества на базе типа и его диапазонного подтипа или на базе двух диапазонных типов одного базового типа неявно преобразуются друг к другу. Если при присваивании s := s1 во множестве s1 содержатся элементы, которые не входят в диапазон значений базового типа для множества s, то они отсекаются.

Например:

var st: set of 3..9;
...
st := [1..5,8,10,12]; // в st попадут значения [3..5,8]

Операция in проверяет принадлежность элемента множеству:

if Wed in bestdays then ...

Для множеств определены операции + (объединение), - (разность), * (пересечение), = (равенство), <> (неравенство), <= (нестрогое вложение), < (строгое вложение), >= (нестрого содержит) и > (строго содержит).

Процедура write при выводе множества выводит все его элементы:

write(['Иванов','Петров','Сидорова']);

выведет ['Иванов','Петров','Сидорова'], при этом данные, если это возможно, будут отсортированы по возрастанию.

Для перебора всех элементов множества можно использовать цикл foreach, данные перебираются в некотором внутреннем порядке:

foreach s: string in fios do
write(s,' ');

Для добавления элемента x к множеству s используется конструкция s += [x] или стандартная процедура Include: Include(s,x). Для удаления элемента x из множества s используется конструкция s -= [x] или стандартная процедура Exclude: Exclude(s,x).

Процедурный тип

Переменные, предназначенные для хранения процедур и функций, называются процедурными. Тип процедурной переменной представляет собой заголовок процедуры или функции без имени. Например:

type
procI =procedure(i: integer);
funI = function: integer;

Процедурной переменной можно присвоить процедуру или функцию с совместимым типом:

end;
...
var
p1: procI;
f1: funI;
...
p1 := my;
f1 := f;

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

p1(5);
write(f1);

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

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

procedure forall(var a: array of real; p: procedure(var r: real));
begin
for var i := 0 to a.Length-1 do
p(a[i]);
end;

procedure mult2(var r: real);
begin
r := 2*r;
end;

procedure add3(var r: real);
begin
r := r + 3;
end;

procedure print(var r: real);
begin
write(r,' ');
end;
...
forall(a,mult2); // умножение элементов массива на 2
forall(a,add3); // увеличение элементов массива на 3
forall(a,print); // вывод элементов массива

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

Процедурные переменные реализуются через делегаты .NET. Это означает, что они могут хранить несколько подпрограмм. Для добавления/отсоединения подпрограмм используются операторы += и -=:

p1 += mult2;
p1 += add3;
forall(a,p1);

Подпрограммы в этом случае вызываются в порядке прикрепления: вначале умножение, потом сложение.

Отсоединение неприкрепленных подпрограмм не выполняет никаких действий:

p1 -= print;

Кроме того, к процедурной переменной можно прикреплять/откреплять классовые и экземплярные методы классов.



Поделиться:


Последнее изменение этой страницы: 2024-06-27; просмотров: 3; Нарушение авторского права страницы; Мы поможем в написании вашей работы!

infopedia.su Все материалы представленные на сайте исключительно с целью ознакомления читателями и не преследуют коммерческих целей или нарушение авторских прав. Обратная связь - 3.141.198.113 (0.007 с.)