Будь умным!


У вас вопросы?
У нас ответы:) SamZan.net

Стандартные типы данных 2

Работа добавлена на сайт samzan.net:


Структуры данных в Delphi

2.1. Стандартные типы данных

2.1.1. Числовые типы

Некоторые типы данных, стандартные для языка Pascal, немного изменились в сторону расширения диапазона возможных значений и, соответственно, увеличения занимаемого места. Это связано с тем, что создаваемые в Delphi приложения ориентированы на работу в операционной системе Windows, а не DOS, что накладывает на них некоторые требования. Программы, выполняемые в Windows, широко используют системные функции операционной системы, передавая им множество параметров. Таким образом, представление информации в Delphi должно соответствовать представлению аналогичной информации в Windows.

Рассмотрим сравнительные таблицы типов данных в Pascal и Delphi (см. табл. 2.1 и 2.2), в которых указаны сведения о типах данных в Pascal и Delphi. В нижних частях таблиц приводятся сведения о новых типах данных, которых не было в языке Pascal.

Из сравнительных таблиц видно, что среди целочисленных типов данных не произошло существенных изменений, за исключением увеличения диапазона типа Integer. Это связано с частым использованием данного типа при передаче параметров системным функциям Windows. Также добавлены новые Типы Cardinal, Int64 и Longword для более удобной организации структур данных в программе.

Новый целочисленный тип данных Smallint соответствует типу Integer языка Pascal и добавлен в Delphi для упрощения переноса фрагментов текста из старых программ, работающих в операционной системе DOS, которые используют переменные типа Integer и чувствительны к возможному изменению размеров этих переменных. При переносе таких фрагментов ссылки на тип Integer следует заменять на Smallint.

Среди вещественных типов данных изменены возможности типов Real, Extended и Comp, а также, для совместимости с программами, написанными на Turbo Pascal, добавлен новый тип Real48, совпадающий с типом Real   языка Pascal.

Особого внимания заслуживает новый вещественный тип данных Currency, предназначенный для использования в финансовых вычислениях и призванный исключить ошибки искажения значений, присущие переменным с плавающей точкой. Переменные типа Currency на самом деле хранятся не как вещественные переменные, а как целочисленные переменные типа Int64, а при использовании их в выражениях автоматически делятся на 10000. Таким образом, значения переменных типа Currency являются числами не с плавающей точкой, а с фиксированной.

Сравнительная таблица целочисленных типов данных в Pascal и Delphi

Таблица 2.1

2.1.2. Строковые типы данных

В языке программирования Pascal для работы со строками был предусмотрен тип String, представляющий собой последовательность (массив) символов, размером до 255-ти байт, в начале которой находилось однобайтовое число, содержащее длину строки. С другой стороны, в языке С, на который, в основном, ориентируется среда Windows, строки хранятся в так называемом ASCIIZ-формате.

Каждая строка в формате ASCIIZ представляет собой указатель на массив символов, который заканчивается нулевым символом. Такое представление строки имеет свои преимущества — например, практически неограниченная длина ASCIIZ-строк, и свои недостатки — связанные с неудобством использования указателей (ссылочных переменных).

В Delphi предлагается компромисс между двумя подходами к хранению строк. Внутреннее представление строки реализовано динамически, в ASCIIZ-формате, тогда как с точки зрения программиста строка является массивом символов известной длины (символы в массиве пронумерованы от единицы). В связи с этим отменена возможность доступа к нулевому элементу строки с целью получения ее длины. Длину строки в Delphi можно определить с помощью функции Length:

Length(<Строка>):    Integer;

Установить длину строки можно с помощью процедуры SetLength: SetLength(<Строка>,   <Новая   длина>);

Еще одной особенностью работы в среде Windows является возможность использования кодировки символов Unicode, в которой каждый символ представляется не одним, а двумя байтами. Кодировка Unicode предназначена для индексации символов нескольких алфавитов одновременно. Строковые типы данных, доступные в Delphi, описаны в табл. 2.3.

Тип ShortString введен для обратной совместимости с Pascal под DOS и не рекомендуется для использования. Переменной, описанной с использованием устаревшего типа String, назначается тип ShortString, если при компиляции директива н находится в выключенном состоянии: {$н-}, или Ansistring, если при компиляции директива н находится во включенном состоянии: {$Н+}.

Для больи;;::-: Unicode) д.:я вать тип я.-5:

Строковые типы данных в Delphi

Таблица 2.3

Название типа

Максимальная длина, символов

Занимаемая память

Размер символа, байт

ShortString

255

От 2 до 256 байт

1

AnsiString

От 4 байт до 2 Гб

1

WideString

От 4 байт до 2 Гб

2

Для большинства случаев (не связанных с использованием кодировки Unicode) для описания строковых переменных рекомендуется использовать ТИП AnsiString.

2.1.3. Другие стандартные типы данных

Работа с другими типами данных, предусмотренными в Delphi, не отличается от использования аналогичных типов данных в Pascal.

Например, вместо одного логического типа данных в Pascal, в Delphi существует целых четыре: Boolean, ByteBool, WordBool и LongBool. Такое разнообразие типов предусмотрено для обеспечения совместимости с другими языками программирования и средами выполнения. Как видно из их названий, они отличаются друг от друга только размером, и без особой необходимости нет смысла в использовании для описания логических переменных какого-либо другого типа вместо обычного Boolean.

