Файл: Учебное пособие для студентов Авторы А. Н. Вальвачев, К. А. Сурков, Д. А. Сурков, Ю. М. Четырько Содержание Содержание 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 мы и займемся в следующей главе.