ТОП 10:

Массивы в параметрах процедур и функций



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

const Max = 63;type TStatistics = array [0..Max] of Double; function Average(const A: TStatistics): Double;var I: Integer;begin Result := 0; for I := Low(A) to High(A) do Result := Result + A[I]; Result := Result / (High(A) - Low(A) + 1);end;

Функция Average принимает в качестве параметра массив известной размерности. Требование фиксированного размера для массива-параметра часто является чрезмерно сдерживающим фактором. Процедура для нахождения среднего значения должна быть способна работать с массивами произвольной длины. Для этой цели в язык Delphi введены открытые массивы-параметры. Такие массивы были заимствованы разработчиками языка Delphi из языка Modula-2.

Особенности:

1. Открытый массив-параметр описывается с помощью словосочетания array of, при этом границы массива опускаются:

function Average(const A: array of Double): Double;var I: Integer;begin Result := 0; for I := Low(A) to High(A) do Result := Result + A[I]; Result := Result / (High(A) - Low(A) + 1);end;

2. Внутри подпрограммы Average нижняя граница открытого массива A равна нулю (Low(A) = 0), а вот значение верхней границы (High(A)) неизвестно и выясняется только на этапе выполнения программы.

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

Вот пример использования функции Average:

var Statistics: array[1..10] of Double; Mean: Double;begin ... Mean := Average(Statistics); Mean := Average([0, Random, 1]); ...end;

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

5. Открытые массивы могут быть переданы в подпрограммы только по значению или как параметры-константы.

6. Некоторые библиотечные подпрограммы языка Delphi принимают параметры типа array of const — открытые массивы констант. Массив, передаваемый в качестве такого параметра, обязательно конструируется в момент вызова подпрограммы и может состоять из элементов различных типов (!). Физически он состоит из записей типа TVarRec, кодирующих тип и значение элементов массива (записи рассматриваются ниже). Открытый массив констант позволяет эмулировать подпрограммы с переменным количеством разнотипных параметров и используется, например, в функции Format для форматирования строки.

Передача параметров по значению

Этот режим передачи параметров применяется по умолчанию. Если параметр передается по значению, создается локальная копия данной переменной, которая и предоставляется для обработки в процедуру или функцию. Посмотрите на следующий пример:

procedure Test( s: string );

При вызове указанной процедуры будет создана копия передаваемой ей в качестве параметра строки s, с которой и будет работать процедура Test. При этом все внесенные в строку изменения никак не отразятся на исходной переменной s.

Однако это не относится к объектам. Например, если в функцию передается переменная (а точнее экземпляр объекта) TStringList, то в данном случае произойдет передача по ссылке (даже если это не указано явно).

Одномерные и двумерные статические массивы. Описание и обращение к элементам. Передача массивов как параметров в подпрограммы. Примеры.

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

array [indexType1, ..., indexTypen] of baseType,

где каждый indexType – это порядковый тип, размерность которого не превосходит 2GB. Для этого можно воспользоваться идентификатором некоторого типа (например, boolean или ansichar), однако на практике обычно явно задается поддиапазон целых чисел. Число элементов массива в каждом измерении задается соотвествующим порядковым типом. Количество элементов массива равно произведению количеств элементов во всех измерениях.

Словосочетание array of является зарезевированным. Квадратные скобки после слова array являются требованием синтаксиса, а после слова of — тип элементов массива.

1. Примеры.

Простейший случай – это одномерный массив:

type TStates = array[1..50] of string; TCoordinates = array[1..3] of Integer;

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

var States: TStates; { 50 strings }const Coordinates: TCoordinates = (10, 20, 5); { 3 integers }

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

3. Массив может быть определен и без описания типа:

var Symbols: array[0..80] of Char; { 81 characters }

4. Чтобы получить доступ к отдельному элементу массива, нужно в квадратных скобках указать его индекс, например

Symbols[0]

5. Объявленные выше массивы являются одномерными, так как имеют только один индекс. Одномерные массивы обычно используются для представления линейной последовательности элементов. Если при описании массива задано два индекса, массив называется двумерным, если n индексов — n-мерным. Двумерные массивы используются для представления таблицы, а n-мерные — для представления пространств. Вот пример объявления таблицы, состоящей из 5 колонок и 20 строк:

var Table: array[1..5] of array[1..20] of Double;

То же самое можно записать в более компактном виде:

var Table: array[1..5, 1..20] of Double;

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

