Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
delphi / песни о паскале.pdf
Скачиваний:
63
Добавлен:
26.03.2016
Размер:
5.16 Mб
Скачать

Глава 32

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

Инкремент и декремент

Угадайте, что чаще всего делают с целыми переменными? — прибавляют и вычитают единицу. Потому в процессорах стараются ускорить эти операции. Паскаль не обошел вниманием эту особенность программ, и предлагает вам две процедуры, объявленные так:

procedure

Inc

(var

N

:

longint);

{

прибавление единицы к переменной N }

procedure

Dec

(var

N

:

longint);

{

вычитание единицы из переменной N }

 

 

 

 

 

 

 

 

Хотя параметр N в процедурах объявлен как LONGINT, в действительности здесь может стоять переменная любого порядкового типа: INTEGER, WORD, BYTE,

CHAR и даже BOOLEAN.

var B: byte; N: integer; C: char;

. . .

 

 

Inc(B);

{ B:= B+1

}

Dec(N);

{ N:= N-1

}

C:= ‘A‘;

Inc(C);

{ ‘B‘}

Процедуры инкремента и декремента — так их называют — выполняются быстрее операторов присваивания N:=N+1 и N:=N-1.

Работающим в IDE Borland Pascal следует учесть, что здесь процедуры инкремента и декремента не подвластны директиве $R+ (в отличие от сложения и вычитания). То есть, переполнения и антипереполнения не вызывают аварий.

Диапазоны

Контроль переполнений директивой $R+ повышает надежность программ. Но порой нужны более сильные ограничения. Предположим, некая переменная M по смыслу является порядковым номером месяца в году. Стало быть, её значения должны быть ограничены диапазоном от 1 до 12. Программист может указать это компилятору, объявив переменную как диапазон, и явно задав допустимые пределы её изменения:

var M : 1..12;

Диапазон выражается двумя константами: минимальным и максимальным значениями, разделенными двумя точками. Теперь, при включенной директиве $R+, будет выдано сообщение об ошибке при попытке присвоить этой переменной любое значение за пределами 1…12. Во всем прочем диапазон — это обычный целочисленный тип (в данном случае — однобайтовый).

223

Глава 32

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

Перечисления

Рассмотрим ещё пример:

var M : 1..12;

{ месяцы }

D : 1..7;

{ дни недели }

 

M:= D;

{ здесь возможна смысловая ошибка }

 

 

Здесь объявлены две переменные: M — номер месяца в году, и D — номер дня недели. Это сделано через диапазоны, что гарантирует соблюдение границ. Но ничто не мешает нам присвоить месяцу значение дня, — ведь это не нарушит установленных пределов. Другое дело — смысл. Есть ли смысл в таком присваивании, или налицо ошибка программиста? Вероятней всего — последнее. Выявить ошибки такого рода помогает ещё один тип данных — перечисление.

Перечислением программист дает имена всем возможным значениям переменных, эти имена перечисляются внутри круглых скобок. Например, переменные M1 и M2 могут быть объявлены через сокращенные названия месяцев, а переменные D1 и D2 — через сокращенные названия дней недели.

var M1, M2 : (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);

D1, D2 : (Mond, Tues, Wedn, Thur, Frid, Satu, Sund);

Теперь компилятор разрешит присваивать переменным только объявленные значения, например:

M1:= Apr;

{ допустимо }

M1:= M2;

{ допустимо }

M1:= 3;

{ ошибка }

M1:= Jan+2;

{ ошибка }

D2:= M1;

{ ошибка }

 

 

Кстати, один из перечислимых типов вам знаком — это булев тип. Объявление булевой переменной равнозначно объявлению перечисления.

var B : ( FALSE, TRUE );

{ равнозначно B : Boolean; }

Имена в перечислениях — это не строковые константы. Поэтому имя Jan и строка «Jan» совсем не одно и то же. Иначе говоря, оператор Write(M1) не напечатает вам название месяца, который содержится в переменной M1. Вы спросите, а как же печать булевых данных? Ведь они печатаются как «TRUE» и «FALSE». Да, но это единственное исключение.

224

Глава 32

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

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

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

Определение порядкового номера

Название «порядковый» говорит о том, что значения этих типов данных упорядочены относительно друг друга. С числами всё ясно, — здесь порядок очевиден. А символы? Если вспомнить алфавит и таблицу кодировки символов, вопрос отпадет.

Хорошо, а как насчет перечислений и булевого типа? Оказывается, в памяти компьютера они тоже хранятся как числа. Например, упомянутое выше перечисление месяцев в памяти компьютера кодируется числами 0, 1, 2 и так далее, то есть как числовой диапазон 0..11. Таким образом, значение Jan соответствует нулю, Feb — единице и так далее. Подобным образом кодируются и булевы данные: FALSE — нулем, а TRUE — единицей.

