
- •Основы программирования
- •Введение
- •Основы delphi
- •Общая технология программирования
- •Язык программирования
- •Объектно-ориентированное программирование
- •Визуальное программирование
- •Событийно управляемое программирование
- •Windows-приложение
- •Среда программирования
- •Первоначальные сведения о проекте приложения
- •Встроенный отладчик
- •Использование встроенных классов
- •Иерархия классов
- •Использование палитры компонентов и инспектора объектов
- •Использование графики
- •Основные инструменты
- •Основные характеристики шрифтов
- •Графические данные и палитра
- •Некоторые общие свойства компонентов
- •Сохранение проекта
- •Построение простейшего проекта
- •Понятие исключительной ситуации
- •Введение в object pascal
- •Структура приложения
- •Структура программы-проекта
- •Структура модуля
- •Пример 1
- •Описания программных элементов
- •Программные элементы и адреса памяти
- •Области видимости
- •Правила записи имен
- •Время жизни идентификаторов
- •Использование локальных переменных в примере 1
- •Использование глобальных переменных в примере 1
- •Простые типы
- •Целые типы
- •Целые типы
- •Некоторые операции с целым типом
- •Символьные типы
- •Логические типы
- •Тип перечень
- •Интервальный тип
- •Вещественный тип
- •Вещественные типы
- •Некоторые операции с вещественным типом
- •Тип дата-время
- •Выражения
- •Константы
- •Типизированные константы.
- •Переменные
- •Операции
- •Унарная операция not (отрицание)
- •Логические операции and, or, xor
- •Функции
- •Порядок вычисления выражений
- •Виды операторов
- •Простые операторы
- •Составной оператор
- •Операторы условного перехода
- •Оператор if
- •Пример 2
- •Оператор case
- •Пример 3
- •Использование enter в примере 3
- •Операторы цикла
- •Оператор цикла for
- •Пример 4
- •Оператор цикла while
- •Пример 5
- •Оператор цикла repeat
- •Пример 6
- •Использование процедур break и continue
- •Пример 7
- •Массивы
- •Статические массивы
- •Динамические массивы
- •Пример 8
- •Пример 9
- •Записи (объединения)
- •Оператор with
- •Пример 10
- •Совместимость и преобразование типов данных
- •Идентичность типов
- •Совместимость типов
- •Совместимость по присваиванию
- •Преобразование типов
- •Операторы обработки исключительных ситуаций
- •Пример 11
- •Множества
- •Операции над множествами
- •Пример 12
- •Вариантный тип данных
- •Процедуры и функции
- •Процедура
- •Функция
- •Рекурсия
- •Формальные и фактические параметры
- •Параметры-значения
- •Параметры-переменные
- •Параметры-константы
- •Параметры без типа
- •Массивы открытого типа
- •Парамеры по умолчанию
- •Процедура exit
- •Директивы подпрограммы
- •Соглашения по передаче данных
- •Директива forward
- •Директива external
- •Директива assembler
- •Перегруженные подпрограммы
- •Пример 13
- •Инкапсуляция
- •Класс как объектный тип
- •Наследование
- •Области видимости
- •Операции is и as
- •Виды методов
- •Методы virtual и полиморфизм
- •Методы dynamic
- •Методы message
- •Методы abstract
- •Методы override
- •Методы class
- •Пример 14
- •Динамическое создание компонентов
- •Использование класса со счетчиком объектов
- •Отслеживание разрушения объектов
- •События
- •Указатели на методы
- •Пример 15
- •Типы ссылки на класс
- •Свойства
- •Свойства simple
- •Свойства enumerated
- •Свойства set
- •Свойства object
- •Свойства array
- •Задание начальных значений свойствам
- •Пример 16
- •Файловые типы
- •Текстовые файлы
- •Типизированные файлы
- •Файлы без типа
- •Дополнительные процедуры и функции
- •Пример 17
- •Компонент tmainmenu
- •Указатели
- •Пример 18
- •Динамические структуры данных
- •Однонаправленные списки
- •Двунаправленные списки
- •Стеки, очереди
- •Бинарные деревья
- •Пример 19
- •Процедурный тип
- •Программные единицы dll
- •Пример 20
- •Технологии программирования
- •Потоки данных
- •Пример 21
- •Пример 22
- •Интерфейс drag and drop
- •Пример 23
- •Технология drag and dock
- •Пример 24
- •Использование функций windows api при работе с файлами
- •Пример 25
- •Использование отображаемых файлов
- •Пример 26
- •Программные потоки
- •Приоритеты потоков
- •Класс tthread
- •Пример 27
- •Использование блокировки в примере 27
- •Многопоточное приложение в примере 28
- •Проблемы синхронизации потоков
- •Список используемых в примерах компонентов
- •Список используемых компонентов и других классов
- •Библиографический список
- •Оглавление
Указатели
Как отмечено было выше, переменные могут располагаться или в статической или в динамической памяти. В первом случае под них выделяется вполне определённый размер памяти и связи между программными элементами устанавливаются на этапе компиляции и компоновки программы. Во втором случае память выделяется на этапе выполнения программы и может уничтожаться, повторно выделяться, что позволяет эффективно её использовать. При этом используется динамическая память – специально выделенная область оперативной памяти – Heap (куча).
К динамическим переменным относятся рассмотренные выше строки и динамические массивы, а также классы. Переменные данного типа называются ссылками. Работа со ссылками, в общем случае, отличается от работы с обычными переменными тем, что необходимо на каком-то этапе выполнения программы выделять память, а затем высвобождать её. Для строк память выделяется автоматически, автоматически строки (почти все типы) и уничтожаются. Это достигается довольно сложной структурой строки (кроме памяти под значение строки выделяется несколько байт для служебных целей). При работе с динамическими массивами приходится иногда (например, при присваивании) учитывать, что это ссылки. Для создания в программе собственных динамических переменных введён в язык Object Pascal тип указатель. Указателем иногда называют любую динамическую переменную.
Существуют стандартные указатели Pointer и типизированные указатели. Переменная-указатель – это переменная, которая хранит не сами данные, а адрес размещения этих данных. Указатели Pointer – это просто адреса без указания, что по этим адресам записано. Типизированные указатели содержат в себе ещё информацию о типе хранимых данных.
При объявлении типизированного указателя задаётся базовый тип данных. В этом случае компилятор легко определяет необходимый размер динамической памяти, который требуется выделить данному указателю. Объявление типизированного указателя записывается, например, следующим образом:
Type Mas=array [1..10] of real;
PtrMas=^Mas;
Var P:PtrMas;
Это же можно записать по-другому:
Var P:^array [1..10] of real;
Здесь объявлен указатель P, который является физическим носителем адреса расположения одномерного массива из 10 вещественных чисел.
В соответствии с объявлением указателя выделяется всего 4 байта статической памяти для записи адреса. Для записи данных вначале необходимо выделить динамическую память, её адрес записать в переменную-указатель и после этого размещать данные. Рассмотрим, как синтаксически это может быть записано. Объявим две переменные:
Var P1: ^Integer; D: Integer;
Теперь запишем:
New(P1); P1^:=5; D:=2+P1^; Dispose(P1);
Здесь первый оператор выделяет память, второй записывает число 5. Третий выполняет сложение с содержимым выделенной динамической памяти. Четвёртый освобождает занятую память.
Указателю можно присваивать значение nil – пустой адрес, например, P1:=nil;
Для задания значения указателю можно воспользоваться операцией взятия адреса, например, P1:=@D;
В данном случае показано, что указателю можно присваивать адрес в статической памяти.
Стандартный указатель объявляется, например, так:
Var PP:Pointer;
Память под этот указатель выделяется с помощью следующей процедуры: GetMem(PP, 20);
Здесь выделено 20 байт динамической памяти. Эту процедуру можно использовать и для выделения памяти под типизированные указатели, например, для объявленного выше указателя P:
GetMem(P, SizeOf(Mas));
Функция SizeOf(T) используется для указания размера базового типа для переменной-указателя, здесь T – базовый тип данных. Если память выделена процедурой GetMem(<указатель>, Size), то для освобождения памяти используется процедура FreeMem(<указатель>, Size). Например, FreeMem(P, SizeOf(Mas));
К указателям применимы две операции сравнения равно и не равно. Возможно присваивание их друг другу, например, если объявлено:
Var P1, P2: ^double; P3: Pointer;
то возможны присваивания: P2:=P1; или P3:=P2;
Нельзя присваивать P2:=P3, так как переменная P2 требует задания базового типа, а P3 его не имеет. Присваивание P3:=P2 происходит с потерей информации о базовом типе.
Для проверки значения указателя на неравенство nil можно использовать функцию Assigned(<указатель>). Эта функция возвращает true, если значение указателя не равно nil. В модулях System и SysUtils размещены различные стандартные подпрограммы работы с указателями и динамической памятью.
Рассмотрим, каков синтаксис присваивания значений элементам массива P, объявленного выше.
New(P); P^[1]:=6.7; P^[2]:=-3.5; и т.д.
По окончании работы с массивом занятую память нужно освободить: Dispose(P);