Численные переменные и типы данных. ProDelphi - Тип данных Пример четвёртый - вычитание в цикле

О чём не пишут в книгах по Delphi Григорьев А. Б.

3.2.2. Вещественные типы Delphi

В Delphi существует четыре вещественных типа: Single , Double , Extended и Real . Их общий формат одинаков (рис. 3.1, а).

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

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

а) общий вид вещественного числа

б) Двоичное представление числа типа Single

Рис. 3.1. Хранение вещественного числа в памяти

Микропроцессор Intel 8086/88 и его улучшенные варианты - 80286 и 80386 - также не имели аппаратной поддержки вещественных чисел. Но у систем на базе этих процессоров была возможность подключения так называемого сопроцессора. Эта микросхема работала с памятью через шины основного процессора и обеспечивала аппаратную поддержку вещественных чисел. В системах средней руки гнездо сопроцессора обычно было пустым, т. к. это уменьшало цену (разумеется, вставить туда сопроцессор не было проблемой). Для каждого центрального процессора выпускались свои сопроцессоры, маркировавшиеся Intel 8087, 80287 и 80387 соответственно. Были даже сопроцессоры, выпускаемые другими фирмами. Они работали быстрее, чем сопроцессоры Intel, но появлялись на рынке позже. Тип вещественных чисел, поддерживаемый сопроцессорами, не совпадает с Real . Он определяется стандартом IEEE (Institute of Electrical and Electronics Engineers).

Чтобы обеспечить в своих системах поддержку типов IEEE, Borland вводит в Turbo Pascal типы Single , Double и Extended . Extended - это основной для сопроцессора тип, a Single и Double получаются из него очень простым усечением. Система команд сопроцессора допускает работу с этими типами: при загрузке числа типа Single или Double во внутренний регистр сопроцессора последний конвертирует их в Extended . Напротив, при выгрузке чисел этих типов из регистра в память сопроцессор усекает их до нужного размера. Внутренние же операции всегда выполняются с данными типа Extended (впрочем, из этого правила есть исключение, на котором мы остановимся позже, после детального рассмотрения формата различных типов). Single и Double позволяют экономить память. Ни один из них также не совпадает с типом Real . В системах с сопроцессорами новые типы обрабатываются заметно (в 2–3 раза) быстрее, чем Real (это с учетом того, что тип Real после соответствующего преобразования также обрабатывался сопроцессором; если же сравнивать обработку типа Extended на машине с сопроцессором и Real на машине без сопроцессора, то там на отдельных операциях достигалась разница в скорости примерно в 100 раз). Чтобы программы с этими типами можно было выполнять и в системах без сопроцессора, была предусмотрена возможность подключать к ним программный эмулятор сопроцессора. Обработка этих типов эмулятором была медленнее, чем обработка Real .

Начиная с 486-й серии Intel берет курс на интеграцию процессора и сопроцессора в одной микросхеме. Процент брака в микросхемах слишком велик, поэтому Intel идет на хитрость: если у микросхемы брак только в сопроцессорной части, то на этом кристалле прожигаются перемычки, блокирующие сопроцессор, и микросхема продается как процессор 80486SX, не имеющий встроенного сопроцессора (в отличие от полноценной версии, которую назвали 80486DX). Бывали и обратные ситуации, когда сопроцессор повреждений не имел, зато процессор был неработоспособен. Такие микросхемы превращали в "сопроцессор 80487". Но это уже из области экзотики, и, по имеющейся у нас информации, до России такой сопроцессор не дошел.

Процессор Pentium во всех своих вариантах имел встроенный блок вычислений с плавающей точкой (FPU - Floating Point Unit), и отдельный сопроцессор ему не требовался. Таким образом, с приходом этого процессора тип Real остался только для обратной совместимости, а на передний план вышли типы Single , Double и Extended . Начиная с Delphi 4, тип Real становится синонимом типа Double , а старый 6-байтный тип получает название Real48 .

Примечание

Существует директива компилятора {$REALCOMPATIBILITY ON/OFF} , при включении которой (по умолчанию она отключена) Real становится синонимом Real48 , а не Double .

Размеры полей для различных вещественных типов указаны в табл. 3.1.

Таблица 3.1. Размеры полей в вещественных типах

Тип Размер типа, байты Размер мантиссы, биты Размер экспоненты, биты
Single 4 23 8
Double 8 52 11
Extended 10 64 15
Real 6 40 7

Другие параметры вещественных типов, такие как диапазон и точность, можно найти в справке Delphi.

Из книги Язык программирования С# 2005 и платформа.NET 2.0. автора Троелсен Эндрю