В Паскале есть функция, определяющая числовой код данных любого порядкового типа. Она называется Ord (от Order — «порядок»), вот примеры её применения (в комментариях указаны результаты).

Writeln ( Ord(5) );

{ 5

}

Writeln ( Ord(’F’) );

{ 70 – по таблице кодировки}

Writeln ( Ord(Mar) );

{ 2

– смотри перечисление месяцев }

Writeln ( Ord(False) );

{

0

}

Writeln ( Ord(True) );

{

1

}

 

 

 

 

Для числа функция возвращает само число, для символа — код по таблице кодировки, а для перечислений — порядковый номер в перечислении, считая с нуля.

Сравнение

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

if

M2

>

M1

then

… {

если

второй месяц больше первого }

if

D1

=

D2

then

… {

если

дни совпадают }

 

 

 

 

 

 

 

 

Нельзя сравнивать данные разных перечислимых типов.

225

Глава 32

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

if M2 > D1 then … { месяц и день – недопустимо } if 'W' > 20 then … { символ и число – недопустимо }

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

if Ord(M2) = Ord(D1) then … { сравниваются числовые коды }

if Ord(’W’) > 20 then … { сравнивается код символа с числом }

Прыг-скок

Итак, числа, символы, булевы данные, диапазоны и перечисления принадлежат к порядковым типам. В общем случае наращивать и уменьшать порядковые переменные путём сложения и вычитания нельзя (можно лишь числа и диапазоны). Но рассмотренные ранее процедуры инкремента (INC) и декремента (DEC) умеют это делать, они были введены в Паскаль фирмой Borland. Другим таким средством являются функции SUCC и PRED, которые существовали ещё в исходной «виртовской» версии языка.

Функция SUCC (от слова SUCCESS — «ряд», «последовательность») принимает значение порядкового типа и возвращает следующее значение того же самого типа, например:

Writeln ( Succ(20) );

{ 21 }

Writeln ( Succ(’D’) );

{ ’E’ }

Writeln ( Succ(False) );

{ True }

m:= Succ(Feb);

{ переменной m присвоено Mar }

 

 

Функция PRED (от PREDECESSOR — «предшественник») возвращает предыдущее значение порядкового типа:

Writeln ( Pred(20) );

{ 19 }

Writeln ( Pred(’D’) );

{ ’C’ }

Writeln ( Pred(True) );

{ False }

m:= Pred(Feb);

{ переменной m присвоено Jan }

 

 

Функции SUCC и PRED подчиняются директиве контроля диапазонов $R+. Например, следующие операторы вызовут аварийное прекращение программы:

{ $R+ }

 

m:= Succ(Dec);

{ превышение верхнего предела }

m:= Pred(Jan);

{ выход за нижний предел }

 

 

В Borland Pascal есть одна тонкость: директива $R+ не действует, если функции SUCC и PRED вызываются для чисел, например:

226

Глава 32

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

{ $R+ }

 

 

var B : byte;

 

 

. . .

 

 

B:=255;

B:= Succ(B);

{ нет реакции на переполнение }

B:=0;

B:= Pred(B);

{ нет реакции на антипереполнение }

В таких случаях в Borland Pascal имеет силу директива проверки переполнения $Q+, которая соответствует флажку «Overflow Checking» в окне опций компилятора (рис. 74). Директивы $R+ и $Q+ можно применять совместно, например:

{ $R+, Q+ }

 

 

 

var B : byte;

 

{ допустимые значения для байта от 0 до 255 }

C : ’a’..’z’;

{ это ограниченный диапазон символов }

. . .

 

 

 

C:=’z’;

C:= Succ(C);

{ сработает R+ }

B:=255;

B:= Succ(B);

{ сработает Q+ }

 

 

 

 

Счетчики циклов

В операторе FOR-TO-DO для счетчика цикла мы применяли числовые переменные. Теперь разнообразим меню: ведь для этого годятся переменные любого порядкового типа, например:

var m : (Jan,Feb,Mar,Apr,May,Jun,Jul,Aug,Sep,Oct,Nov,Dec);

. . .

for m:= Jan to Dec do . . .

А вот так вычисляется сумма кодов для символов от «a» до «z», здесь счетчиком цикла является символьная переменная:

var Sum : word; Chr : char;

. . .

Sum:=0;

for Chr:= ’a’ to ’z’

do Sum:= Sum + Ord(Chr);

Метки в операторе выбора

Вот ещё одно следствие числового кодирования: любой порядковый тип может служить меткой в операторе CASE-OF-ELSE-END:

227

Соседние файлы в папке delphi