2.2. Описание структур данных

2.2.1. Описание и использование переменных

Описание переменных

Описание переменных производится в разделе описания переменных (после ключевого слова Var) основной части программы, интерфейсных или описательных частях модулей в следующем виде:

Var

<Название переменной

(Начало раздела описания переменных}  <Тип' данных>;

{Описание переменной}

<Название   переменной   N>:   <Тип   данных>;

{Описание   переменной}

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

<Название  переменной  1>,

<Название  переменной М>:   <Тил  данных>;

Оператор присваивания

Для присвоения значения переменной используется оператор присваивания:

<Название   переменной>   :=   <3начение>; Пример использования оператора присваивания приведен в листинге 2.1.

Листинг 2.1. Использование оператора присваивания

Program   UsingVariables;

Var                          {Начало   раздела   описания   переменных}

Int:    Integer;    {Описание   переменной   типа   Integer с   именем   Int}

Begin

Int := 56;    {Присвоение переменной Int значения 56)

End.

2.2.2. Описание констант

Константами называются идентификаторы, вместо которых на этапе компиляции программы подставляются заданные при описании этих констант значения. Соответственно, использование констант не сказывается на непосредственной работе приложения, зато существенно упрощает процесс программирования, делая текст программы более наглядным. Раздел описания констант начинается ключевым словом Const, a сами описания выглядят следующим образом:

Const

<Название   константы>   =   <3начение   константы>;

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

Const

DeveloperName   =   ''Michael   Suharev' ;

{Описание    строковой   константы}

DelphiVersion   =   7;        {Описание   целочисленной   константы}

IncludeOOP   =   True;        {Описание   логической   константы

(типа   Boolean)}

Как и в Pascal под DOS, в Delphi существует возможность описания типизированной константы, которая на самом деле будет являться переменной, причем ее значение будет установлено уже на старте программы. Описание типизированных констант выглядит следующим образом:

Const

<Название   константы>:   <Тип>   =   Оначение   константы>;

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

Const

DelphiVersion: Byte = 7 ;

{Описание целочисленной типизированной константы, значение которой может быть изменено в процессе выполнения программы. Начальное значение константы 7} IncludeOOP: Boolean = True;

{Описание логической константы (типа Boolean), значение которой может быть изменено в процессе выполнения программы. Начальное значение константы True}

2.2.3. Описание нестандартных типов данных

Delphi, как и Pascal, позволяет описывать дополнительные типы данных («нестандартные»), отличные от встроенных (стандартных). При описании могут использоваться как стандартные типы данных, так и нестандартные, то есть описанные ранее в основной части программы или в модуле. После создания нестандартные типы данных могут использоваться для описания переменных на их основе. Само создание нестандартных типов производится в разделах описания типов (после ключевого слова Туре) основной части программы, интерфейсных или описательных частях модулей в следующем виде:

Туре          {Начало   раздела   описания   типов   данных}

<Название   типа   1>   =   <Описание   типа   данных>;

{Описание   типа}

<Название   типа   N>   =   <Описание   типа   данных>;

{Описание   типа}

В качестве примера можно привести описание нестандартного типа данных Mylnteger, эквивалентного стандартному типу Integer.

Program   UsingCustomTypesl;

Type               '                         {Начало   раздела   описания   типов   данных}

Mylnteger   =   Integer;     {Описание   типа   Mylnteger} Begin End.

Аналогичным образом можно описать тип данных otherlnteger, эквивалентный нестандартному типу Mylnteger. Более сложные примеры мы рассмотрим при обсуждении сложных типов данных.

2.3.1.    Интервальные типы данных

Интервальные типы данных (типы-диапазоны) представляют собой подмножества возможных значений стандартных типов данных Integer и Char и применяются для более удобного представления информации в программе. Описание интервального типа данных выглядит следующим образом:

<Название   переменной>   =   <начальное   знач.>..<конечное   знач.>

Использование интервального типа данных аналогично использованию любого другого типа данных. Рассмотрим пример, в котором описывается переменная интервального типа, значениями которой могут быть строчные латинские символы от 'с' до 'у' (см. листинг 2.2).

Листинг 2.2. Использование интервального типа

Program   UsingSubranges; Type

TInterval   =   'с'..'у';

{Описание интервального типа — подмножества типа Char; допустимые значения переменных данного типа находятся в диапазоне от символа 'с' до символа 'у' } Var

Interval: TInterval;

{Описание переменной интервального типа TInterval}

Begin

Interval    :=    'е';

