- •Программирование на языке Delphi.
- •1. Краткий экскурс в историю
- •1.1. Языки программирования
- •1.2. Объектно-ориентированное программирование
- •1.3. Визуальное программирование
- •1.4. Среда программирования Delphi
- •1.5. Технология Java
- •1.6. Среда программирования Kylix
- •1.7. Технология .Net
- •... И опять среда Delphi
- •2. Основы языка Delphi
- •2.1. Алфавит
- •2.1.1. Буквы
- •2.1.2. Числа
- •2.1.3. Слова-идентификаторы
- •2.1.4. Комментарии
- •2.2. Типы данных
- •2.2.1. Понятие типа данных
- •2.2.2. Простые типы данных
- •Целочисленные типы данных
- •Вещественные типы данных
- •Временной тип данных
- •Символьные типы данных
- •Булевские типы данных
- •Определение новых типов данных
- •Перечисляемые типы данных
- •Интервальные типы данных
- •2.3. Данные
- •2.3.1. Константы
- •2.3.2. Переменные
- •2.4. Операции
- •2.4.1. Выражения
- •2.4.2. Арифметические операции
- •2.4.3. Операции отношения
- •2.4.4. Булевские операции
- •2.4.5. Операции с битами (эта часть пока не нужна)
- •2.4.6. Очередность выполнения операций
- •2.5. Строки
- •2.5.1. Строковые значения
- •2.5.2. Строковые переменные
- •2.5.3. Операции над строками
- •2.5.4. Стандартные процедуры и функции для работы со строками
- •2.6. Операторы
- •2.6.1. Общие положения
- •2.6.2. Простые операторы
- •Оператор присваивания
- •Оператор вызова процедуры
- •Пустой оператор
- •Оператор безусловного перехода
- •2.6.3. Структурированные операторы
- •Составной оператор
- •Оператор ветвления if
- •Оператор множественного выбора case
- •Оператор повтора for
- •Оператор повтора repeat
- •Оператор повтора while
- •2.6.4. Прямая передача управления в операторах повтора
- •2.7. Подпрограммы
- •2.7.1. Общие положения
- •2.7.2. Объявление процедур и функций
- •Список формальных параметров
- •Локальные объявления
- •Тип возвращаемого значения
- •Соглашения о вызове подпрограмм
- •2.7.3. Вызов процедур и функций
- •2.7.4. Перегрузка процедур и функций
- •2.7.5. Рекурсивные подпрограммы
- •2.7.6. Упреждающее объявление процедур и функций
- •2.7.7. Процедурные типы данных
- •2.7.8. Стандартные процедуры и функции
- •2.8. Структура программных единиц
- •2.8.1. Структура файла проекта
- •Заголовок программы
- •Подключение модулей
- •Программный блок
- •2.8.2. Структура модуля
- •2.8.3. Стандартные модули языка Delphi
- •2.8.4. Область действия идентификаторов
- •2.9. Массивы
- •2.9.1. Статические массивы
- •2.9.2. Работа с массивами
- •2.9.3. Массивы в параметрах процедур и функций
- •2.9.4. Уплотнение структурных данных в памяти
- •2.9.5. Динамические массивы
- •2.10. Множества
- •2.10.1. Объявление множества
- •2.10.2. Операции над множествами
- •2.10.3. Стандартные процедуры для работы с множествами
- •2.11. Записи
- •2.11.1. Объявление записи
- •2.11.2. Операции над записями
- •2.11.3. Записи с вариантами
- •2.12. Файлы
- •2.12.1. Понятие файла
- •2.12.2. Работа с файлами
- •2.12.3. Стандартные подпрограммы управления файлами
- •2.13. Переменные с непостоянным типом значений
- •2.13.1. Тип данных Variant
- •2.13.2. Значения переменных с типом Variant
- •2.13.3. Variant в выражениях
- •2.13.4. Преобразование вариантов к другим типам данных
- •2.13.5. Подпрограммы для работы с вариантами
- •2.13.6. Вариантные массивы
- •2.14. Указатели
- •2.14.1. Понятие указателя
- •2.14.2. Стандартные указательные типы
- •2.14.3. Динамическое распределение памяти
- •2.14.4. Операции над указателями
- •2.14.5. Процедуры GetMem и FreeMem
- •2.15. Представление строк в памяти
- •2.16. Нуль-терминированные строки
- •2.17.1. Встроенный ассемблер
- •2.17.2. Подключение внешних подпрограмм
- •Delphi 6 в подлиннике
- •Часть I. Введение в delphi 6
- •Глава 1. Среда Delphi 6
- •Глава 2. Язык Object Pascal
- •Глава 3. Использование визуальных компонентов
- •Глава 4. Форма - главный компонент приложения
- •Глава 20. Реляционный способ доступа к данным
- •Глава 21. Работа с отчетами
- •Глава 22. Инструментальные средства
- •Часть V. Удаленные базы данных
- •Глава 23. Введение в работу с удаленными базами данных
- •Глава 24. Работа с удаленными базами данных
- •Глава 25. Инструментальные средства для
- •Глава 26. Трехуровневые приложения
- •Часть VI. Публикация баз данных в интернете
- •Глава 27. Введение в технологии публикаций
- •Глава 28. Web-приложения, серверы и интерфейсы
- •Глава 29. Публикация баз данных средствами Delphi
2.9.4. Уплотнение структурных данных в памяти
С целью экономии памяти, занимаемой массивами и другими структурными данными, вы можете предварять описание типа зарезервированным словом packed, например:
var A: packed array[1..10] of Byte; |
Ключевое слово packed указывает компилятору, что элементы структурного типа должны храниться плотно прижатыми друг к другу, даже если это замедляет к ним доступ. Если структурный тип данных описан без ключевого слова packed, компилятор выравнивает его элементы на 2- и 4-байтовых границах, чтобы ускорить к ним доступ.
Заметим, что ключевое слово packed применимо к любому структурному типу данных, т.е. массиву, множеству, записи, файлу, классу, ссылке на класс.
2.9.5. Динамические массивы
Одним из мощнейших средств языка 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; // Присвоить начальному элементу значение 5 DynArray[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. |
То есть память выделяется для каждой размерности.