Простые типы данных
Логические типы данных
Символьные типы данных
Структурные типы данных
Строки
Множества
Массивы
Записи
Указатели, процедурные и вариантные типы данных
Указатели
Процедурные типы данных
Вариантные типы данных
Эта глава представляет обзор типов данных, которые имеются в языке Object Pascal.
Мы рассмотрим как простые типы данных, так и структурные, вариантные и процедурные
типы данных. Кроме того, кратко остановимся на указателях.
Object Pascal представляет собой строго типизированный язык, который требует
особого внимания при объявлении и использовании переменных, процедур и функций.
Тип данных определяет то множество значений, которые может принимать данная
переменная или другой элемент программы. В зависимости от типа данных, с ними
можно выполнять определенные действия. Например, над вещественными переменными
можно производить любые арифметические операции, а со строковыми переменными
такие операции недопустимы.
Мы разделим все типы данных языка Object Pascal на пять групп:
простые;
структурные;
указатели;
процедурные;
вариантные.
Простые типы данных
Простые типы данных - это такие типы, которые не содержат в себе данные других
типов. К таким типам относятся:
целочисленные;
вещественные;
логические;
символьные.
Все эти типы, кроме вещественного, являются так называемыми порядковыми типами
данных.
Порядковым типом данных называется такой тип данных, значения образуют упорядоченную
последовательность с разницей в единицу.
Над порядковыми типами данных допустимо производить следующие операции:
Low (t) - минимальное значение данных типа t; High(t) - максимальное значение
данных типа t;
ord (x) - порядковый номер значения х;
fixed (х) - значение, предшествующее значению х; Succ (x) - значение, следующее
после значения х.
Кроме того, над перечислимыми типами данных допустимы следующие процедуры:
Dec(x) - уменьшение значения переменной х на единицу; Inc(x) - увеличение значения
переменной х на единицу. Рассмотрим по порядку простые типы данных.
Целочисленные типы данных
В языке Object Pascal определено несколько целочисленных типов данных. Самый
используемый из них - тип integer. В табл. 2.1 приведены все целочисленные типы
данных.
Таблица 2.1. Целочисленные типы данных
Тип данных | Диапазон значений | Формат чисел в памяти |
Integer | -2 147 483 648-2 147 483 647 | 32 бита со знаком |
Cardinal | 0-4 294 967 295 | 32 бита без знака |
Shortint | -128-127 | 8 битов со знаком |
Smallint | -32 768-32 767 | 16 битов со знаком |
Lohgint | -2 147 483 648-2 147 483 647 | 32 бита без знака |
Int64 | -2^63-2^63-1 | 64 бита со знаком |
Byte | 0-255 | 8 битов без знака |
Word | 0-65 535 | 16 битов без знака |
Longword | 0-4 294 967 295 | 32 бита без знака |
Для записи целых чисел можно использовать знаки "+" и "- ".
Если знак числа отсутствует, число считается положительным.
Вещественные типы данных
Наиболее используемым вещественным типом является тип Real. Переменные этого
типа могут содержать любые непорядковые числовые значения со знаком. Различия
вещественных типов данных заключаются в основном в отличии числа знаков после
запятой (точности). Табл. 2.2 содержит перечень вещественных типов данных языка
Object Pascal.
Таблица 2.2. Вещественные типы данных
Тип данных | Диапазон значений | Точность (знаков) | Количество байт |
Rea148 | 2,9x10^ -39 -1,7х10^38 | 11-12 | 6 |
Single | 1,5x10^-45-3,4x10^38 | 7-8 | 4 |
Double | 5,0x10^-324-1,7х10^308 | 15-16 | 8 |
Extended | 3,6x10^-4951-1,1х10^4932 | 19-20 | 10 |
Comp | -2^63+1-2^63 -1 | 19-20 | 8 |
Currency | -922 337 203 685 477,5808-922 337 203 685 477,5807 | 19-20 | 8 |
Real | 5,0x10^-324-1,7х10^308 | 15-16 | 8 |
Примечание
Шестибайтовый тип Real48 применялся в ранних версиях языка Object Pascal как
Real. Если вы перекомпилируете код, который использовал ранний шестибайтовый
тип Real, вы можете для удобства изменить его на Real48. Кроме того, вы можете
применить директиву компилятора {$REALCOMPATIBILITY ON} для автоматического
перевода типа Real в шестибайтовый.
О вышеперечисленных типах можно еще сказать следующее:
тип Real48 добавлен в язык для обратной совместимости со старыми версиями программ.
Так как такой формат данных не является "родным" для процессоров семейства
Intel, использование типа Rea148 замедляет скорость выполнения программы;
тип Extended предлагает большую точность, чем другие вещественные типы, но является
наименее компактным. Будьте осторожны при использовании данного типа, если вы
хотите создавать программы сразу для нескольких платформ;
тип Comp является "родным" для семейства процессоров Intel и представляет
собой 64-разрядное целое число. Данный тип не относится к целым типам, т. к.
не является порядковым и при присваивании переменной
данного типа вещественного числа происходит его округление до ближайшего целого.
Кроме того, данный тип не поддерживает некоторые операции, допустимые над целыми
порядковыми числами (inc(x), Dec(x) и др.) Этот тип используется лишь для обратной
совместимости. Для лучшего быстродействия воспользуйтесь типом Int 64;
тип Currency является типом с фиксированной запятой, которая применяется для
уменьшения ошибок при вычислениях, связанных с денежными суммами. Данный тип
представляет собой 64-разрядное целое число с четырьмя знаками после запятой.
вещественными числами допускается осуществлять следующие операции:
Round (x) - округление числа х;
Trunc(x) - отбрасывание дробной части числа х.
Логические типы данных
Для хранения логических значений Object Pascal использует тип данных Boolean.
Переменная логического типа занимает один байт памяти и может 1ринймать два
значения: 1 или 0. Значение 1 соответствует значению True ^истина). Значение
0 соответствует значению False (ложь). Из-за того, что щнный тип'не совместим
с подобными логическими типами, применяемыми в Других языках программирования,
Object Pascal имеет три дополнительных логических типа:
ByteBool - порядковое численное значение от 0 до 255, где 0 соответствует значению
False, а все остальные числа - значению True. Данный Шй занимает 1 байт памяти;
WordBool - порядковое числовое значение от 0 до 65 535, где 0 соответствует
значению False, а все остальные числа - значению True. Данный тип занимает 2
байта памяти;
LongBool - порядковое числовое значение от 0 до 4 294 967 295, где 0 соответствует
значению False, а все остальные числа - значению True. Данный тип занимает 4
байта памяти.
Операции над этими типами могут привести к разным значениям. В табл. 2.3 вы
найдете отличия в результатах операций над различными логическими типами.
Таблица 2.3. Отличия результатов операций над логическими типами
Тип данных Boolean | Типы данных ByteBool, WordBool, LongBool |
False < True | False <> True |
Ord (False) = 0 | Ord (False) = 0 |
Ord (True) = 1 | Ord (True) <> 0 |
Succ (False) = True | Succ (False) = True |
Pred (True) = False | Pred (False) = True |
Символьные типы данных
Основным символьным типом является char. Данный тип используется для хранения
символа из таблицы ASCII. Каждый символ в данной таблице представлен числовым
значением от 0 до 255, поэтому переменная такого типа занимает в памяти всего
1 байт.
Кроме типа Char, язык Object Pascal имеет еще два символьных типа:
AnsiChar является полным аналогом типа char. Занимает 1 байт памяти;
WideChar - тип, который используется для хранения символов в кодировке Unicode.
Данная кодировка ограничена не 256-ю а
65 535-ю символами. Занимает 2 байта памяти.
Над символьными типами данных допустимы следующие операции:
chr(x) - возвращает символ с кодом, который соответствует целочисленному значению
х;
UpCase(c) - возвращает символ с, преобразованный в верхний регистр (то есть
преобразует прописные буквы в заглавные).
Структурные типы данных
Структурные типы данных - это такие типы, которые состоят из данных Других типов,
в том числе из данных структурного типа. К числу таких данных относятся:
строки;
множества;
массивы;
записи;
файлы.
Рассмотрим эти типы данных.
Строки
В Object Pascal имеются строковые типы данных, которые перечислены в табл. 2.4.
Таблица 2.4. Строковые типы данных
Тип данных | Максимальная длина | Занимаемая память | Используется для: |
ShortString | 255 символов | 2-256 байт | совместимости с предыдущими версиями языка |
AnsiString | 2^31 символов | 4 байт-2 Гбайт | символов ANSI, строк переменной длины |
WideString | 2^30 символов | 4 байт-2 Гбайт | символов Unicode, COM-серверов и интерфейсов |
Кроме того, наиболее часто применяется тип данных string. Свойства данного
типа зависят от директивы компилятора {$H+}: если она включена {$Н+}, то данный
тип эквивалентен типу AnsiString. Если же она выключена {$Н-}, то тип string
будет равносилен типу Shortstring. По умолчанию данная директива выключена.
Строки, по своему определению, являются массивами символов. Поэтому для обращения
к любому символу строки достаточно указать название строковой переменной и номер
символа (как при обращении к элементу массива):
var
A:,.Char;.
MyString: String;
begin
A:=MyString[10];
end;
Кроме перечисленных в табл. 2.4 строковых типов данных, имеется еще один тип
PChar, который является строкой с нулевым окончанием, т. е. в конце строки стоит
код 0. Длина строки типа PChar может быть любой, но, естественно, не более чем
объем памяти компьютера.
Множества
Множество - это набор данных, относящихся к одному и тому же простому типу.
Значения входящих в множество элементов ограничены только своим простым типом.
Количество элементов множества не должно превышать 256. Описание множественного
типа можно осуществить так:
set of Тип данных;
Рассмотрим способ, задания множества целых чисел путем определения промежутка
чисел:
Type
TSomeInts = 1..250;
TIntSet = set of TSomeInts;
В данном примере мы создаем тип множества Tintset, который содержит набор целых
чисел от 1 до 250. Перед этим мы создали свой тип TSomeInts, который является
частью типа Integer. Мы можем создать это же множество другим способом:
Type TIntSet = set of 1..250;
В общем случае, элементы множества задаются с помощью простого их перечисления
в квадратных скобках через запятую. Например, если ранее была записана представленная
выше строка определения типа Tint set, можно задать множества set1 и set2:
var Set1 Set2: TIntSet;
…
Set1 : = [1, 3, 5, 7, 9];
Set2: = [2, 4, б, 8, 10]
Кроме того, вы можете задавать множества непосредственно в объявлении переменных
с помощью конструкции set of:
var MySet: set of 'a'..'z';
…
MySet := ['a','b','c'];
В табл.. 2.5 приведен список операций, которые допустимы над множествами.
Таблица 2.5. Операции, допустимые над множествами
Обозначение | Название | Тип результата | Результат | Пример |
+
|
Объединение множеств | Множество | Неповторяющиеся элементы первого и второго множества | Set1 + Set2 |
-
|
Разность множеств | Множество | Элементы из первого мно жества, которые отсутствуют во втором | Set1 - Set2 |
*
|
Пересечение множеств | Множество | Элементы, которые есть как в первом, так и во втором множестве | Set1 * Set2 |
=
|
Эквивалентность | Логический | Истина, если множества эквивалентны, иначе - ложь | Set1 = Set 2 |
<>
|
Неравенство | Логический | Истина, если множества не являются эквивалентными, иначе - ложь | Set1<> Set 2 |
<=
|
Подмножество | Логический | Истина, если первое множество входит во второе, ложь - в противном случае | Set1<= Set 2 |
>=
|
Расширенный набор | Логический | Истина, если первое множество включает в себя второе, иначе - ложь |
Set1>= Set 2 |
In
|
Членство | Логический | Истина, если данный элемент входит в множество, иначе - ложь | A in Set1 |
Массивы
Массив - это упорядоченная совокупность элементов одного и того же типа. Элементы
массива имеют уникальные индексы. Массив обязательно имеет имя.
Так как элементы массива имеют индексы, массивы могут содержать одинаковые значения
неоднократно. Каждый элемент массива однозначно определяется именем массива
и собственным индексом.
Массивы подразделяются на статические и динамические.
Статический массив - это массив, размеры которого задаются при объявлений, т.
е. это массив с четкими границами индексов.
Статический массив определяется следующей конструкцией языка Object Pascal:
Array [indexType1, ..., indexTypen] of baseType;
Каждый indexType внутри квадратных скобок является порядковым типом, диапазон
которого не превышает 2 Гбайт. Диапазон каждого indexType ограничивает число
элементов, входящих в массив.
Примечание
Хотя, по определению, индексом массива может быть любой порядковый тип, на практике
обычно применяется тип integer.
Для обращения к любому элементу массива нужно указать сначала имя массива, а
затем - в квадратных скобках номер (индекс) элемента:
MyArray [10];
Динамический массив - это массив, в котором при объявлении указывается со тип
его элементов. Размеры динамических массивов изменяются в выполнения программы.
Динамический массив задается с помощью нижеприведенной конструкции:
array of baseType;
Object Pascal поддерживает многомерные массивы. Самым простым Дается одномерный
массив. Его можно представить как пронумерованную строку переменных (рис. 2.1).
Приведем пример создания простого одномерного массива.
Рис. 2.1. Одномерный массив на десять переменных
Статистический одномерный массив:
var MyArray: array [1. .100] of Char;
Данная запись задает одномерный массив с именем МуАггау, который будет содержать
100 символьных переменных. Данные переменные будут иметь от 1 до 100. Так, например,
для доступа к пятому элементу массива нужно использовать запись МуАггау [ 5
] .
Динамический одномерный массив:
var MyFlexibleArray: array of Real;
Данное объявление, в отличие от предыдущего, не занимает память под будущий
массив. Для того чтобы это сделать, можно воспользоваться вызовом процедуры
SetLength. Например, команда
SetLength (MyFlexibleArray, 20);
отводит в памяти массив на 20 вещественных чисел с индексами от 0 до 19.
Примечание
Индексами динамических массивов всегда являются целые числа. Стартовый индекс
- всегда 0.
Доступ к элементам динамического массива аналогичен доступу к элементам статического
массива.Более сложным примером массива является двумерный массив. Его можно
представлять как таблицу переменных, составленную из строк и столбцов (рис.
2.2).
Рис. 2.2. Двумерный массив А на двадцать элементов
Задание статического двумерного массива:
var MyMatrix: arrayfl..10, 1..50] of Real;
Многомерные массивы называют еще и массивами массивов. То есть можно записать
задание того же двумерного массива как:
var MyMatrix: array[1..10] of array[1..50] of Real;
Обращение к элементу массива происходит по всем его индексам. Например, для
нашего двумерного массива доступ к элементу может выглядеть
Так: MyMatrix[5,30],ЛИбо MyMatrix[5] [30].
Для задания многомерного динамического массива можно использовать конструкцию
языка:
array of array of baseType;
Например, создать двумерный динамический массив можно следующим образом:
var MyArray: array of array of integer;
Для того чтобы установить длину многомерного динамического массива с помощью
процедуры setLength, нужно выполнить ее для всех индексов массива. Например,
SetLength(MyArray, 10,20);
Записи
Записи являются аналогом структур в других языках программирования. Они объединяют
фиксированное число разнородных элементов (элементов разных типов). Каждый элемент
записи имеет свое уникальное в пределах записи имя и называется полем.
Записи делятся на:
фиксированные;
вариантные.
Фиксированная запись - это запись, которая состоит из фиксированного числа полей.
Для объявления фиксированной записи применяется следую-1ая конструкция языка
Object Pascal:
Record
FieldListi1: Type1;
…
FieldListiN: TypeN;
end;
FieldList1 - имя первого поля, a FieldListN - имя последнего, N-го поля записи.
Вариантная запись - это запись, которая состоит из фиксированного числа 1ей,
но позволяющая по-разному рассматривать области памяти, занимаемые полями. Вариантная
часть в объявлении записи начинается со слова case должна располагаться после
объявления других полей записи. Для объявления вариантной записи можно использовать
следующую конструкцию:
Record
FieldList1: Typel;
…
FieldListN: TypeN;
case tag: ordinalType of
constantList1: (variant1);
...
constantListn: (variantn);
end;
Первая часть объявления записи, до слова case, такая же, как и в фиксированной
записи. После слова case начинается вариантная часть. В этой части:
признак (tag) является необязательной частью и представляет собой любую объявленную
переменную типа ordinalType. Если вы не используете переменной, то можно ставить
двоеточие сразу после слова case;
ordinalType - это порядковый тип;
каждый из вариантов значения переменной tag, представленный в списке constantList,
должен быть единственным, без повторов;
каждое описание варианта (varianti .. variantn) должно содержать
обычное описание поля, например FieldVarl: typel;.
Приведем пример использования вариантной записи. Предположим, что запись должна
содержать данные о человеке. Назовем запись Person. Пусть она содержит имя (поле
FirstName), фамилию (поле LastName), дату рождения (поле BirthDate) человека.
Кроме того, если человек является гражданином России, в записи указывается место
его рождения (поле Birthplace). Если же человек - иностранец, то в записи о
нем должны присутствовать следующие поля: страна (поле country), дата въезда
в Россию (поле EntryDate) и дата отъезда из России (поле ExitDate). Такую запись
мы объявляем в листинге 2.1.
Листинг 2.1. Использование вариантной записи
var Person = record
FirstName, LastName: string[40];
BirthDate: TDate;
qase Citizen: Boolean of
True: (Birthplace: string[40]);
False: (Country: string[20];
EntryDate, ExitDate: TDate);
end;
Переменная citizen в представленном выше листинге должна быть истинна, если
человек является гражданином России, и ложна - в противном случае.
Файлы
Файл - это именованная порядковая последовательность элементов одного типа,
которая находится на внешнем запоминающем устройстве (дискете, жестком диске
и др.).
По определению, можно сказать, что файл похож на одномерный динамический массив.
Отличие все же есть. Файл размещается не в оперативной памяти компьютера, а
на диске и не требует предварительного задания своего размера.
Для работы с файлами программисты используют файловые переменные или логические
файлы.
Файловая переменная - это переменная, которая связывается с конкретным файлом
на диске. Все операции с этой переменной приводят к изменению физически размещенного
на диске файла.
Файлы бывают разного типа, в зависимости от входящих в него элементов. Так,
различают текстовые, типизированные и нетипизированные файлы.
Текстовые файлы состоят из строк текста переменной длины. Такие файлы объявляются
с помощью слова TextFiie. Приведем пример объявления файловой переменной текстового
файла:
var f: TextFiie;
Типизированные файлы состоят из данных определенного (указанного) типа. Такие
файлы объявляются с помощью конструкции file of typeData. Например:
var f1: file of real;
f2: file of boolean;
Нетипизированные файлы могут содержать элементы, тип которых не указан. Такие
файлы объявляются просто словом file. Например:
var f: file;
Кроме доступа к файлу с помощью файловых переменных, многие компоненты Kylix
предоставляют свои собственные методы работы с файлами, такие как LoadFromFiie
или saveToFiie. О них мы расскажем далее, когда будем описывать свойства и методы
основных компонентов Kylix.
Указатели, процедурные и вариантные типы данных
Кроме рассмотренных выше простых и структурных типов данных, в языке Object
Pascal имеется еще несколько типов данных, не относящихся ни к тем, ни к другим.
Рассмотрим их.
Указатели
Указатель - это переменная, в которой хранится адрес памяти, указывающий на
начало размещения некоторых данных в памяти.
Указатели применяют для определения адреса в памяти конкретного объекта, например
какой-либо переменной.
Переменные типа "указатель" содержат и изменяют свои значения в процессе
выполнения программы.
Указатели бывают типизированными и нетипизированными.
Типизированный указатель - это указатель, который ссылается на данные определенного
типа и указан при объявлении указателя или типа указателя.
Для объявления типа указателя используется специальный значок ^, который располагается
перед типом адресуемых данных.
Приведем пример объявления типизированного указателя:
var
X, Y: Integer; // X и Y переменные типа Integer
Р: ^Integer; // Р - указатель типа Integer
Нетипизированный указатель всегда имеет тип Pointer и ссылается на данные любого
типа.
Пример объявления нетипизированного указателя:
var
Р: Pointer; o// Р-- нетипизированный указатель типа Pointer
Рассмотрим пример использования указателей и поясним на этом примере операции,
допустимые над указателями (листинг 2.2).
Листинг 2.2 Пример использования указателей
var
X, Y: Integer; // объявление целых переменных X и Y
Р: "Integer; // Р - указатель целого типа
begin
X := 17; // присваиваем значение переменной X
Р := @Х; // присваиваем адрес переменной X указателю Р
Y :*= Р^; // разыменовываем указатель Р и присваиваем результат
// переменной Y
end;
Итак, для назначения указателю адреса объекта (в нашем случае - переменной х)
мы воспользовались операцией @. Символ @, поставленный перед объектом, определяет
адрес этого объекта в оперативной памяти.
Символ ^ имеет два назначения. Во-первых, если он стоит перед идентификатором
типа, он обозначает тип данного указателя. Если же он стоит после переменной
типа указателя, как в последней строке нашего примера, то он разыменовывает
указатель. Операция разыменовывания указателя применяется для получения доступа
к значению адресуемых данных.
После выполнения программы, представленной на листинге 2.2, обе переменные х
и Y будут иметь одинаковое значение - 17.
Процедурные типы данных
Процедурные типы данных применяются для того, чтобы можно было процедуры и функции
понимать как обычные значения, которые можно присваивать переменным, или выполнять
с ними различные действия.
Описание данных процедурного типа похоже на описание процедуры или функции.
На листинге 2.3 представлено описание процедурных указателей.
Листинг 2.3. Описание процедурных указателей
type
TlntegerFunction = function: Integer;
TProcedure = procedure;
TStrProc = procedure(const S: string);
TMathFunc = function(X: Double): Double;
var
F: TlntegerFunction; // F - это функция без параметров, которая
// возвращает целое число
Proc: TProcedure; // Proc - это процедура без параметров
SP: TStrProc; // SP - это процедура, у которой есть один
// строковый параметр
М: TMathFunc; // М - это функция с действительным параметром
// данная функция возвращает действительное значение
Для описания данных процедурного типа используется конструкция of object. Например:
type
TMethod = procedure of object;
TNotifyEvent = procedure(Sender: TObject) of object;
Данные процедурного типа применяются, например, для назначения обработчиков
события.
Вариантные типы данных
Иногда возникает необходимость работы с типами данных, которые не могут быть
определены во время разработки приложения или тип которых изменяется. Для этого
в язык Object Pascal были введены так называемые вариантные типы данных. Переменные
вариантного типа могут содержать данные разных типов, кроме структурных типов
данных, указателей и типа Iint64. Для объявления переменной вариантного типа
используется слово Variant. Все типы являются совм6стимыми с типом Variant,
и компилятор делает необходимые преобразования типов автоматически.
Пример, приведенный на листинге 2.4, показывает применение вариантного типа
данных.
Листинг 2.4 Использование данных вариантного типа
var
V1, V2, V3, V4, V5: Variant;
I: Integer;
D: Double;
S: string; begin
V1 := 1; // целое значение
V2 := 1234.5678; // действительное значение
V3 := 'Это строка!'; // строковое значение
V4 :- '1000'; // строковое значение
V5 := V1 + V2 + V4; // действительное значение, равное 2235.5678
I := V1; //1=1 (целое значение)
D := V2; // D = 1234.5678 (действительное значение)
S := V3; // S = 'Это строка!' (строковое значение)
I := V4; // I = 1000 (целое значение)
S := V5; // S - '2235.5678' (строковое значение)
end;
Переменная вариантного типа может принимать два дополнительных значения:
Unassigned - не определено;
Null - значение неизвестного типа или значение потеряно.