Table[2][10]

или в более компактной записи

Table[2, 10]

Эти два способа индексации эквивалентны.

Одномерные и двумерные динамические массивы. Описание и обращение к элементам. Процедура SetLength, функции Length, Low, High. Примеры.

Одним из мощнейших средств языка Delphi являются динамические массивы. Их основное отличие от обычных массивов заключается в том, что они хранятся в динамической памяти. Этим и обусловлено их название. Чтобы понять, зачем они нужны, рассмотрим пример:

Var N: Integer; A: array[1..100] of Integer; // обычный массивbegin Write('Введите количество элементов: '); ReadLn(N); ...end.

Задать размер массива A в зависимости от введенного пользователем значения невозможно, поскольку в качестве границ массива необходимо указать константные значения. А введенное пользователем значение никак не может претендовать на роль константы. Иными словами, следующее объявление будет ошибочным:

Var N: Integer; A: array[1..N] of Integer; // Ошибка!begin Write('Введите количество элементов: '); ReadLn(N); ...end.

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

  • На какое количество элементов объявить массив?
  • Что делать, если пользователю все-таки понадобится большее количество элементов?

Можно поступить следующим образом. В качестве верхней границы массива установить максимально возможное (?) количество элементов, а реально использовать только часть массива. Если пользователю потребуется большее количество элементов, чем зарезервировано, то ему можно попросту вежливо отказать. Например:

Const MaxNumberOfElements = 100;var N: Integer; A: array[1.. MaxNumberOfElements] of Integer;begin Write('Введите количество элементов (не более ', MaxNumberOfElements, '): '); ReadLn(N); if N > MaxNumberOfElements then begin Write('Извините, программа не может работать '); Writeln('с количеством элементов больше , ' MaxNumberOfElements, '.'); end else begin ... // Инициализируем массив необходимыми значениями и обрабатываем его end;end.

Такое решение проблемы является неоптимальным. Если пользователю необходимо всего 10 элементов, программа работает без проблем, но всегда использует объем памяти, необходимый для хранения 100 элементов. Память, отведенная под остальные 90 элементов, не будет использоваться ни Вашей программой, ни другими. А теперь представьте, что все программы поступают таким же образом. Эффективность использования оперативной памяти резко снижается.

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

Динамический массив объявляется без указания границ:

array of baseType

Например:

var DynArray: array of Integer;

Работа с динамическими массивами:

1. Переменная DynArray представляет собой ссылку на размещаемые в динамической памяти элементы массива.

2. Изначально память под массив не резервируется, количество элементов в массиве равно нулю, а значение переменной DynArray равно nil.

3. Создание динамического массива (выделение памяти для его элементов) осуществляется процедурой SetLength.

SetLength(DynArray, 50); // Выделить память для 50 элементов

4. Изменение размера динамического массива производится этой же процедурой:

SetLength(DynArray, 100); // Теперь размер массива 100 элементов

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

При уменьшении размера динамического массива лишние элементы теряютяся.

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

5. Определение количества элементов производится с помощью функции Length:

N := Length(DynArray); // N получит значение 100

6. Элементы динамического массива всегда индексируются от нуля.

7. Доступ к ним ничем не отличается от доступа к элементам обычных статических массивов:

DynArray[0] := 5; // Присвоить начальному элементу значение 5DynArray[High(DynArray)] := 10; // присвоить конечному элементу значение 10

8. К динамическим массивам, как и к обычным массивам, применимы функции Low и High, возвращающие минимальный и максимальный индексы массива соответственно. Для динамических массивов функция Low всегда возвращает 0.

9. Освобождение памяти, выделенной для элементов динамического массива, осуществляется установкой длины в значение 0 или присваиванием переменной-массиву значения nil (оба варианта эквивалентны):

SetLength(DynArray, 0); // Эквивалентно: DynArray := nil;

Однако Вам вовсе необязательно по окончании использования динамического массива освобождать выделенную память, поскольку она освобождается автоматически при выходе из области действия переменной-массива (удобно, не правда ли!). Данная возможность обеспечивается механизмом подсчета количества ссылок.

10. При присваивании одного динамического массива другому, копия уже существующего массива не создается.

Var A, B: array of Integer;begin SetLength(A, 100); // Выделить память для 100 элементов A[0] := 5; B := A; // A и B указывают на одну и ту же область памяти! B[1] := 7; // Теперь A[1] тоже равно 7! B[0] := 3; // Теперь A[0] равно 3, а не 5!End.

