Файл: Учебное пособие для студентов Авторы А. Н. Вальвачев, К. А. Сурков, Д. А. Сурков, Ю. М. Четырько Содержание Содержание 1.doc
ВУЗ: Не указан
Категория: Не указан
Дисциплина: Не указана
Добавлен: 04.05.2024
Просмотров: 152
Скачиваний: 4
ВНИМАНИЕ! Если данный файл нарушает Ваши авторские права, то обязательно сообщите нам.
Также, как и при работе со строками, при присваивании одного динамического массива другому, копия уже существующего массива не создается.
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;
Для работы с динамическими массивами вы можете использовать знакомую по строкам функцию Copy. Она возвращает часть массива в виде нового динамического массива.
Не смотря на сильное сходство динамических массивов со строками, у них имеется одно существенное отличие: отсутствие механизма копирования при записи (copy-on-write).
2.18. Нуль-терминированные строки
Кроме стандартных строк ShortString и AnsiString, в языке Delphi поддерживаются нуль-терминированные строки языка C, используемые процедурами и функциями Windows. Нуль-терминированная строка представляет собой индексированный от нуля массив ASCII-символов, заканчивающийся нулевым символом #0. Для поддержки нуль-терминированных строк в языке Delphi введены три указательных типа данных:
type
PAnsiChar = ^AnsiChar;
PWideChar = ^WideChar;
PChar = PAnsiChar;
Типы PAnsiChar и PWideChar являются фундаментальными и на самом деле используются редко. PChar — это обобщенный тип данных, в основном именно он используется для описания нуль-терминированных строк.
Ниже приведены примеры объявления нуль-терминированных строк в виде типизированных констант и переменных:
const
S1: PChar = 'Object Pascal'; // #0 дописывается автоматически
S2: array[0..12] of Char = 'Delphi/Kylix'; // #0 дописывается автоматически
var
S3: PChar;
Переменные типа PChar являются указателями, а не настоящими строками. Поэтому, если переменной типа PChar присвоить значение другой переменной такого же типа, то в результате получится два указателя на одну и ту же строку, а не две копии исходной строки. Например, в результате оператора
S3 := S1;
переменная S3 получит адрес уже существующей строки 'Object Pascal'.
Для удобной работы с нуль-терминированными строками в языке Delphi предусмотрена директива $EXTENDEDSYNTAX. Если она включена (ON), то появляются следующие дополнительные возможности:
-
массив символов, в котором нижний индекс равен 0, совместим с типом PChar; -
строковые константы совместимы с типом PChar. -
указатели типа PChar могут участвовать в операциях сложения и вычитания с целыми числами; допустимо также вычитание (но не сложение!) указателей.
В режиме расширенного синтаксиса допустимы, например, следующие операторы:
S3 := S2; // S3 указывает на строку 'Delphi/Kylix'
S3 := S1 + 7; // S3 указывает на подстроку 'Pascal'
В языке Delphi существует богатый набор процедур и функций для работы с нуль-терминированными строками (см. справочник по среде Delphi).
2.19. Переменные с непостоянным типом значений
2.19.1. Тип данных Variant
В среде Delphi определен стандартный тип данных Variant, с помощью которого объявляются переменные с непостоянным типом значений. Такие переменные могут принимать значения разных типов данных в зависимости от типа выражения, в котором используются. Следующий пример хорошо демонстрирует мощь переменных с непостоянным типом значений:
program Console;
{$APPTYPE CONSOLE}
uses
SysUtils;
var
V1, V2, V3, V4: Variant;
begin
V1 := 5; // целое число
V2 := 0.8; // вещественное число
V3 := '10'; // строка
V4 := V1 + V2 + V3; // вещественное число 15.8
Writeln(V4); // 15.8
Writeln('Press Enter to exit...');
Readln;
end.
2.19.2. Значения переменных с типом Variant
Переменные с непостоянным типом содержат целые, вещественные, строковые, булевские значения, дату и время, массивы и др. Кроме того, переменные с типом Variant принимают два специальных значения: Unassigned и Null.
Значение Unassigned показывает, что переменная является нетронутой, т.е. переменной еще не присвоено значение. Оно автоматически устанавливается в качестве начального значения любой переменной с типом Variant.
Значение Null показывает, что переменная имеет неопределенное значение. Если в выражении участвует переменная со значением Null, то результат всего выражения тоже равен Null.
Переменная с типом Variant занимает в памяти 16 байт. В них хранятся текущее значение переменной (или адрес значения в динамической памяти) и тип этого значения.
Тип значения выясняется с помощью функции
VarType(const V: Variant): Integer;
Возвращаемый результат формируется из констант, перечисленных в таблице 2.10. Например, следующий условный оператор проверяет, содержит ли переменная строку (массив строк):
if VarType(V) and varTypeMask = varString then ...
Код типа | Значение | Описание |
varEmpty | $0000 | Переменная содержит значение Unassigned. |
varNull | $0001 | Переменная содержит значение Null. |
varSmallint | $0002 | Переменная содержит значение типа Smallint. |
varInteger | $0003 | Переменная содержит значение типа Integer. |
varSingle | $0004 | Переменная содержит значение типа Single. |
varDouble | $0005 | Переменная содержит значение типа Double. |
varCurrency | $0006 | Переменная содержит значение типа Currency. |
varDate | $0007 | Переменная содержит значение типа TDateTime. |
varOleStr | $0008 | Переменная содержит ссылку на строку формата Unicode в динамической памяти. |
varDispatch | $0009 | Переменная содержит ссылку на интерфейс IDispatch (интерфейсы рассмотрены в главе 6). |
varError | $000A | Переменная содержит системный код ошибки. |
varBoolean | $000B | Переменная содержит значение типа WordBool. |
varVariant | $000C | Элемент варьируемого массива содержит значение типа Variant (код varVariant используется только в сочетании с флагом varArray). |
varUnknown | $000D | Переменная содержит ссылку на интерфейс IUnknown (интерфейсы рассмотрены в главе 6). |
varShortint | $0010 | Переменная содержит значение типа Shortint |
varByte | $0011 | Переменная содержит значение типа Byte. |
varWord | $0012 | Переменная содержит значение типа Word |
varLongword | $0013 | Переменная содрежит значение типа Longword |
varInt64 | $0014 | Переменная содержит значение типа Int64 |
varStrArg | $0048 | Переменная содержит строку, совместимую со стандартом COM, принятым в операционной системе Windows. |
varString | $0100 | Переменная содержит ссылку на длинную строку. |
varAny | $0101 | Переменная содержит значение любого типа данных технологии CORBA |
Флаги | ||
varTypeMask | $0FFF | Маска для выяснения типа значения. |
varArray | $2000 | Переменная содержит массив значений. |
varByRef | $4000 | Переменная содержит ссылку на значение. |
Таблица 2.10. Коды и флаги варьируемых переменных
Функция
VarAsType(const V: Variant; VarType: Integer): Variant;
позволяет вам преобразовать значение варьируемой переменной к нужному типу, например:
V1 := '100';
V2 := VarAsType(V1, varInteger);
Пока это все, что нужно знать о типе Variant, но мы к нему еще вернемся при обсуждении технологии COM Automation.
2.20. Delphi + ассемблер
В процессе разработки программы вы можете неожиданно обнаружить, что описанных выше средств языка Delphi для решения некоторых насущных проблем явно недостаточно. Например, организация критичных по времени вычислений требует использования ассемблера. Кроме того, часто возникает необходимость включить в программу на языке Delphi откомпилированные ранее процедуры и функции, написанные на ассемблере. Разработчики языка учли эти проблемы и дали программисту необходимые средства их решения.
2.20.1. Встроенный ассемблер
Пользователю предоставляется возможность делать вставки на встроенном ассемблере в исходный текст на языке Delphi.
К встроенному ассемблеру можно обратиться с помощью зарезервированного слова asm, за которым следуют команды ассемблера и слово end:
asm
<оператор ассемблера>
...
<оператор ассемблера>
end;
На одной строке можно поместить несколько операторов ассемблера, разделенных двоеточием. Если каждый оператор размещен на отдельной строке, двоеточие не ставится.
В языке Delphi имеется возможность не только делать ассемблерные вставки, но писать процедуры и функции полностью на ассемблере. В этом случае тело подпрограммы ограничивается словами asm и end (а не begin и end), между которыми помещаются инструкции ассемблера. Перед словом asm могут располагаться объявления локальных констант, типов, и переменных. Например, вот как могут быть реализованы функции вычисления минимального и максимального значения из двух целых чисел:
function Min(A, B: Integer): Integer; register;
asm
CMP EDX, EAX
JGE @@1
MOV EAX, EDX
@@1:
end;
function Max(A, B: Integer): Integer; register;
asm
CMP EDX, EAX
JLE @@1
MOV EAX, EDX
@@1:
end;
Обращение к этим функциям имеет привычный вид:
Writeln(Min(10, 20));
Writeln(Max(10, 20));
2.20.2. Подключение внешних подпрограмм
Программисту предоставляется возможность подключать к программе или модулю отдельно скомпилированные процедуры и функции, написанные на языке ассемблера или C. Для этого используется директива компилятора $LINK и зарезервированное слово external. Директива {$LINK <имя файла>} указывает подключаемый объектный модуль, а
external сообщает компилятору, что подпрограмма внешняя.
Предположим, что на ассемблере написаны и скомпилированы функции Min и Max, их объектный код находится в файле MINMAX.OBJ. Подключение функций Min и Max к программе на языке Delphi будет выглядеть так:
function Min(X, Y: Integer): Integer; external;
function Max(X, Y: Integer): Integer; external;
{$LINK MINMAX.OBJ}
В модулях внешние подпрограммы подключаются в разделе implementation.
2.21. Итоги
Все, что вы изучили, называется языком Delphi. Мы надеемся, что вам понравились стройность и выразительная сила языка. Но это всего лишь основа. Теперь пора подняться на следующую ступень и изучить технику объектно-ориентированного программирования, без которого немыслимо стать профессиональным программистом. Именно этим вопросом в рамках применения объектов в среде Delphi мы и займемся в следующей главе.