{Присвоение   переменной   Interval   значения    хе'} End.

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

2.3.2. Перечислимые типы данных

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

<Тип> = (<Имя константы

<Имя константы п>);

Перечислимые типы используются для описания множества значений какого-либо свойства, например, цвета некоторого объекта. Описание и использование такого свойства может выглядеть так, как показано в листинге 2.3.

Листинг 2.3. Использование перечислимого типа

Program   UsingEnumerateds; Type

TColor   =    (Black,    White,    Red) ;

{Описание   перечислимого   типа   TColors. Диапазоном   значений   переменных   этого типа   являются   три   константы   —   Black, White,    Red;    значения   этих   констант не   известны,    но   их   можно   использовать по   именам}

Var

Color:    TColor;{Описание перечислимого типа данных} Begin

Color := White;{Присвоение переменной Color значение White}

End.

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

2.3.3. Множества

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

<Переменная>:    Set   Of   <Перечислимый   тип>;

Аналогично можно описать множество на основе интервального типа: <Переменная>:    Set   Of   <Интервальный   тип>;

Для присвоения значения переменной множественного типа используется специальный оператор — конструктор множества [ ]:

<Переменная>    :=    [Оначение   1>,    . . . ,    Оначение   п>] ;

В качестве Значений может быть использовано любое значение из множества, на основе которого создан данный тип.

Рассмотрим пример описания и использования переменной-множества, основанной на перечислимом типе данных (см. листинг 2.4).

Листинг 2.4. Пример описания и использования переменной-множества

Program   UsingSets; Type

TColors   =   Set   Of    (Black,   White,   Red) ;

{описание   множественного   типа   данных TCoiors.    В   качестве   значений   переменных данного   типа   в   любой   момент   времени выполнения   программы   может   быть   любое сочетание   констант   Black,    White   и   Red}

Var

Colors: TColors;

{описание переменной множественного гиг.а данных TColors}

Begin

Colors:=   [Black,   Red];   {присвоение   переменной   Colors

множества,    состоящего   из   двух

элементов   —   Black   и   Red}

Colors :=    [];              {присвоение   переменной   Colors    пустого

множества}

Colors:=   [White];      {присвоение   переменной   Colors

множества,    состоящего   из   одного

элемент.а   —   White} 

End.

При работе с множествами используются следующие понятия:

 Объединением двух множеств называется  множество, содержащее элементы, как первого, так и второго множеств. Для объединения множеств используется оператор «+». Например, после выполнения команды Colors     :=     [Black]     +     [Red],   В  переменной  Colors будет содержаться множество [Black,   Red].

 Пересечением двух  множеств называется множество,  содержащее элементы, включенные в оба множества. Для пересечения множеств используется оператор «*». Например, после выполнения команды Colors     :=    [Black,    Red]     *     [Black,    White],  В  переменной Colors   будет содержаться множество из одного элемента Black.

 Разностью двух множеств называется множество, содержащее элементы первого множества (уменьшаемого), не содержащиеся во втором множестве. Для определения разности множеств используется оператор «-». Например, после выполнения команды Colors    : = [Black,    Red]    -    [Black,   White], в переменной Colors   будет содержаться множество из одного элемента Red.

 Пустым множеством называется множество, не содержащее элементов. Для  присвоения  переменной  множественного типа  пустого множества может использоваться обычный конструктор множества. Например, после выполнения команды Colors   :=   []  в переменной Colors   не будет содержаться ни одного элемента. Множество станет пустым, если вычесть из него множество, содержащее все возможные элементы. Например, после выполнения команды Colors :=   Colors    -    [Black,    White,    Red]   множество Colors    будет пустым вне зависимости от своего начального состояния. 2.3.4. Записи

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

Туре   {начало   раздела   описания   типов   данных} <Имя   типа>=Record       {заголовок   описания   записи} <Имя   переменной   1>:   <Тип>;

{описание   "поля»   записи}

<Имя   переменной   п>:   <Тип>;

{описание   "поля»   записи} end;        {окончание   описания   типа}

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

Описание переменных-записей, или, как их принято называть, экземпляров записей, осуществляется по обычным правилам в разделе описания переменных Var.

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

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

<Имя переменной-экземпляра записи>.<Имя поля>

С полями экземпляров записей можно производить любые операции, допустимые для типа данных этого поля, то есть указывать в качестве параметров процедур и функций, использовать как операнды для арифметических и логических операторов, и так далее. Приведем небольшой пример (листинг 2.5).

Листинг 2.5. Работа с записями

Program UsingRecords;

Type                                       {начало раздела описания типов данных}

Thuman = Record                                  {заголовок описания записи)

FirstName: String; {описание поля записи

с именем FirstName} {описание поля записи с именем LastName} {описание поля записи с именем Age} {окончание описания типа}

Lastame: String; Age: Integer; end;

Var Human1:Thuman; Human2: Thuman;

{Описание переменной — записи типа THuman с именем Human1} {Описание переменной — записи типа THuman с именем Human2}

Begin

Humanl.FirstName

= 'Michael'; {Изменение поля FirstName

переменной Humanl}

Human2 := Humanl; {Копирование значений всех полей записи Humanl в поля записи Human2. Таким образом поле FirstName записи Human2 станет иметь значение 'Michael'}

End.

2.3.5. Массивы

Массив — это поименованная область памяти, доступ к отдельным частям которой осуществляется по общему имени и индексу соответствующей части. Все части (элементы) массива имеют один и тот же тип, в качестве которого может выступать любой из стандартных или нестандартных типов, описанных к моменту объявления массива. В частности, элементы массива также могут являться массивами. Такие структуры называются многомерными.

Описание массива производится в разделе описания типов данных (после ключевого слова Туре) и выглядит следующим образом:

<Наззание   массива>   =  Array   [<Нижний   индекс>..<Верхний   индекс>]

Of   <Тип   элементов>;

Program DeclareArrayTypesl;

Type

MyArray

Begin End.

{Начало раздела описания типов данных) Array [5..150] Of Integer;

{Описание типа данных — массива с именем MуАrrау, состоящего из 14 6-ти элементов, пронумерованных от 5-ти до 150-ти, каждый из которых имеет тип Integer}

С момента такого описания тип MyArray может использоваться наравне с остальными типами данных, известными компилятору, например, для описания двухмерного массива:

Program DeclareArrayTypes2;

Туре         {Начало раздела описания типов данных) MyArray = Array [5..150] Of Integer;

{Описание типа данных — массива с именем MyArray, состоящего из 146-ти элементов, пронумерованных от 5-ти до 150-ти, каждый из которых имеет тип Integer) MyArray2D = Array [1..10] Of MyArray;

{Описание типа данных — массива с именем MyArray2D, состоящего из 10-ти элементов, пронумерованных от 1 до 10-ти, каждый из которых представляет собой массив типа MyArray}

Begin

End.

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

Туре

MyArray2D = Array [1..10, 5..150] Of Integer;

{Описание двухмерного массива)

Описание переменной, представляющей собой массив, происходит по обычным правилам описания переменных:

Туре

MyArray2D = Array [1..10, 5..150] Of Integer;

{Описание двухмерного массива) Var

Array2D: MyArray2D;   {Описание переменной-массива}

Для обращения к элементу массива-переменной, ее индекс (индексы в случае многомерных массивов) указываются в квадратных скобках после имени переменной:

Program   UsingArrays; Type

MyArray2D   =   Array    [1..10,    5..150]    Of   Integer;

{Описание   двухмерного   массива) Var

Array2D:    MyArray2D;         {Описание    переменной-массива} Begin

Array2D    [1,    6]     :=   18; {Присвоение    значение   элементу

массива   с   индексами   1,    6} End.

Обратите внимание, что максимально возможный размер массивов в Delphi увеличен по сравнению с Pascal, и может достигать 2 гигабайт вместо 64 килобайт.

Заметим, что для массивов одного и того же типа, как и для записей, определена операция присвоения, выполняемая копированием значений элементов одного массива в другой. Также доступна операция присвоения для отдельных элементов массивов. Сравнение массивов в целом невозможно и вызывает ошибку компиляции. Однако это доступно динамическим массивам, описанным ниже.

Переменную-массив можно описать и без предварительного создания соответствующего типа данных, прямо в разделе описания переменных:

Var

MyArray2D: Array [1..10, 5..150] Of Integer;

{Описание переменной — двухмерного массива целочисленных элементов;

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

?•::ходит по

Туре

ArrType = Array [1..10] Of Integer;

{Описание типа данных — массива целочисленных элементов}

Var А1

= Array [1..10] Of Integer;

{Описание переменной-массива целочисленных элементов}

А2   =  Array   [1..10]    Of   Integer;

A3:   ArrType;

A4:   ArrType; Begin

A3    :=   A4;

Al    :=  A2;

{Описание   переменной-массива целочисленных   элементов,    полностью идентичной   А1}

{Описание   переменной-массива целочисленных   элементов}

{Операция   допустима,    так   как   обе переменные   имеют   один   и   тот   же тип   —  ArrType}

{Операция   не   допустима,    так   как обе   переменные   имеют   не   один   и   тот же   тип   данных,   а   лишь   похожие   по структуре   типы}

В рассмотренном примере все четыре используемые переменные являются одномерными массивами целочисленных элементов, проиндексированных от 1 до Ю, однако переменные A3 и А4 совместимы между собой, так как при их описании явно указан один и тот же тип, а переменные А1 и А2 не совместимы ни между собой, ни с переменными A3 и А4. Соответственно при попытке компиляции такого фрагмента программы будет выдана ошибка "Incompatible types» - "Несовместимость   типов».

Однако если бы переменные А1 и А2 были описаны в одной строке, то их типы считались бы идентичными:

var

Al, A2

Array [1..10] Of Integer;

{Описание двух переменных-массивов целочисленных элементов}

Begin

Al := А2;

(Операция допустима)

2.4. Динамические структуры данных

Для работы с динамическими структурами данных Turbo Pascal предлагал два вида ссылочных типов — типизированные указатели и нетипизи-рованные.

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

В Delphi сохранены все возможности работы с указателями, а также добавлены новые структуры данных на их основе.

2.4.1. Нетипизированные указатели

Переменные -- нетипизированные указатели описываются с указанием типа Pointer, а выделение и освобождение памяти под них осуществляется, соответсвенно, командами GetMem  и FreeMem  (см. листинг 2.6).

Листинг 2.6. Использование нетипизированных переменных-указателей

Program   UsingPointers; Var

Point:    Pointer;

Begin

GetMem(Point,    1024) ;

FreeMem(Point,    1024)

{Описание   переменной-указателя, указан   тип   Pointer,    то   есть описывается   нетипизированная   ссылка!

{Выделение   памяти   под   переменную-указатель   размером   1024   байт} {Освобождение   памяти,    занятой под   переменную-указатель}

End.

2.4.2. Типизированные указатели

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

Для описания типизированной ссылки не предусмотрен какой-либо специальный тип данных, в отличие от нетипизированных указателей, имеющих тип Pointer. Поскольку ссылочная переменная такого рода всегда указывает на данные конкретного типа, то ее описание и строится на основе этого типа. Для указания на ссылочную природу переменных используется оператор «^», и описание выглядит следующим образом:

Var

<Переменная>:

^<названке   типа>;

Или в разделе описания типов данных:

Туре

<Новый тип данных> = Л<Тип данных>;

После описания переменной-указателя под нее выделяется память только для хранения адреса, а под сами данные, на которые переменная указывает, память не выделяется. Для инициализации переменной используется процедура New, отличием которой от аналогичной процедуры GetMem, используемой для работы с нетипизированными указателями, является отсутствие второго параметра, определяющего размер выделяемой памяти. Это связано с тем, что типизированная ссылка указывает на данные известного типа, соответственно, размер эт^их данных также известен компилятору.

Итак, инициализация переменной выглядит следующим образом:

New(<Типизированный указатель>);

Соответственно, при освобождении памяти, занятой под типизированный

указатель, используется процедура Dispose — аналог процедуры FreeMem без второго параметра:

Dispose(<Типизированный   указатель>);

Обращение к переменной-указателю происходит обычным образом — по ее имени, а для обращения к данным, на которые переменная указывает, после имени переменной указывается оператор разыменовывания «л»:

<Название   переменной>А

Рассмотрим пример работы с типизированной ссылкой, указывающей на переменную типа Double   (см. листинг 2.7).

Begin

New(MyPDouble);

{Выде.-.е.-.-.^ переуе:-н;'.-: опреде~ =-■; ~ памятх   з z .-

MyPDoubleA = 12. {Приев: е-" ссылает ; -.

Dispose(MyPDoubi

End.

котору:-: освобож

MyPDoub

2.4.3.

В Delphi добавлена ин зания размерностей и.

Var

IntArray:   Array

Такие массивы являю длину. Установка разм ния программы произ ций SetLength и Lenc меруются от нуля.

Program   UsingDyna Var

А,    В:   Array   of

Листинг 2.7. Пример работы с типизированной ссылкой

Program   UsingTypedPointers; Type

pDouble   =   "Double;

Var

MyPDouble: pDouble;

{Описание типа данных — указателя на переменную типа Double}

(Описание переменной — типизированного указателя на переменную типа Double}

Begin

New(MyPDouble) ;

{Выделение места в динамической памяти под одну переменную типа Double (размер необходимой памяти определяется автоматически) , адрес выделенной памяти заносится в переменную MyPDouble}

MyPDoubleA = 12.8;

{Присвоение переменной, на которую ссылается переменная-указатель значения 12.8}

Dispose(MyPDouble);

{Освобождение памяти, занятой под переменную, на которую указывает переменная MyPDouble. Адрес освобожденной памяти остается в переменной MyPDouble, но его использование недопустимо} End.

2.4.3. Динамические массивы

В Delphi добавлена интересная возможность описания массивов без указания размерностей и, соответственно, пределов изменения индексов:

Var

IntArray:   Array   Of   Integer;

Такие массивы являются динамическими6 и изначально имеют нулевую длину. Установка размера массива и определение его во время выполнения программы производится так же как и для строк, с помощью функций SetLength и Length, соответственно. Элементы в данном случае нумеруются от нуля.

Program   UsingDynamicArraysl; Var

А,   В:   Array   of   Integer;

{Описание   двух   переменных   —   динамических массивов   целочисленных   элементов}

Begin

SetLength(A,    5)

А[0]     :=   1;

End.

{Установка   размера   массива   А (5   элементов)}

{Присвоение   значения   I   элементу массива   А   с   номером   0}

Заметим, что в Turbo Pascal также существовала возможность использования динамических массивов через типизированные указатели, под которые память выделяется процедурой FreeMem, а не New. Однако о безопасности использования таких структур должен был заботиться программист. Также неудобства доставляла необходимость указания размерностей таких массивов и ограничение максимального числа элементов. В Object Pascal реализована более удобная схема работы с динамическими массивами.

2.5. Вариантные структуры данных

2.5.1. Общие понятия

Структура данных программы на языке Pascal (то есть переменные) описывается в одном месте каждого модуля — в разделе описания переменных. Данный раздел начинается ключевым словом Var и специально предназначен для этого. Таким образом, переменные не могут быть введены во время выполнения программы. Еще одна существенная особенность представления информации в Pascal — это назначение типа переменной на этапе компиляции.

Однако при программировании под Windows довольно часто встречаются задачи, в которых переменные должны изменять свой тип во время выполнения программы, соответственно, нельзя на этапе написания программы указать, какого именно типа должна быть та или иная переменная. В основном такие возможности требуются от программы, работающей с базами данных и использующей технологию СОМ.

В Delphi введена поддержка переменных, которые не имеют конкретного типа данных на этапе компиляции, а в процессе выполнения программы могут хранить данные разных типов. Такие переменные называются вариантными (англ. Variant — вариантный, различный) и описываются по обычным правилам с указанием в качестве типа данных ключевого слова Variant:

Var

<Назвак/!е

леременной>:    Variant;

Во время выполнения программы в вариантных переменных могут храниться данные любого типа, за исключением структурных (записей и статических массивов) и ссылочных (типизированные и нетипизирован-ные указатели, метаклассы и указатели на экземпляры классов7). Также в вариантных переменных не могут находиться значения множественных типов данных. Неинициализированной переменной автоматически присваивается специальная константа Unassigned, описанная в модуле

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

Листинг 2.9. Пример описания и использования вариантной переменной

Program   UsingVariantsl ; Var

V:   Variant;{Описание   вариантной   переменной,

тип   переменной   не   определен}

S:    String;    {Описание   переменной   типа    String} Begin

V   :=   250;        {Присвоение   значения   вариантной   переменной   V,

переменной   назначается   целочисленный   тип   данных;

V   :=    'It   is   a   STRING' ;

{Присвоение значения вариантной переменной V, переменной назначается строковый тип данных}

S := V; {Строковой переменной присваивается строковое значение вариантной переменной}

End.

2.5.3. Определение типа вариантных переменных

Переменная типа Variant занимает в памяти шестнадцать байт, в которых находится информация о типе данных (код типа), хранящихся в данный момент в данной переменной и сами данные, либо указатель на них. Возможные коды типов данных для вариантных переменных, описанные в модуле System, представлены в табл. 2.4.

Для определения типа данных, хранимых в вариантной переменной, используется функция VarType, описанная в модуле Variants в следующем виде:

Function   VarType(const   V:   Variant):    TVarType;

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

♦  нулевое значение $0000 — указывает на то, что данные заявленного типа хранятся непосредственно в вариантной переменной;

♦  значение $2000 (константа varArray модуля System) — указывает на то, что хранимые данные являются массивом элементов, имеющих тип, определяемый кодом типа данных;

♦  значение $4000 (константа varByRef модуля System) — указывает на то, что хранимые данные являются ссылкой на соответствующий тип данных, определяемый кодом типа данных.

Для выделения части значения, содержащей код типа данных, предусмотрена константа varTypeMask (значение $0FFF), с помощью которой можно отделить код типа данных от дополнительных признаков:

<Переменная типа Variant> and varTypeMask

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

S := 'Data element type:  s;

Case VarType(V) and varTypeMask of

varEmpty:     S := S +  xThe variant is UnassignecT ;

varNuil:      S := S +  'The variant is Null';

Таким образом, если в переменной v находится значение 2 0 0, то после выполнения данного фрагмента программы значением переменной s будет строка 'Data element type: A Byte', если переменной v задать значение 1221.66, то в переменной s будет строка 'Data  element   type:

Currency floating-point value (type Currency)'. Если же значение переменной V будет строковым, например, '1221.66', то значением переменной S будет такая строка: 'Data element type: Reference to   a   dynamically   allocated   string'.

2-5.4. Автоматическое приведение типов

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

Допустим, например, что в программе имеется вариантная переменная Vi, которой присвоено значение 2 0 0. После присвоения переменная vi будет целочисленной (иметь тип с кодом varByte):

Vi    :=   200;

Допустим также, что имеется переменная S типа string. Тогда в результате выполнения оператора присваивания s := vi, значением переменной s будет строка '200'. Таким образом, во время выполнения оператора значение целочисленной переменной будет автоматически переведено в строковый вид.

Более того, возможна и обратная ситуация, когда вариантная переменная строкового типа автоматически переводится в численную форму. Однако именно в таких ситуациях могут возникать ошибки времени выполнения. Рассмотрим пример безошибочного использования вариантной переменной (листинг 2.10).

Листинг 2.11. Пример t

Program   UsingVariant Var

V:   Variant;        ; : rv.

I:    Integer;        ::::

Begin V   :=    'a280' ;           .  "

I    :=   V;

End.

Выполнение такой прогг нием об ошибке: "Сс:1: into type (Integer " -Integer". Эта ошибка : вать строку в числовое ъ\ лить целое число именно

Правила трансформации выражениях приведены 5

Листинг 2.10.    Пример безошибочного использования вариантной переменной

Program   UsingVariants2; Var

V:    Variant;

Правила изменения вариантных :■■

I:    Integer; Begin V    :=    v280' ;

I    :=   V;

End.

(Описание   вариантной   переменной,    тип переменной   не   определен} (Описание   переменной   типа   String}

{Присвоение   значения   вариантной   переменной V,    переменной   назначается   строковый   тип данных}

{Целочисленной   переменной   I   присваивается значение   вариантной   переменной   V.    Значение переменной   I         становится   равным   2 80}

Но значением переменной V могла бы быть не строка '280', а, например, строка ‘a28 0' — см. листинг 2.1.1.

Листинг 2.11. Пример возникновения ошибочной ситуации

Program   UsingVariants3 ; Var

V:   Variant;

I:    Integer; Begin V   :=    'a280';

I    :=  V;

End.

{Описание   вариантной   переменной, тип   переменной   не   определен} (Описание   переменной   типа   String}

{Присвоение   значения   вариантной переменной   V,    переменной   назначается строковый   тип   данных}

{Ошибка   времени   выполнения   —   несоответствие типов,    так   как   из   строковой   вариантной переменной   невозможно   выделить   целочисленное   значение}

Выполнение такой программы невозможно и будет прервано с сообщением об ошибке: "Could not convert variant of type (String) into type (Integer)" — "Невозможно- привести тип String к типу Integer". Эта ошибка появляется не из-за невозможности преобразовать строку в числовое значение вообще, а из-за невозможности выделить целое число именно из этой строки.

Правила трансформации вариантных значений при использовании их в выражениях приведены в табл. 2.5.

Правила изменения вариантных значений

Таблица 2.5

Тип переменной источника

Тип переменной-приемника

Целочисленные

Вещественные

Строковые

Логические

Целочисленные

без изменения

без изменения

Перевод в строку

0 -> False, иначе True

Вещественные

округление

без изменения

Перевод в строку

0 -> False, иначе True

Строковые

выделение числа с округлением

выделение числа

без изменения

"false" -> False "true" -> True

если можно выделить число:

0 -> False иначе True

Логические

False -> 'О' True -> '-1

False -> '0' True -> '-1

False -> '0' True -> '-1'

без изменения

Значение Unassigned

0

0

Пустая строка

False

Значение Null

Сообщение об ошибке

2.5.5. Вариантные массивы

Как было отмечено выше, значением вариантной переменной не может являться массив, описанный по обычным правилам. Однако Delphi предлагает специальный вариантный массив, который можно создать с помощью функции VarArrayCreate, описанной в модуле Variants:

Function   VarArrayCreate(const   Bounds: VarType:    TVarType):   Variant;

array   of   Integer;

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

<А2,    В2>,

<An,    Bn>j

Вторым параметром задается тип элементов массива. При этом могут использоваться любые константы, приведенные в табл. 2.4, за исключением varstring, однако для формирования массива строковых элементов допустимо использование константы varOleStr.

Рис. 2.1. Непрямоугольный однородный массив (слева) и неоднородный массив (справа)

Заметим, что вне зависимости от количества измерений массива все его элементы имеют один и тот же тип, указываемый при вызове функции VarArrayCreate, но если в качестве типа элементов задать константу varVariant, то элементом вариантного массива будет также являться вариант.

Следовательно, такому элементу можно присвоить вариантный массив, причем тип его элементов также может быть произвольным. Таким образом, в Delphi появилась возможность создания неоднородных (состоящих из элементов разного типа) массивов, или, например, однородных массивов непрямоугольной формы.

Для получения информации о размерностях и индексации вариантных массивов в модуле Variants   предусмотрены следующие функции:

VarArrayDimCount — возвращает размерность заданного вариантного масива.

♦  VarArrayLowBound — возвращает нижнюю границу индексов заданного вариантного массива для заданного измерения.

♦  VarArrayHighBound — возвращает верхнюю границу индексов заданного вариантного массива для заданного измерения.

Описание этих функций выглядит следующим образом:

Function VarArrayDimCount(const   A:   Variant) :    Integer; Function VarArrayLowBound(const   A:   Variant;   Dim:    Integer):

Integer; Function VarArrayHighBound(const   A:    Variant;    Dim:    Integer):

Integer;

Пример использования и тех, и других приведен в листинге 2.12.

Листинг 2.12. Работа с вариантными массивами

Var

V: Variant;   {Описание вариантной переменной} LI, HI, L2, Н2: Integer;

{Описание четырех целочисленных переменных}

Begin

V := VarArrayCreate ([0, 5, 3, 8], varlnteger) ;

{Создание двухмерного вариантного массива целочисленных элементов, аналогичного по описанию массиву Array[0..5, 3..8] Of Integer}

LI := VarArrayLowBound(V, 1);

{Определение минимально возможного индекса элемента для первого измерения вариантного массива V и занесение его в переменную L1 (значение 0) }

HI := VarArrayHighBound(V, 1);

{Определение максимально возможного индекса элемента для первого измерения вариантного массива V и занесение его в переменную HI (значение 5) }

L2 := VarArrayLowBound(V, 2);

{Определение минимально возможного индекса элемента для второго измерения вариантного массива V и занесение его в переменную L2 (значение 3) }

Н2    :=   VarArrayHighBound(V,    2) ;

{Определение   максимально   возможного   индекса элемента   для   второго   измерения   вариантного массива   V   и   занесение   его   в   переменную   Н2 (значение   8)    )

2.5.6. Разрушение вариантных переменных

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

В случае глобальных переменных разрушение структур данных происходит при присвоении новых значений вариантным переменным или при завершении программы. Это не всегда правильно, так как неиспользуемые глобальные переменные могут неоправданно занимать большой объем памяти, замедляя работу системы в целом. Для немедленного разрушения вариантной переменной предназначена процедура VarClear, по своему действию эквивалентная присвоению переменной значения Unassigned:

Procedure   VarClear(V:   Variant); Например:

Var

V: Variant;

{Описание вариантной переменной)

Begin

V := VarArrayCreate ([0, 5, 3, 8], varlnteger);

{Создание двухмерного вариантного массива)

VarClear(V);

[Разрушение вариантного массива V}

2.6. Выражения в Object Pascal

Выражения в Object Pascal можно разделить на арифметические, логические и строковые.

К арифметическим выражениям относятся операции сложения (используется оператор +), вычитания (используется оператор -), умножения (используется оператор *) и деления (используется оператор /), производимые над вещественными и целочисленными значениями. При использовании в одном выражении значений разных типов, например при умножении целого числа типа integer на вещественное значение типа Double, тип результата выражения устанавливается по типу одного из операндов, имеющего самую широкую область значений.

Var

X,   Rd:   Double; I,   Ri:    Integer;

{Описание   вещественных   переменных   X   и   Rd} {Описание   целочисленных   переменных   I   и   Ri}

Begin

Rd := X * I;

Ri := X

I;

{Попытка присвоения переменной Rd значения арифметического выражения — произведения целочисленной и вещественной переменных I и X. Операция корректна, так как выражение имеет тип Double, как наиболее широкий из типов операндов. Следовательно, результат может быть занесен в переменную Rd, имеющую тип Double} {Попытка присвоения переменной Ri значения арифметического выражения — произведения целочисленной и вещественной переменных I и X. Операция является ошибочной, так как выражение имеет тип Double, как наиболее широкий из типов операндов. Следовательно, результат не может быть занесен в переменную Ri, имеющую тип Integer}

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

Var

N, F: Double; {Списание двух строковых переменных — N и F}

Begin

Var

N    :=    'Ольга';         {Присвоение   переменной   N   значения    'Ольга'} F    :=    'Тихонова';{Присвоение   переменной   F   значения    'Тихонова' N   := N +   '   '   + F;  {Присвоение   переменной   N   результата конкатенации   трех   строк   —   значения переменной   N,    строки,    состоящей   из символа   пробел,    и   значения   переменной   F. В   переменной   N,    таким   образом,    будет содержаться   строка    'Ольга   Тихонова'}

Логические операции представляют собой набор логических операндов (переменных или констант типа Boolean), соединенных логическими операторами And, Or и Not. Оператор And возвращает значение True, если оба операнда имеют значение True. Оператор Or возвращает значение True, если хотя бы один из операторов имеет такое значение. Оператор Not предназначен для работы с одним операндом и инвертирует его значение.

Var А,   В,   С:   Boolean

Begin

А := True; В := True; А    :=   Not   А;

С    :=   A   Or   В;

С    :=   A   And   В;

{Описание   переменных  А,   В  и  С   типа   Boolean

{Присвоение   переменной   А   значения   True} {Присвоение   переменной   В   значения   True} {В   переменную   А   заносится инвертированное   значение   этой   же переменной    (False)}

{В   переменную   С   заносится   результат логического   выражения   A   or   В.    Так   как один   из   операндов    (В)    имеет   значение True,    то   результатом   выражения   также является    значение   True} {В   переменную   С   заносится   результат логического   выражения   A   and   В.    Так   как один   из   операндов    (А)    имеет   значение False,    то   результатом   выражения   также является   значение   False}

Begin

Y    :=   Sin(X);

В выражениях любого вида могут использоваться более сложные конструкции, например:

Var

А, В, С: Double;  {Описание вещественных переменных А, В и С}

Begin

:= А + В * А + В; {В переменную С заносится значение

выражения А + В * А + В, вычисляемого с использованием обычных математических правил: А + (В * А) + В}

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

Var

X,    Y:   Double;

Begin

Y    :=   Sin(X);

{Описание   вещественных   переменных   X   и   Y]

{Присвоение   переменной   Y   значения, возвращаемого   функцией   Sin}




1. познавательный интерес в психологопедагогической литературе Особенности развития познавательного инт
2. Вам предлагается описать свое состояние в данный момент с помощью таблицы состоящей из 30 пар полярных приз
3.  При раздаче горячие блюда супы соусы напитки должны иметь температуру не ниже 75 град
4. Образ Англии в творчестве Е Замятина
5. таки можно- к горести нашей или к счастью но экономические политические и социокультурные перемены нараста
6. 011998 г 1 Общие требования безопасности 1
7. ЛЕКЦИЯМ ПО ПРАВОВЫМ АСПЕКТАМ ДЕЯТЕЛЬНОСТИ ВРАЧАСТОМАТОЛОГА Рекомендуется для направлений под
8. пропаганда здорового образа жизни в семье
9. реферат дисертації на здобуття наукового ступеня кандидата медичних наук Сімферополь 2002
10. Радянський військово морський флот в роки Другої світової війни
11. Основным критерием работоспособности закрытой зубчатой передачи является Бпрочность зубьев на изгиб Г
12. Остеомиелит верхних конечностей
13. ТЕМА 4. ИНФЛЯЦИЯ. ВКЛАДЫ ПО ПЕРВОМУ ТРЕБОВАНИЮ Задание 1.
14. Реформы Петра Великого
15. по теме Статистика рабочего времени
16. Картография (шпаргалка
17. Расследование причин аварий на предприятиях
18. Химик Анри Этьен СентКлер Девилль
19. Апелляция в гражданском процессе
20. Рассмотрено Руководитель ШМО Андреева Ю