В приведенном примере, в переменную B заносится адрес динамической области памяти, в которой хранятся элементы массива A (другими словами, ссылочной переменной B присваивается значение ссылочной переменной A).

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

var A, B: array of Integer;begin SetLength(A, 100); // Выделить память для 100 элементов A[0] := 10; B := A; // B указывает на те же элементы, что и A A := nil; // Память еще не освобождается, поскольку на нее указывает B B[1] := 5; // Продолжаем работать с B, B[0] = 10, а B[1] = 5 B := nil; // Теперь ссылок на блок памяти нет. Память освобождаетсяEnd;

11. Для работы с динамическими массивами вы можете использовать знакомую по строкам функцию Copy. Она возвращает часть массива в виде нового динамического массива.

12. Для многомерных динамических массивов:

Var A: array of array of Integer; begin SetLength(A, 100); // Выделить память для 100 элементов for I := Low(A) to High(A) do SetLength(A[I], I);End.

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

12. Множества. Описание, задание, операции над множествами. Примеры.

Объявление множества

Множество — это составной тип данных для представления набора некоторых элементов как единого целого. Область значений этого типа — набор всевозможных подмножеств, составленных из его элементов, включая и пустое множество. Все элементы множества принадлежат к некоторому порядковому типу, который называется базовым типом множества. Базовый тип не может иметь больше, чем 256 возможных значений. Поэтому, в качестве базового типа выбирают либо однобайтовые порядковые типы (AnsiChar, Byte, ShortInt, Boolean, WordBool), либо их некоторое подмножество.

Описание

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

set of baseType

Пример:

type TLetters = set of 'A'..'Z';

Теперь можно объявить переменную множественного типа:

var Letters: TLetters;

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

var Symbols: set of Char;

Доступ

· В выражениях значения элементов множества указываются в квадратных скобках: [2, 3, 5, 7], [1..9], ['A', 'B', 'C'].

· Если множество не имеет элементов, оно называется пустым и обозначается как [ ].

· Пример инициализации множеств:

const Vowels: TLetters = ['A', 'E', 'I', 'O', 'U'];begin Letters := ['A', 'B', 'C']; Symbols := [ ]; { пустое множество }end;

Операции над множествами

При работе с множествами допускается использование операций отношения (=, <>, >=, <=), объединения, пересечения, разности множеств и операции in.

Операции сравнения (=, <>). Два множества считаются равными, если они состоят из одних и тех же элементов. Порядок следования элементов в сравниваемых множествах значения не имеет. Два множества A и B считаются неравными, если они отличаются по мощности или по значению хотя бы одного элемента.

Выражение Результат
[1, 2] <> [1, 2, 3] True
[1, 2] = [1, 2, 2] True
[1, 2, 3] = [3, 2, 1] True
[1, 2, 3] = [1..3] True

Операции принадлежности (>=, <=). Выражение A >= B равно True, если все элементы множества B содержатся во множестве A. Выражение A <= B равно True, если выполняется обратное условие, т.е. все элементы множества A содержатся во множестве B.

Выражение Результат
[1, 2] <= [1, 2, 3] True
[1, 2, 3] >= [1, 2] True
[1, 2] <= [1, 3] False

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

Выражение Результат
5 in [1..9] True
5 in [1..4, 6..9] False

Операция in позволяет эффективно и наглядно выполнять сложные проверки условий, заменяя иногда десятки других операций. Например, оператор

if (X = 1) or (X = 2) or (X = 3) or (X = 5) or (X = 7) then

можно заменить более коротким:

if X in [1..3, 5, 7] then

Операцию in иногда пытаются записать с отрицанием: X not in S. Такая запись является ошибочной, так как две операции следуют подряд. Правильная запись имеет вид: not (X in S).

Объединение множеств (+). Объединением двух множеств является третье множество, содержащее элементы обоих множеств.

Выражение Результат
[ ] + [1, 2] [1, 2]
[1, 2] + [2, 3, 4] [1, 2, 3, 4]

Пересечение множеств (*). Пересечение двух множеств — это третье множество, которое содержит элементы, входящие одновременно в оба множества.

Выражение Результат
[ ] * [1, 2] [ ]
[1, 2] * [2, 3, 4] [2]

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







Последнее изменение этой страницы: 2017-02-08; Нарушение авторского права страницы

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