Типы, характеризуемые значениями, ссылочные типы и оператор присваивания Теперь изучите следующий метод Main() и рассмотрите его вывод, показанный на рис. 3.12.static void Main(string args) { Console.WriteLine("*** Типы, характеризуемые значением / Ссылочные типы ***"); Console.WriteLine(-› Создание p1"); MyPoint

Из книги Советы по Delphi. Версия 1.0.6 автора Озеров Валентин

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

Из книги Интернет решения от доктора Боба автора Сворт Боб

Типы, характеризуемые значениями, и ссылочные типы: заключительные замечания Чтобы завершить обсуждение данной темы, изучите информацию табл. 3.8, в которой приводится краткая сводка основных отличий между типами, характеризуемыми значением, и ссылочными типами.Таблица

Из книги Delphi. Трюки и эффекты автора Чиртик Александр Анатольевич

Из книги Фундаментальные алгоритмы и структуры данных в Delphi автора Бакнелл Джулиан М.

1.3.3. Delphi и CGI В данной главе я расскажу, как написать простое Дельфи CGI приложение, без использования Web Modules или других Client/Server модулей.Во первых аббревиатура CGI означает Common Gateway Interface, и это только имя для передачи информации от клиента серверу. На клиентской стороне это

Из книги Мир InterBase. Архитектура, администрирование и разработка приложений баз данных в InterBase/FireBird/Yaffil автора Ковязин Алексей Николаевич

2.1.1. Delphi и HTML Мой главный инструмент разработчики это Дельфи, и мы напишем Delphi Database HTML Expert в данной главе. Дельфи позволяет подсоединяться практически к базе данных любого формата. С помощью BDE к Парадоксу и dBASE, с помощью ODBC например к Access, и с помощью SQL Links к большим DBMS типа

Из книги Виртуальная библиотека Delphi автора

9.3. Использование OLE в Delphi Как и многие современные среды программирования, Delphi поддерживает возможность автоматизированной разработки приложений, работающих с различными СОМ-сервисами или серверами. Для более глубокого понимания принципов работы приложений,

Из книги Описание языка PascalABC.NET автора Коллектив РуБоард

Типы массивов в Delphi В Delphi имеется три типа поддерживаемых языком массивов. Первый - стандартный массив, который объявляется с помощью ключевого слова array. Второй тип был впервые введен в Delphi 4 в качестве имитации того, что было давным-давно доступно в Visual Basic, - динамический

Из книги Язык программирования ABC PASCAL автора Цветков Александр Станиславович

Вещественные типы данных К вещественным типам (их еще называют типами чисел с плавающей точкой) относятся FLOAT и DOUBLE PRECISION. Сразу следует предостеречь читателя от использования типа FLOAT - его точность недостаточна для хранения большинства дробных значений. Особенно не

Из книги автора

Вопросы по Delphi 2.0 Что нового в Delphi 2.0 по сравнения с Delphi 1.0? Выпущенная в феврале 1995 года версия Delphi 1.0 стала первым инструментом для Windows, комбинирующим оптимизирующий компилятор, механизмы визуальной разработки Two-Way-Tools и масштабируемую архитектуру обработки баз данных.

Из книги автора

Что нового в Delphi 2.0 по сравнения с Delphi 1.0? Выпущенная в феврале 1995 года версия Delphi 1.0 стала первым инструментом для Windows, комбинирующим оптимизирующий компилятор, механизмы визуальной разработки Two-Way-Tools и масштабируемую архитектуру обработки баз данных. Сегодня сотни

Из книги автора

Из книги автора

Из книги автора

Вещественные типы Ниже приводится таблица вещественных типов, содержащая их размер, количество значащих цифр и диапазон допустимых значений: Тип Размер, байт Количество значащих цифр Диапазон значений real 8 15-16 -1.8?10308 .. 1.8?10308 double 8 15-16 -1.8?10308 ..

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

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

Место описания данных в программе - вне логических блоков begin / end . В модуле перед ключевым словом implementation есть блок описания:

var
Form1: TForm1;

Именно здесь, начиная со следующей строки, удобно объявлять глобальные переменные и константы. Как видим, одна (Form1) уже есть!

Команда объявления переменных в языке Delphi :

var имя_переменной : тип_переменной ;

Слово var - ключевое. Именем может быть любой идентификатор, если он не был описан ранее и не является одним из ключевых или зарезервированных слов языка Delphi . Если нужно описать несколько переменных одного типа, то их перечисляют, отделяя запятой:

var A, B, C : Integer;

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

var A, B : Integer;
C, D : String;

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

const pi= 3.1415 ;
ZnakPi : String = "Это значение числа пи" ;

К слову, константа Pi встроенная в Delphi, то есть для того чтобы использовать в Delphi число 3,1415... в расчётах, нужно просто присвоить встроенную константу Pi переменной типа Real или просто использовать непосредственно в выражениях.

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

Строкой называется последовательность символов, заключённая в одиночные кавычки:
"это текстовая строка" Если текст должен содержать сам символ кавычки, то его надо повторить дважды:
"это "" - символ одиночной кавычки" Строка может быть и пустой, не содержащей символов. Тогда она состоит из двух идущих друг за другом без пробела кавычек. Естественно, строка может состоять и только из одних пробелов.
Самый популярный строковый тип - String . Строка типа String может содержать переменное количество символов объёмом до 2 Гбайт. Если нужно ограничить размер строки фиксированным значением, то после ключевого слова String в квадратных скобках указывается число, определяющее количество символов в строке: String . Более полно работа со строками Delphi описывается далее.
Одиночный символ имеет тип Char и записывается в виде знака в одиночных кавычках: "a" . Есть символы, которые на экране отобразить невозможно, например, символ конца строки (равен #13), символ переноса строки (равен #10). Такие символы записываются в виде их числового кода (в кодировке ANSI ), перед которым стоит знак # . Например, #0 .
Наконец, существуют так называемые нуль-терминированные строки. Отсчёт символов в таких строках начинается с нуля, а заканчивается символом с кодом 0 (#0 ). Такие строки имеют тип PChar .

Числа бывают целые и дробные .
В следующей таблице перечислены стандартные типы целых чисел и соответствующие им дипазоны допустимых значений.

Дробные числа имеют дробную часть, отделяемую десятичной точкой. Допускается использование символа e (или E ), за которым следует число, указывающее, что левую часть нужно умножить на 10 в соответствующей степени: 5e25 - пять умножить на десять в двадцать пятой степени.
Ниже приведены стандартные типы дробных чисел и соответствующие им диапазоны допустимых значений. Для большинства типов указан диапазон положительных значений, однако допустимым является аналогичный диапазон отрицательных значений, а также число 0 .

Следующим типом данных является логический Boolean , состоящий всего из двух значений: True (Истина) и False (Ложь). При этом True > False .

Теперь, используя компоненты, их свойства и события, вводя собственные переменные, можно конструировать программы, содержащие вычисления. Осталось узнать, как вычисленное значение вывести на экран.
Про консольные программы я здесь не говорю ! А в нормальных оконных Windows-приложениях это значение нужно поместить в какой-нибудь компонент, имеющий свойства Text или Caption . Это, например, такие компоненты как Label и Edit , да и сама Форма имеет свойство Caption , куда тоже можно выводить информацию. Однако, в Delphi информацию перед выводом, как правило, необходимо преобразовывать. Так как присвоение возможно только между переменными одного типа, то такая программа (не пытайтесь её исполнять):

var A, B, C: Integer ;
begin
A:= 5 ;
B:= 10 ;
C:= A+B ;
Label1.Caption:= C ;
end ;

Вызовет ошибку, так как свойство Caption имеет текстовый тип String , а использованные переменные - цифровой тип Integer . Значит, нужно преобразовать значение переменной C в текстовый тип. Для этого есть встроенная функция IntToStr . Строка в нашей "программе", вызывавшая ошибку, должна выглядеть так:

Label1.Caption:= IntToStr(C) ;

Такая программа, кроме показа числа 15 , ни на что не способна. Мы должны научиться вводить в программу другие числа. Используем компоненты Edit . Введённые числа будут содержаться в свойстве Text этих компонентов. Расположим на форме два компонента Edit , один компонент Label и кнопку Button , по нажатию на которую и будем проводить вычисления. В компоненты Edit1 и Edit2 будем вводить числа для суммирования. Чтобы переместиться в редактор кода, щёлкнем дважды по нашей кнопке Button1. Мы попадём прямо в сформированную для нас средой Delphi заготовку обработчика нажатия на кнопку, непосредственно между операторами begin и end . Напишем такой простой код:

procedure TForm1.Button1Click(Sender: TObject);
var A, B, C: Integer;//Не забудьте описание переменных
begin
//Начало кода:
A:= Edit1.Text;
B:= Edit2.Text;
C:= A+B;
Label1.Caption:= IntToStr(C);
//Конец кода
end ;

При попытке исполнить этот код Delphi покажет ошибки по аналогичной причине - переменные A и B имеют цифровой тип Integer , а свойство Text - текстовый тип String . Исправить ошибки поможет встроенная функция StrToInt , выполняющая обратное преобразование - текст в целое число. Операторы присвоения переменным A и B должны выглядеть так:

A:= StrToInt(Edit1.Text);
B:= StrToInt(Edit2.Text);

В данном случае переменные A, B, C использовались для наглядности. Можно обойтись одной строчкой:

Label1.Caption:=IntToStr(StrToInt(Edit1.Text)+StrToInt(Edit2.Text));

Аналогично, имеются функции и для преобразования в строку и обратно действительных чисел c плавающей (Float ing англ.) запятой, имеющих тип Real . Для преобразования в строку - FloatToStr , обратно - StrToFloat .
Часто результаты вычислений, имеющие тип Delphi Real , имеют после запятой длинный "хвост" цифр. При выводе такой переменной в текстовом виде необходимо ограничить количество цифр после запятой. Как это можно сделать, описывается также в Уроке Delphi

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

Пользовательские типы данных

При разработке программ довольно часто оказывается недостаточно тех типов данных, которые представлены языком программирования. Например, бывает удобным совместить в одной переменной сразу ряд однотипных данных, или же предусмотреть хранение данных разных типов, например, строк и чисел. К счастью, в Object Pascal имеется возможность создавать собственные типы данных на основе уже имеющихся, совмещая их, или комбинируя. Например, для создания упорядоченного списка однотипных данных используют массивы (arrays), а для объединения нескольких типов в один - записи (records).

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

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

Массивы

Массив - это упорядоченная структура, состоящая из множества однотипных элементов, имеющих общее имя. Таким образом, при помощи всего лишь одной переменной можно хранить целый набор данных, при этом каждый элемент массива имеет свой собственный индекс, или индексы - в случае, если массив многомерный. Массив объявляется в Object Pascal при помощи ключевого слова Array, необязательных квадратных скобок с указанием числа элементов массива, и типа данных для элементов массива:

Array [индексы] of ;

Количество индексов определяет размерность массива. Так, для одномерного массива (в математике - вектор) требуется всего один индекс, а для двумерного массива (матрицы) понадобится 2 индекса и т.д. Объявления массивов могут выглядеть так:

Type MyArray1 = array of integer; type MyArray2 = array of integer;

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

Var A1: MyArray1;

Другим вариантом создания массива является одновременное объявление как переменной, так и описания массива:

Var A1: array of Integer;

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

Var DynArray: array of integer;

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

SetLength(DynArray, 10);

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

Для обращения к конкретному элементу массива используется индекс (или индексы) элемента в массиве. Так, первый элемент в массиве типа MyArray1 (array ) имеет индекс, равный 1, а последний - 100. Соответственно, чтобы обратиться к первому элементу массива, скажем для того, чтобы присвоить ему значение, используются записи подобного типа:

A1 := 10;

Здесь мы присвоили элементу массива A1 с индексом 1 значение 10. Считывание данных производится аналогичным образом:

В данном случае переменной x будет присвоено значение 1-го элемента массива A1. При этом важно, чтобы было соблюдено 2 условия: во-первых, тот элемент массива, к которому идет обращение, должен существовать. Т.е. если обратиться к 11-му элементу массива, состоящего из 10 элементом, то произойдет ошибка доступа к памяти. Во-вторых, тип присваиваемых данных должен совпадать. Иначе говоря, если массив определен как целочисленный, то только целочисленные значения можно ему присваивать. При обратной же ситуации (считывания данных) правила несколько мягче, поскольку целое число можно присвоить переменой как целочисленного, так и вещественного типа.

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

Var A1: array of integer; var A2: array of array of integer; ... A1:=5; A2:=5; A1:=5; A2:=5;

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

Var DynArray: array of array of real;

При выделении памяти под такой массив так же следует учитывать его размерность. Например, если требуется массив размером 10 на 20 элементов, то следует использовать процедуру SetLength со следующими параметрами:

SetLength(DynArray, 10, 20);

В завершение знакомства с массивами нам осталось рассмотреть обещанный ранее пример использования циклов для заполнения массива. Допустим, у нас имеется простой массив-вектор для 10 целых чисел:

Var MyArray: array of integer;

Таким образом, если нам надо заполнить его значениями, следующими по порядку (скажем, числа от 10 до 100 с шагом 10), то вместо того, чтобы последовательно присваивать каждому элементу массива свое значение, можно использовать следующий цикл:

For i:= 1 to 10 do MyArray[i] := i * 10;

Здесь переменная i, являющаяся счетчиком цикла, при каждой его итерации последовательно увеличивается на 1. В результате каждый элемент массива MyArray получает значение этой переменной, умноженной на 10, т.е. 10, 20, 30, 40 и т.д. - чего нам и требовалось. Чтобы убедиться в этом, а заодно продемонстрировать цикл для считывания данных из массива, обратимся к примеру, приведенному в листинге 5.1 (на CD этот пример находится в папке Demo\Part1\ArrayFor):

Листинг 5.1. Запись и считывание данных массивов в цикле

Program arrayfor; {$APPTYPE CONSOLE} var MyArray: array of integer; i:integer; begin for i:= 1 to 10 do MyArray[i] := i * 10; // заполнение массива for i:= 1 to 10 do writeln(MyArray[i]); // вывод массива readln; // ожидание ввода для предотвращения закрытия окна end.

Относительно массивов можно сделать еще одно замечание: один уже известный нам тип данных - строки (string) можно рассматривать как массив символов (char). При этом никаких предварительных преобразований не требуется: если у нас уже есть строка, то всегда можно обратиться к отдельному ее символу как к элементу массива:

Var s: string; c: char; ... s:= Москва; c:= s;

В данном случае переменная c получит в качестве своего значения букву "М", т.е. первый символ строки.

Множества

Иногда бывает удобным ограничить возможные значения переменной только частью значений из множества всех значений, допускаемых ее типом. Допустим, нам нужна переменная типа Char, которая может принимать значения только из строчных латинских символов. В таком случае нам пригодится такое средство, как подмножество, в данном случае - подмножество символов от a до z. Определить его можно так:

Type SmLetter = a..z;

Таким образом, мы получили новый тип данных - SmLetter, который является "урезанным" вариантом типа Char. При использовании такого типа данных, переменные типа SmLetter не смогут принимать значения, выходящие за пределы указанного диапазона:

Var a: SmLetter; ... a:= ; // здесь все правильно, т.к. малая b входит в подмножество a..z a:= B; // ошибка! Прописная B не входит в подмножество a..z

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

Развитием подмножеств являются множества, или наборы (sets). Они, подобно подмножествам, могут быть выделены в отдельные типы данных, однако допустимые диапазоны их значений определяются несколько иначе. Прежде всего, для определения множества используется ключевое слово set:

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

Type Letters = set of Сhar; var a: Letters; ... a:= ;

Таким образом, определение множества состоит из двух этапов: вначале определяется тип, на основании которого строится подмножество (Letters), затем объявляется переменная этого типа (a), и уже к переменной применяется диапазон. Преимущество здесь состоит в том, что, во-первых, по ходу программы можно менять допустимые диапазоны значений, а во-вторых, сами диапазоны определяются гораздо более гибко. В частности, они могут содержать в себе как ряды отдельных значений, так и подмножества, или их сочетания в любой последовательности. Например, если нам надо выделить только некоторые символы, скажем, прописные от A до K, а так же цифры 1, 3, 4, 5 и 9, то определение группы получится следующим:

Type Letters = set of Char; var a: Letters; ... a:= ;

Для проверки, является ли то или иное значение членом множества, используется операция in. Например, чтобы проверить, относится ли введенный пользователем символ (обозначим его как переменную "c") к множеству a, достаточно такого выражения:

If c in a then ...

Чтобы продемонстрировать работу множеств и операции in, обратимся к примеру, приведенному в листинге 5.2 (Demo\Part1\Ranges).

Листинг 5.2. Операция in и подмножества

Program rangeset; {$APPTYPE CONSOLE} type Letters = set of Char; var a: Letters; c: Char; begin a:= ; // определение группы readln(c); // считывание ввода пользователя if c in a then writeln(Input is Ok!) else writeln(Input is Wrong!); readln; // ожидание ввода для предотвращения закрытия окна end.

Еще одной разновидностью множества является перечисление. Использование перечислений призвано, прежде всего, улучшить читаемость (восприятие) кода программы. Допустим, в программе требуется неоднократно определять текущую раскладку клавиатуры, причем предусмотрено 3 состояния - русская, английская и другая. Разумеется, каждому состоянию можно назначить цифру, скажем, 1, 2 и 3 соответственно, однако по ходу написания программы всякий раз придется вспоминать, что означает та или иная цифра:

If KeyLang = 2 then ... // по прошествии месяца вспомните, что тут значит 2!

На помощь здесь приходят перечисляемые типы. Они определяются следующим образом:

= (, ...);

Например, в варианте для трех значений раскладки клавиатуры мы получим:

Type TKeyLang = (klRussian, klEnglish, klOther);

Согласитесь, что klEnglish куда понятнее, чем просто цифра "2". Более того, на основании заданного таким образом перечисления можно создать тип-множество. Для этого после того, как исходный тип с диапазоном определен, определяют имя типа на его основе:

Type TKeyLang = (klRussian, klEnglish, klOther); TKeyLangs = set of TKeyLang;

ВНИМАНИЕ
Обратите внимание на то, что имена типов начинаются с буквы "T". Хотя это и не является требованием языка, однако начинать названия сложных типов с этой буквы (от слова Type - тип) де-факто является стандартом.

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

Var KeyLang: TKeyLangs; ... if KeyLang = klEnglish then ;

ПРИМЕЧАНИЕ
Объявление типов-перечислений в 2 этапа является наиболее распространенной практикой. При этом исходный тип определяется именем в единственном числе (TKeyLang), а производный - во множественном, с "s" на конце (TKeyLangs).

Записи

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

Объявление записи начинается с ключевого слова record, за которым следует перечисление всех входящих в нее элементов, называемых полями записи, и завершается ключевым словом end:

Record: ; ... : ; end;

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

Type TAddress = record PostIndex: integer; City: string; Street: string; HouseNr: integer; FlatNr: integer; end;

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

Var MyAddr: TAddress; ... MyAddr.PostIndex:= 119071; MyAddr.City:= Москва; В том случае, если полем записи является другая запись, то точка используется дважды. Так, если у нас определена еще одна запись, для хранения информации о персоне, то одним из ее полей наверняка окажется адрес, а у нас уже есть подходящий тип данных для этого, так что можно использовать его в качестве поля: type TPerson = record Name: string; Phone: string; Address: TAddress; end;

Таким образом, все поля типа TAddress будут принадлежать также и к типу TPerson, но обращаться к ним надо не напрямую, а через поле записи TPerson соответствующего типа, т.е. через Address. Такие поля называются составными:

Var Anybody: TPerson; ... Anybody.Name:= Вася Иванов; Anybody.Address.PostIndex:= 119071; Anybody.Address.City:= Москва;

В то же время, можно поступить и по другому: создать переменную типа TAddress, заполнить ее значениями, а затем присвоить соответствующему полю переменной типа TPerson. В примере, приведенном в листинге 5.3, продемонстрированы оба способа работы с составными полями, а так же продемонстрировано, что со всеми полями можно делать то же самое, что и с отдельными переменными того же типа.

Листинг 5.3. Записи

Program recdemo; {$APPTYPE CONSOLE} type TAddress = record PostIndex: integer; City: string; Street: string; HouseNr: integer; FlatNr: integer; end; TPerson = record Name: string; Phone: string; Address: TAddress; end; var Anybody: TPerson; Address: TAddress; begin write(Name:); readln(Anybody.Name); write(Phone:); readln(Anybody.Phone); write(Postal Index:); readln(Address.PostIndex); write(City:); readln(Address.City); write(Street:); readln(Address.Street); write(House number:); readln(Address.HouseNr); write(Flat number:); readln(Address.FlatNr); Anybody.Address:=Address; writeln(Anybody.Name); writeln(Anybody.Phone); writeln(Anybody.Address.PostIndex); writeln(Anybody.Address.City); writeln(Anybody.Address.Street); writeln(Anybody.Address.HouseNr); writeln(Anybody.Address.FlatNr); readln; end.

Приведенная в листинге программа последовательно предлагает пользователю ввести свойства - сначала для записи о персоне, а затем - для адреса, после чего полю адреса персоны присваивается значение записи-адреса. После этого все поля последовательно выводятся на экран. Исходный код программы можно найти в папке Demo\Part1\Records (файл recdemo.dpr).

В завершение темы записей рассмотрим еще одну их особенность, характерную для Object Pascal, а именно - возможность сочетать в одном типе записи с разными полями. Называются такие записи вариантными и объявляются так же как и обычные, за исключением того, что содержат дополнительную часть, начинающуюся с ключевого слова case:

Record [ : ; ... : ;] case [ :] of: (); ... : (); end;

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

Type TEmployee = record Name: string; JobTitle: string; case Salaried: Boolean of true: (Salary: Currency); false: (Hourly: Currency); end;

Здесь, в зависимости от того, будет ли значением поля Salaried той или иной переменной типа TEmployee ложь или истина, у нее будет либо поле Salary, либо Hourly. Пример использования подобной вариантной записи вы можете посмотреть в файле varrec.dpr.

Специальные типы данных

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

Поскольку этот тип является, фактически, вещественным числом, то данные хранятся в нем следующим образом: целая часть числа определяет дату, за которую берется количество дней, прошедших с 31 декабря 1899 года, а дробная определяет время в миллисекундах, прошедших с начала текущего дня. Преимуществом же типа TDateTime является то, что для него предусмотрен целый набор готовых функций, позволяющих работать с датами и временем. Их список приведен в таблице 5.1.

Таблица 5.1. Функции для работы с датой и временем
Функция Описание
Now Возвращает текущие дату и время
Date Возвращает текущую дату (целую часть TDateTime)
Time Возвращает текущее время (дробную часть TDateTime)
DateTimeToStr Преобразует дату и время в строку на основе системных настроек
DateTimeToString Копирует дату и время в указанную строковую переменную
DateToStr Преобразует дату в строку
TimeToStr Преобразует время в строку
FormatDateTime Преобразует дату и время в указанный формат
StrToDateTime Преобразует строку, содержащую написанную надлежащим способом дату и время, в переменную типа TDateTime
StrToDate Преобразует строку в дату в формате TDateTime
StrToTime Преобразует строку во время в формате TDateTime
DayOfWeek Возвращает номер дня недели (от 1 до 7) для указанной даты. Учитывайте, что 1-й день недели – воскресенье
DecodeDate Раскладывает значение типа TDateTime на 3 целых, представляющих собой год, месяц и день месяца
DecodeTime Раскладывает значение типа TDateTime на 4 целых, представляющих собой часы, минуты, секунды и миллисекунды
EncodeDate Объединяет 3 целых, представляющих собой год, месяц и день, в одно значение типа TDateTime
EncodeTime Объединяет 4 целых, представляющих собой часы, минуты, секунды и миллисекунды? в одно значение типа TDateTime

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

Var today, yesterday: TDateTime; s: string; ... today:= Now(); yesterday:= today - 1; s:= TateToStr(yesterday);

Здесь переменной s будет назначено значение, соответствующее вчерашнему дню в формате, принятому в системе (например, "16.07.2005"). Более полный пример работы с датами вы можете посмотреть в Demo\Part1\Dates.

Кроме дат, рассмотрим еще один тип данных - файлы (files). Файлы представляет собой некую последовательность однотипных элементов, размещенных на внешнем носителе, не находящемся в оперативной памяти ПК. В типичном случае таким носителем является жесткий диск. Этот тип данных можно охарактеризовать как одномерный массив без указания размера. Чтобы производить те или иные операции над такими данными, используют специальную переменную файлового типа. Причем в зависимости от того, с какими данными предстоит работать, задают тот или иной тип файла. Например, для работы с текстовыми файлами используют специальный тип TextFile, а если файл содержит в себе ряд чисел, то определяют, какой тип чисел в нем используется:

Var f1: TextFile; // текстовый файл f2: File of integer; // файл с целыми числами f3: File of double; // файл с вещественными числами

Если же файл нетипизированный, (например, бинарный), то используют тип File без каких-либо дополнений:

Var f4: File; // двоичный файл или файл заранее неизвестного типа

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

ПРИМЕЧАНИЕ
Саму файловую переменную называют дескриптором файла, т.е. фактически она лишь указывает программе на место в памяти, через которое обеспечивается доступ к файлу средствами операционной системы.

Для работы с файлами так же предусмотрен целый ряд процедур и функций. Среди них можно отметить уже знакомые нам read/readln и write/writeln. Чтобы эти процедуры работали с файлами, в качестве первого параметра указывают имя файловой переменной (дескриптор файла):

Writeln(f, Текст для записи в файл);

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

AssignFile(f, c:\file.txt);

Что касается открытия файла, то тут дела обстоят несколько сложнее, поскольку следует учитывать тип файла и режим доступа. Так, применительно к текстовым файлам, используют процедуры Reset, Rewrite и Append, открывающие файл на чтение, перезапись и добавление (запись в конец файла), соответственно.

Наконец, следует отметить, что после того, как операции с файлом произведены, его необходимо закрыть. Для закрытия файла используется процедура CloseFile. Таким образом, вариант использование всех этих процедур для чтения и записи файла в общем случае, выглядит таким образом, как показано в листинге 5.4:

Листинг 5.4. Запись и чтение в файлах

Program readwrite; {$APPTYPE CONSOLE} uses SysUtils; var f: TextFile; s: string; begin AssignFile(f, c:\test.txt); // назначаем дескриптор файлу text.txt Rewrite(f); // открываем файл на запись writeln(f, s); // производим запись в файл CloseFile(f); // закрываем файл Reset(f); // открываем файл на чтение readln(f, s); // считываем данные из файла CloseFile(f); // закрываем файл end;

Еще один пример работы с файлами можно посмотреть в Demo\Part1\Files. Вместе с тем, на практике файловые типы данных не часто используются при современном программировании в среде Delphi, поскольку VCL предлагает ряд более удобных и изящных методов для хранения данных на диске, начиная от методов отдельных классов и заканчивая потоками и базами данных.

Совместимость и преобразование типов

При рассмотрении простых типов мы уже поднимали вопрос их совместимости и преобразования друг в друга. Теперь настала пора рассмотреть этот аспект более внимательно. В частности, если целое число без проблем приводится к вещественному, то как быть в том случае, если требуется обратное преобразование? Выход в данной ситуации состоит в использовании специальных функций преобразования типов. Так, для преобразования вещественного числа в целое используются функции Round и Trunc. Их отличие состоит в том, что первая округляет значение до целого, опираясь на стандартные математические правила, а вторая - просто отбрасывает дробную часть числа. Отметим, что если надо просто отбросить дробную часть числа, оставив тип данных без изменений, то следует использовать другую функцию - Int. Примеры их использования показаны ниже:

Var i: integer; r: real; ... r:= 5.75; i:= Round(r); // i получит значение 6 i:= Trunc(r); // i получит значение 5 r:= Int(r); // r получит значение 5.0

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

Таблица 5.2. Функции для преобразования чисел в строки и наоборот
Функция Описание
IntToStr Преобразует целое число в строку
StrToInt Преобразует строку в целое число, в случае невозможности преобразования вызывает ошибку
StrToIntDef Преобразует строку в целое число, в случае невозможности преобразования возвращает число, указанное в качестве второго аргумента
FloatToStr Преобразует вещественное число в строку
FloatToStrF Преобразует вещественное число в строку на основе указанного формата
StrToFloat Преобразует строку в вещественное число, в случае невозможности преобразования вызывает ошибку
StrToFloatDef Преобразует строку в вещественное число, в случае невозможности преобразования возвращает число, указанное в качестве второго аргумента
CurrToStr Преобразует число типа Currency в строку
CurrToStrF Преобразует число типа Currency в строку на основе указанного формата
StrToCurr Преобразует строку в число типа Currency, в случае невозможности преобразования вызывает ошибку
StrToCurrDef Преобразует строку в число типа Currency, в случае невозможности преобразования возвращает число, указанное в качестве второго аргумента

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

Str:= FloatToStrF(x, ffGeneral, 10, 2);

Здесь ffGeneral является указанием на формат вывода, 10 определяет максимально возможное число знаков в числе вообще, а 2 - предельно допустимое число знаков после запятой. Помимо ffGeneral, определяющего наиболее обобщенный формат представления чисел, имеются и другие:

  • ffExponent - формат с экспонентой (например, 1.45E10);
  • ffFixed - фиксированный формат (например, 145000.01);
  • ffNumber - "прописной" формат (например, 1,450,000.0);
  • ffCurrency - валютный формат (например, 145 000,00р).

Таким образом, привести то или иное число к строке нужного формата, оказывается достаточно просто - важно лишь определиться, что нужно получить. А еще одна функция - Chr - позволяет преобразовывать маленькие числа (до 255) в символы, т.е. фактически, из типа Byte делает Char.

Что касается обратных преобразований (строк в числа), то тут следует соблюдать определенную осторожность, поскольку далеко не всякая строка может стать числом. В первую очередь это касается преобразований вещественных числе, поскольку нередко вместо отделяющей мантиссу точки может оказаться запятая. В случаях, когда преобразование строки в число невозможно, возникает ошибка выполнения программы. Ее можно обрабатывать самостоятельно (об обработке ошибок будет рассказано во второй части книги), или же поручить это дело функции - в таком случае следует использовать функции с суффиксом Def (StrToIntDef, StrToFloatDef и StrToCurrDef). В качестве второго аргумента они принимают значение, которое следует использовать в том случае, если преобразование невозможно:

X:= StrToIntDef(str, -1);

В данном случае, если в строке str не удастся распознать число, переменной x будет присвоено значение -1.

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

Var v: variant; ... v:= 5; v:= Строковое значение; v:= 10.54;

Этот пример иллюстрирует, как одной т той же переменной последовательно присваиваются данные 3 разных типов - целочисленного, строкового и вещественного. При этом никакой ошибки не возникает. Однако вариантные данные обрабатываются гораздо медленнее, чем типизированные - практически так же медленно, как программы на языке BASIC. (кстати, в классическом BASIC как раз только вариантные данные и были). Кроме того, использование нетипизированных данных вообще, а в строго типизированном языке - особенно, чревато непредсказуемым поведением программы и прочими ошибками. Поэтому оставим этот тип для внутреннего использования Delphi - в VCL он применяется для работы с OLE и базами данных.

Указатели

Указатели (pointers) - это такой тип переменных, которые хранят адрес в памяти компьютера, по которому расположена другая переменная. Фактически, указатель не содержит значение, а ссылается на него.

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

Var P: ^integer;

Здесь мы определили указатель P, являющийся указателем на переменную целочисленного типа.

После того, как указатель создан, можно связать его с переменной подходящего типа, используя операцию @:

Var P: ^integer; x: integer; ... P:= @x; Теперь к переменной x можно обращаться как непосредственно, так и через ее указатель. В случае обращения через указатель так же используют символ "^": x:= 10; P^ := 10;

В обоих случаях переменная x получит значение 10.

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

Var P: ^integer; ... New(P); // выделение памяти, необходимой для хранения данных типа Integer P^ := 10; // занесение данных в выделенный блок памяти Dispose(P); // освобождение памяти

При работе с указателями таким методом следует самостоятельно заботиться о выделении и очистке памяти под данные.

В целом же указатели, как правило, используются для взаимодействия с системными функциями операционной системы (в частности, с Windows API), для взаимодействия со сторонними программами и динамически подключаемыми библиотеками.

Объекты

Самые сложные и интересные типы данных - это объекты. В современных версиях Delphi объекты бывают 3 основных типов: собственно объекты, а так же классы и интерфейсы. Тип объекта (object) достался Delphi от предшественника - языка Pascal with Objects, и в настоящее время практически не используется. Основным типом объектных данных в современных программах является класс (class). Что касается интерфейсов (interface), то они являются разновидностью классов, и предназначены для взаимодействия с системными объектными функциями Windows.

Тема объектов достаточно обширна, поскольку является основой для парадигмы объектно-ориентированного программирования. ООП в Object Pascal рассматривается во второй части настоящего издания.

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

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

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

Что же касается объявлений var, то они задают компилятору некоторые действия, связанные с ранее объявленными типами. Тип переменной ограничивает как ее значения, так и операции, которые можно выполнять с этими значениями.

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

type
typel = type definitioni; //Новые типы данных определяются в разделе "type". Каждому новому
// типу присваивается имя, затем он определяется через уже
//существующие типы.
type2 = type__definition2; // В одном разделе "type" можно объявить несколько типов.
//Самое простое определение типа состоит из имени типа,
type3 = typel; // определенного ранее.
// Новые переменные объявляются в
var // разделе "var". Каждой новой
var1: type definitions; // переменной сначала присваивается имя, а затем - тип (на основе
// ранее определенных типов).
var2, var3: type definition4; // В одном разделе "var" можно объявить несколько переменных.
// Нескольким переменным можно присваивать один и тот же тип.
var4: typel; // Программу легче читать, если переменным присвоены
//существующие типы.

Синтаксис Object Pascal позволяет одновременно конструировать исключительно сложные типы и определение переменных. Однако определение типов в разделах type тех или иных блоков дает возможность использовать эти типы в разных частях программы. Новые типы определяются из типов следующих категории.

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

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

Функция SizeOf очень важна для написания эффективных программ. Многие из определенных в Object Pascal типов имеют очень сложную структуру и могут занимать в памяти довольно много места. При этом элементы таких типов созданы скорее для представления значений в некотором логическом порядке, а не для того, чтобы занимать место в памяти. Функция SizeOf избавляет программиста от необходимости вычислять объем данных в подобных случаях.

Простые типы данных

Порядковые типы
Целые типы
Символьные типы
Булевы типы
Перечислимые типы
Поддиапазонные типы
Действительные типы

Любой реально существующий тип данных, каким бы сложным он ни казался на первый взгляд, представляет собой простые составляющие, которыми процессор может манипулировать. В Object Pascal эти простые типы данных разбиты на две группы: порядковые, представляющие данные разных объемов, которыми процессор может легко манипулировать, и действительные, представляющие приближенно математические действительные числа. Разделение типов на порядковые и действительные несколько условно. Точно так же простые данные можно было бы разделить на числа и не числа. Однако в языке Object Pascal порядковые и действительные данные трактуются по-разному, и такое разделение даже полезно.

Порядковые типы

Из простых типов данных порядковые - самые простые. В этих типах информация представляется в виде отдельных элементов. Связь между отдельными элементами и их представлением в памяти определяет естественные отношения порядка между этими элементами. Отсюда и название порядковые.

В Object Pascal определены три группы порядковых типов и два типа, определяемых пользователем. Группы - это целые, символьные и булевы типы. Порядковые типы, задаваемые пользователем, - это перечисления и поддиапазоны.

Все значения любого порядкового типа образуют упорядоченную последовательность, и значение переменной порядкового типа определяется его местом в этой последовательности. За исключением переменных целых типов, значения которых могут быть как положительными, так и отрицательными, первый элемент любого порядкового типа имеет номер 0, второй элемент - номер 1 и т.д. Порядковый номер целого значения равен самому значению. Отношение порядка определяет общие для данных всех порядковых типов операции. Некоторые стандартные функции такого вида встроены в Object Pascal. Они представлены в табл. 1.1.

Для всех порядковых типов в Object Pascal существует операция задания типа для преобразования целых значений в значения соответствующих порядковых типов. Если Т - имя порядкового типа, а Х - целое выражение, то Т (X) воз-вращает значение Т с порядковым номером X.

Таблица 1.1. Операции над порядковыми типами

Операция

Описание

Минимальное значение порядкового типа Т

Максимальное значение порядкового типа Т

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

Предыдущее по порядку значение. Для целых выражений эквивалентно Х-1

Следующее по порядку значение. Для целых выражений эквивалентно Х+1

Уменьшает значение переменной на 1. Эквивалентно V:= Pred(V)

Увеличивает значение переменной на 1. Эквивалентно V:= Succ(V)

Целые типы

В переменных целых типов информация представляется в виде целых чисел, т.е. чисел не имеющих дробной части. Определенные в Object Pascal целые типы подразделяются на физические (фундаментальные) и логические (общие). При программировании удобнее использовать логические целые типы, которые задают объем переменных в зависимости от типа микропроцессора и операционной среды таким образом, чтобы достигалась максимальная эффективность. Физические целые типы следует применять лишь в тех случаях, когда в первую очередь важны именно диапазон значений и физический объем переменной. В Object Pascal определены следующие целые типы.

Integer
Shortint
Smallint
Longint
Byte
Word
Cardinal

Обратите внимание, что один из этих целых типов назван именно целым (integer). Это может иногда приводить к путанице, но мы легко сможем ее избежать, применяя термин целый к. группе типов, a integer - к конкретному типу, определяемому в программе этим ключевым словом. Переменные физических целых типов имеют разные диапазоны значений в зависимости от того, сколько байтов памяти они занимают (что равно значению, возвращаемому функцией SizeOf для данного типа). Диапазоны значений для всех физических типов перечислены в табл. 1.2.

Таблица 1.2. Физические целые типы

Диапазон значении

Физический формат

8 бит, со знаком

16 бит, со знаком

2 147 483 648-2 147 483 647

32 бит, со знаком

8 бит, без знака

16 бит, без знака

Диапазоны значений и форматы физических целых типов не зависят от микропроцессора и операционной системы, в которых выполняется программа. Они не меняются (или, по крайней мере, не должны меняться) с изменением реализации или версии Object Pascal.

Диапазоны значений логических целых типов (Integer и Cardinal) определяются совершенно иным образом. Как видно из табл. 1.3, они никак не связаны с диапазонами соответствующих физических типов. Обратите внимание, что в Delphi по умолчанию задано 32-разрядное представление.

Таблица 1.3. Логические целые типы

Диапазон значений

Физический формат

16 бит, со знаком (SmalIInt)

2 147 483 648-2 147 483 647

32 бит, со знаком (Longint)

16 бит, без знака (Word)

32 бит, без знака (Longint)

Над целыми данными выполняются все операции, определенные для порядковых типов, но с ними все же удобнее работать как с числами, а не с "нечисленными порядковыми типами". Как и "живые" числа, данные целых типов можно складывать (+), вычитать (-) и умножать (*). Однако некоторые операции и функции, применяемые к данным целых типов, имеют несколько иной смысл.

Символьные типы

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

В реализациях языка Pascal для первых микропроцессоров была применена 7-битовая схема, названная ASCII (American Standard Code for Information Interchange - Американский стандартный код для обмена информацией). Эта схема и поныне широко распространена, но информация хранится, как правило, в 8-битовых участках памяти. Дополнительный бит удваивает число возможных представлений символов, но реализации расширенного набора символов ASCII часто бывают далеки от стандарта. В данной версии Delphi определен набор 8-битовых символов, известный как расширенный (extended) ANSI (American National Standards Institute - Американский национальный институт стандартов). Как бы то ни было, символьную схему приходится воспринимать так, как ее воспринимает операционная система. Для оконных операционных систем фирмы Microsoft это схема ANSI, включающая ограниченное число предназначенных для вывода международных знаков. В стремлении же применить более обширный набор международных знаков весь компьютерный мир переходит к 16-битовой схеме, именуемой UNICODE, в которой первые 256 знаков совпадают с символами, определенными в схеме ANSI.

Для совместимости со всеми этими представлениями в Object Pascal определены два физических символьных типа и один логический.

Физические типы перечислены ниже.

Символьные типы объемом в двойное слово (32 бит) отсутствуют.

Логический символьный тип именуется char. В классическом языке Pascal char- единственный символьный тип. В Delphi char всегда соответствует физическому типу данных AnsiChar. У американских программистов ассоциация символа с однобайтовой ячейкой памяти укоренилась за долгие годы настолько, что им зачастую просто не приходит в голову, что можно использовать другие схемы кодирования. Однако дискуссии по интернационализации программ в Internet и World Wide Web могут существенно изменить их отношение к проблеме объема символьных данных. Применяя логический тип char, следует делать реализации для других микропроцессоров и операционных систем, в которых char может определяться как WideChar. При написании программ, которые могут обрабатывать строки любого размера, для указания этого размера рекомендуется применять функцию SizeOf, не задавая ее жестко постоянной. Функция Ord (С), где С - любая переменная символьного типа, возвращает целое значение, которым символ С представлен в памяти.

Булевы типы

На ранней стадии обучения программисты осваивают понятие бита, два состояния которого можно использовать для записи информации о чем-либо, представляющем собой одно из двух. Бит может обозначать 0 или 1, ДА или НЕТ, ВКЛЮЧЕНО или ВЫКЛЮЧЕНО, ВЕРХ или НИЗ, СТОЯТЬ или ИДТИ. В Object Pascal информация о чем-либо, что можно представить как ИСТИНА (True) или ЛОЖЬ (False), хранится в переменных булевых типов. Всего таких типов че-тыре, и они представлены в табл. 1.4.

Таблица 1.4. Размеры переменных булевых типов

2 байт (объем Word)

4 байт (объем Longint)

По аналогии с целыми и символьными типами, подразделяющимися на физические и логические, естественно предположить, что ByteBool, WordBool и LongBool - физические типы, Boolean - логический. Но в данном случае это не совсем так. Все четыре типа различны. Для Object Pascal предпочтителен тип Boolean, остальные определены для совместимости с другими языками программирования и операционными системами.

Переменным типа Boolean можно присваивать только значения True (истина) и False (ложь). Переменные ByteBool, WordBool и LongBool могут принимать и другие порядковые значения, интерпретируемые обычно как False в случае нуля и True - при любом ненулевом значении.

Перечислимые типы

Type enum type = (first value, value2, value3, last value);

Обычно данные перечислимых типов содержат дискретные значения, представляемые не числами, а именами. Тип Boolean- простейший перечислимый тип в Object Pascal. Булевы переменные могут принимать два значения, выражаемые именами True и False, а сам тип определен в Object Pascal так, как будто он объявлен следующим образом:

Type Boolean = (False, True);

С помощью типа Boolean в Object Pascal выполняются сравнения, большинство же перечислимых типов - это просто списки уникальных имен или идентификаторов, зарезервированных с конкретной целью. Например, можно создать тип MyColor (мой цвет) со значениями myRed, myGreen и myBlue (мой красный, мой зеленый, мой синий). Это делается совсем просто:

Type MyColor = (myRed, myGreen, myBlue);

В этой строке объявлены четыре новых идентификатора: MyColor, myRed, myGreen и myBlue. идентификатором MyColor обозначен порядковый тип, следовательно, в синтаксисе Object Pascal можно применять этот идентификатор везде, где разрешены перечислимые типы. Остальные три идентификатора- это значения типа MyColor. Подобно символьным и булевым типам перечислимые не являются числами, и использовать их наподобие чисел не имеет смысла. Однако перечислимые типы относятся к порядковым, так что значения любого такого типа упорядочены. Идентификаторам в списке присваиваются в качестве порядковых номеров последовательные числа. Первому имени присваивается порядковый номер 0, второму - 1 и т.д.

Поддиапазонные типы

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

Type subrange type = low value...high value;

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

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

Действительные типы

В переменных действительных типов содержатся числа, состоящие из целой и дробной частей. В Object Pascal определено шесть действительных типов. Все типы могут представлять число 0, однако они различаются пороговым (минимальным положительным) и максимальным значениями, которые могут представлять, а также точностью (количеством значащих цифр) и объемом. Действительные типы описываются в табл. 1.5.

Таблица 1.5. Действительные типы.

Целые типы представляют целые числа, т.е. числа, дробная часть которых равна нулю. Разница между двумя неодинаковыми целыми числами не может быть меньше единицы. Именно благодаря этому целые числа применяются для обозначения дискретных величин, независимо от того, имеют ли реальные объекты какое-либо отношение к числам. Действительные типы предназначены для представления чисел, которые могут иметь дробную часть, поэтому они полезны для представления величин, которые могут быть довольно близкими, почти непрерывными.

Заметьте, именно почти. Несмотря на название действительные, переменные этих типов отличаются от математических действительных чисел. В Object Pascal действительный тип - это подмножество математических действительных чисел, которые можно представить в формате с плавающей запятой и фиксированным числом цифр. Для невнимательных программистов ситуация усугубляется тем, что в стандартных форматах IEEE (Institute of Electrical and Electronic Engi-neers - Институт инженеров- электриков и электронщиков), применяемых в программах Delphi и вообще в большинстве программ для Windows, возможно точное представление только чисел с фиксированным числом бит в дробной части. Удивительно, но такое простое число, как 0,1, записывается в расширенном формате IEEE с некоторой погрешностью, пусть очень небольшой. Из-за этого представление с плавающей запятой оказывается несколько неудобным для программ, в которых сохраняется и выводится фиксированное число десятичных разрядов численных значений. Это относится и к программам, работающим с ""живыми" деньгами.

Для частичного решения этой проблемы в Object Pascal определены два формата с фиксированной запятой. Тип Comp (computational - вычислительный) содержит только целые числа в диапазоне от -2 63 +1 до 2 63 -1, что примерно соответствует диапазону от -9,2х10 18 до 9,2х10 18 . При программировании операций с американской валютой разработчикам обычно приходится искать естественный способ записи денежных сумм, в котором целая часть числа определяет количество долларов, дробная - центов. Если такие значения записывать в переменные типа Comp, придется представлять их в виде целого числа центов. В этом случае следует умножать значение на 100 для обращения центов в доллары, а затем делить на 100, чтобы снова получить центы.

Этих забот можно избежать, если воспользоваться типом Currency. В этом случае задачу выбора масштаба возьмет на себя компилятор. Физически значения Currency записываются в память того же объема, что и Comp, как целые числа, однако компилятор не забывает вовремя разделить значение на 10 000 (не на 100!) для его приведения в соответствие с денежным знаком и умножить на 10 000 перед записью в память. Это обеспечивает абсолютную точность в четыре десятичных знака после запятой.

Текст программы на языке Delphi формируется с помощью букв, цифр и специальных символов. Буквы - это прописные и строчные символы латинского алфавита и символ подчеркивания: a b c d e f g h i j k l m n o p q r s t u v w x y z A B C D E F G H I J K L M N O P Q R S T U V W X Y Z _ Цифры представлены стандартной арабской формой записи: 0 1 2 3 4 5 6 7 8 9 Специальные символы + - * / = , . : ; " () { } @ # $ & ^ применяются в основном в качестве знаков арифметических операций, разделителей, ограничителей и т. д. Из специальных символов формируются составные символы: =. . (. .) (* *) // : = Они служат, в частности, для обозначения операций типа "не равно", "больше или равно", указания диапазонов значений, комментирования программы, т. д. Алфавит

Одно и то же число можно записать самыми разными способами, например: 15 { целое } 15. 0 { вещественное с фиксированной точкой } 1. 5 E 01 { вещественное с плавающей точкой } $F { шестнадцатиричное } В языке Delphi имеется возможность применять все способы записи, но чаще всего используют целые и вещественные числа. Целые числа состоят только из цифр и знака + или –. Если знак опущен и число не равно 0, то оно рассматривается как положительное, например: 0 { 0 интерпретируется как целое число } 17 { положительное целое число } -39 { отрицательное целое число } Числовые типы данных

Вещественные числа содержат целую и дробную части, разделенные точкой: 0. 0 { 0 интерпретируется как вещественное число } 133. 5 { положительное вещественное число } -0. 7 { отрицательное вещественное число } Вещественные числа могут быть представлены в двух формах: с фиксированной и плавающей точкой. Форма с фиксированной точкой совпадает с обычной записью чисел: 27800 { точка в конце числа опущена } 3. 14 Форма с плавающей точкой (экспоненциальный вид) используется при работе с очень большими или очень малыми числами. В этой форме число, стоящее перед E, умножается на 10 в степени, указанной после E: 7. 13 E+14 { 7. 13 x 1014 } 1. 7 E-5 { 1. 7 x 10 -5 } 3. 14 E 00 { 3. 14 x 100 = 3. 14} Число, стоящее перед буквой E, называется мантиссой, а число после буквы E - порядком. Числовые типы данных

С помощью комментариев вы можете пояснить логику работы своей программы. Комментарий пропускается компилятором и может находиться в любом месте программы. Комментарием является: { Любой текст в фигурных скобках } (* Любой текст в скобках со звездочками *) // Любой текст от двойной наклонной черты до конца строки Если за символами { или (* сразу идет знак доллара $, то текст в скобках считается не комментарием, а директивой компилятора. Примеры таких директив: {$OPTIMIZATION ON} {$WARNINGS ON} {$RANGECHECKS OFF} Комментарии

Программа в процессе выполнения всегда обрабатывает какиелибо данные. Данные могут представлять собой целые и дробные числа, символы, строки, массивы, множества и др. Так компьютер всего лишь машина, для которой данные - это последовательность нулей и единиц, он должен абсолютно точно "знать", как их интерпретировать. По этой причине все данные в языке Delphi подразделены на типы. Тип данных показывает, какие значения принимают данные и какие операции можно с ними выполнять. Каждому типу данных соответствует определенный объем памяти, который требуется для размещения данных. Например, в языке Delphi существует тип данных Byte. Данные этого типа принимают значения в целочисленном диапазоне от 0 до 255, могут участвовать в операциях сложения, вычитания, умножения, деления, и занимают 1 байт памяти. Типы данных

Все типы данных в языке Delphi можно расклассифицировать следующим образом: простые типы данных. Они в свою очередь подразделяются на порядковые и вещественные типы данных. К порядковым типам относятся целочисленные, символьные, булевские, перечисляемые и др. типы; временной тип данных. Служит для представления значений даты и времени; строковые типы данных. Служат для представления последовательностей из символов, например текста; составные типы данных. Формируются на основе всех остальных типов. К ним относятся массивы, множества, записи, файлы, классы и ссылки на классы; процедурные типы данных. Позволяют манипулировать процедурами и функциями как данными программы; указательные типы данных. Данные этих типов хранят адреса других данных (списки, деревья и т. д.); тип данных с непостоянным типом значений. Служит для представления значений, тип которых заранее неизвестен; с его помощью легко организуется работа со списком разнотипных значений; Классификация типов данных

Рассмотрим форму описания переменных, констант и типов. Описание типов: type =; Описание констант: Const: =; Описание переменных: Var: ; Форма описания данных

Пример записи констант: const Delphi. Language = "Object Pascal"; Kylix. Language = Delphi. Language; Yard = 914. 4; Foot = 304. 8; Seconds. In. Minute = 60; Seconds. In. Hour = Seconds. In. Minute * 60; // Задаем константу Seconds. In. Day = Seconds. In. Hour * 24; // как выражение При объявлении константы можно указать ее тип: Const Percent: Double = 0. 15; File. Name: string = "HELP. TXT"; Такие константы называются типизированными; их основное назначение - объявление константных значений составных типов данных. Описание констант

Кроме стандартных типов данных язык Delphi поддерживает типы, определенные программистом. Новый тип данных определяется с помощью зарезервированного слова type, за которым следует идентификатор типа, знак равенства и описание. Например, можно определить новый тип: type TUnicode = Wide. Char; TFloat = Double; TDirection = (North, South, East, West); Нетрудно заметить, что идентификаторы новых типов в примере начинаются заглавной буквой T (первая буква слова type). Такое соглашение о типах программиста принято разработчиками среды Delphi, но оно не является строгим. Тем не менее, мы рекомендуем его придерживаться, так как оно способствует более легкому восприятию исходного текста программы. Описание типов

Целые тип диапазон Shortint Smallint Integer Longint Cardinal Int 64 Byte Word Longword -128. . 127 знаковый 8 -bit -32768. . 32767 знаковый 16 -bit -2147483648. . 2147483647 знак. 32 -bit 0. . 4294967295 без знака 64 -bit -263. . 263 -1 знаковый 64 -bit 0. . 255 без знака 8 -bit 0. . 65535 без знака 16 -bit 0. . 4294967295 без знака 32 -bit формат Простые типы данных

тип диапазон знач. Real 48 Single Double Extended 5. 0 x 10 -324. . 1. 7 x 10308 15 -16 2. 9 x 10 -39. . 1. 7 x 1038 11 -12 1. 5 x 10 -45. . 3. 4 x 1038 7 -8 5. 0 x 10 -324. . 1. 7 x 10308 15 -16 3. 6 x 10 -4951. . 1. 1 x 104932 19 -20 цифр Comp – 9223372036854775808. . 9223372036854775807 19– 20 Currency – 922337203685477. 5808. . 922337203685477. 5807 19– 20 Вещественные типы байт 8 6 4 8 10 8 8

Символьные типы применяются для описания данных, значением которых является буква, цифра, знак препинания и другие символы. Существуют два фундаментальных символьных типа данных: Ansi. Char и Wide. Char. Они соответствуют двум различным системам кодировки символов. Данные типа Ansi. Char занимают один байт памяти и кодируют один из 256 возможных символов расширенной кодовой таблицы ANSI, в то время как данные типа Wide. Char занимают два байта памяти и кодируют один из 65536 символов кодовой таблицы Unicode. Кодовая таблица Unicode - это стандарт двухбайтовой кодировки символов. Первые 256 символов таблицы Unicode соответствуют таблице ANSI, поэтому тип данных Ansi. Char можно рассматривать как подмножество Wide. Char Символьный тип

Фундаментальные типы данных: Тип данных Объем памяти (байт) Ansi. Char 1 Wide. Char 2 Обобщенный тип данных: Тип данных Объем памяти (байт) Char 1 (но может стать эквивалентом wide) Логический тип данных Var good_file: boolean; Булевские типы данных Byte. Bool, Word. Bool и Long. Bool введены в язык Delphi специально для совместимости с другими языками, в частности с языками C и C++. Все булевские типы данных совместимы друг с другом. Символьный и логический тип данных

Пример. Описание константы и переменной символьного типа. const ch_p=’a’; //символьные константы ch_l: char=’f’; ch_k: wide. Char=’ 5’; var ch_l: char; //символьная переменная В программе значения переменных и констант символьных типов заключаются в апострофы (не путать с кавычками!), например: Symbol: = "A"; // Symbol присваивается буква A Пример символьных типов данных

Строки – динамический массив символов. String – длина не более 256 символов. Wide. String - длина более 256 символов. Информация считается строкой, если она закрыта в одинарные кавычки: ‘Mary It Bread’ – строка « Mary It Bread’ – не строка Пример. Определить константу и переменную строкового типа. Const С_wether=’Холодно…’; Var s 1: C_wether; s 2: string; Строковый тип данных

Перечисляемый тип. Перечисляемый тип данных представляет собой список значений, которые может принимать переменная этого типа. Каждому значению поставлен в соответствие идентификатор, используемый в программе для указания этого значения. Пример. type TColors = (red, white, blue); TMonth=(jnu, feb, mar, april, may, jun, jul, Agu, sep, oct, nov, dec); TDirection = (North, South, East, West); var Month: TMonth; Direction: TDirection; begin Direction: = North; end. Перечислимый тип данных

На самом деле за идентификаторами значений перечисляемого типа стоят целочисленные константы. По умолчанию, первая константа равна 0, вторая - 1 и т. д. Существует возможность явно назначить значения идентификатор type TSize. Unit = (Byte = 1, Kilobyte = 1024 * Byte, Megabyte = Kilobyte * 1024, Gigabyte = Megabyte * 1024); Максимальная мощность перечисляемого типа составляет 65536 значений, поэтому фактически перечисляемый тип задает некоторое подмножество целого типа word и может рассматриваться как компактное объявление сразу группы целочисленных констант со значениями 0, 1 и т. д.

Интервальные типы данных Интервальный тип данных задается двумя константами, ограничивающими диапазон значений для переменных данного типа. Обе константы должны принадлежать одному из стандартных порядковых типов (но не вещественному и не строковому). Пример: type TDigit = 0. . 9; digit = "0". . "9"; dig 2 = 48. . 57; var Digit: TDigit; month: 1. . 12; begin Digit: = 5; Digit: = 10; // Ошибка! Выход за границы диапазона End; Интервальный или тип-диапазон.

Различие между таким способом создания типа и обычным (без слова type) проявится при изучении массивов, записей и классов. Забежим вперед и приведем пример: type TType 1 = array of Integer; TType 2 = type TType 1; var A: TType 1; B: TType 2; begin B: = A; // Ошибка! end. В примере переменные A и B оказываются несовместимы друг с другом из-за слова type в описании типа TType 2. Если же переменные A и B принадлежат простым типам данных, то оператор присваивания будет работать. Специальные типы данных

Массив - это составной тип данных, состоящий из фиксированного числа элементов одного и того же типа. Для описания массива предназначено словосочетание array of. После слова array в квадратных скобках записываются границы массива, а после слова of - тип элементов массива: Type TStates = array of string; TCoordinates = array of Integer; const Coordinates: TCoordinates = (10, 20, 5); { 3 integers } var States: TStates; { 50 strings } Symbols: array of Char; { 81 characters – без определения типа} Чтобы получить доступ к отдельному элементу массива, нужно в квадратных скобках указать его индекс, например Symbols: =‘ё’; Обратите внимание, что инициализация элементов массива происходит в круглых скобках через запятую. Массивы

Объявленные выше массивы являются одномерными, так как имеют только один индекс. Одномерные массивы обычно используются для представления линейной последовательности элементов. Если при описании массива задано два индекса, массив называется двумерным, если n индексов - n-мерным. Двумерные массивы используются для представления таблицы, а n-мерные - для представления пространств. Вот пример объявления таблицы, состоящей из 5 колонок и 20 строк: var Table: array of array of Double; То же самое можно записать в более компактном виде: var Table: array of Double; Чтобы получить доступ к отдельному элементу многомерного массива, нужно указать значение каждого индекса, например Table или в более компактной записи Многомерные массивы Table

Пример. Описание двухмерного динамического массива элементов типа byte в переменной сon. var сon: array of byte; Пример. Многомерные массивы. var Mbon: array of byte; //четырехмерный Type Tmy_mas= array of byte; //тип – двухмерный массив var Mbon 1: array of Tmy_mas; //четырехмерный (двухмерный массив двухмерных массивов) C: array of Real; //трехмерный динамический массив Mbon – элемент массива Мbon Mbon 1 – элемент массива Мbon 1 С - // первый элемент динамического массива Примеры динамических массивов

Множество - это составной тип данных для представления набора некоторых элементов как единого целого. Область значений множества - набор всевозможных подмножеств, составленных из его элементов. Все элементы множества должны принадлежать однобайтовому порядковому типу – базовому типу. Для описания множественного типа используется словосочетание set of, после которого записывается базовый тип множества: type TLetters = set of "A". . "Z"; var Letters: TLetters; Symbols: set of Char; В выражениях значения элементов множества указываются в квадратных скобках: , , ["A", "B", "C"]. Если множество не имеет элементов, оно называется пустым: . Пример: const Vowels: TLetters = ["A", "E", "I", "O", "U"]; Begin Letters: = ["A", "B", "C"]; Symbols: = ; { пустое множество } End. Количество элементов множества называется мощностью. Мощность множества в языке Delphi не может превышать 256. Множества

Src="https://сайт/presentation/20070619_133096976/image-25.jpg" alt="При работе с множествами допускается использование операций отношения (=, , >=, При работе с множествами допускается использование операций отношения (=, >=,). Два множества считаются равными, если они состоят из одних и тех же элементов. Порядок следования элементов в сравниваемых множествах значения не имеет. Два множества A и B считаются не равными, если они отличаются по мощности или по значению хотя бы одного элемента. Выражение Результат True = True = True = True Операции принадлежности (>=, = B равно True, если все элементы множества B содержатся в множестве A. Выражение A

Операция in. Используется для проверки принадлежности элемента указанному множеству. Обычно применяется в условных операторах. 5 in = True 5 in = False Операция in позволяет эффективно и наглядно выполнять сложные проверки условий, заменяя иногда десятки других операций. Например, оператор if (X = 1) or (X = 2) or (X = 3) or (X = 5) or (X = 7) then можно заменить более коротким: if X in then Операцию in иногда пытаются записать с отрицанием: X not in S. Такая запись является ошибочной, так как две операции следуют подряд. Правильная запись имеет вид: not (X in S). Операция вхождения in

Объединение множеств (+). Объединением двух множеств является третье множество, содержащее элементы обоих множеств. + = + = Пересечение множеств (*). Пересечение двух множеств - это третье множество, которое содержит элементы, входящие одновременно в оба множества. * = * = Разность множеств (–). Разностью двух множеств является третье множество, которое содержит элементы первого множества, не входящие во второе множество. – = – = В язык Delphi введены две стандартные процедуры Include и Exclude, которые предназначены для работы с множествами. Процедура Include(S, I) включает в множество S элемент I. Процедура Exclude(S, I) исключает из множества S элемент I. Они дублирует операцию –/+ с той лишь разницей, что работают с одним элементом и делают это более эффективно. Объединение, пересечение, разность