ОПЕРАТОРЫ ЯЗЫКА


С одним из наиболее часто используемых операторов языка Object Pascal - оператором присваивания мы уже познакомились . Ниже рассматриваются остальные операторы.
Составной оператор и пустой оператор
Составной оператор - это последовательность произвольных операторов программы, заключенная в операторные скобки - зарезервированные слова begin ... end . Составные операторы - важный инструмент Object Pascal, дающий возможность писать программы по современной технологии структурного программирования (без операторов перехода goto).
Object Pascal не накладывает никаких ограничений на характер операторов, входящих в составной оператор. Среди них могут быть и другие составные операторы - язык Object Pascal допускает произвольную глубину их вложенности:
Функция Trim не определена в версии 1.
Вместо указанной единственной строки в этом случае
следует написать :[ while post' ', edinput.Text)>0 do
system.delete(edinput.Text, post' ', edinput.Text), 1);
StrToint(edinput.Text);]
begin
begin
begin
end;
end;
end;
Фактически весь раздел операторов, обрамленный словами begin ... end, представляет собой один составной оператор. Поскольку зарезервированное слово end является закрывающей операторной скобкой, оно одновременно указывает и конец предыдущего оператора, поэтому ставить перед ним символ “;” необязательно. Наличие точки с запятой перед end в предыдущих примерах означало, что между последним оператором и операторной скобкой end располагается пустой оператор. Пустой оператор не содержит никаких действий, просто в программу добавляется лишняя точка с запятой. В основном пустой оператор используется для передачи управления в конец составного оператора: как и любой другой, пустой оператор может быть помечен, и ему можно передать управление.
Условный оператор
Условный оператор позволяет проверить некоторое условие и в зависимости от результатов проверки выполнить то или иное действие. Таким образом, условный оператор - это средство ветвления вычислительного процесса.
Структура условного оператора имеет следующий вид:
if <условие> then <оператор1> else <оператор2>;
где if/ then/ else - зарезервированные слова (если, то, иначе);
<условие> - произвольное выражение логического типа;
<оператор1>, <оператор2> - любые операторы языка Object Pascal.
Условный оператор работает по следующему алгоритму. Вначале вычисляется условное выражение <условие>. Если результат есть True (истина), то выполняется <оператор1>, а <оператор2> пропускается; если результат есть False (ложь), наоборот, <оператор1> пропускается, а выполняется <оператор2>. Например:
var
X, Y, Max: Integer;
begin .
if X > Max then
Y := Max else
Y := X;
….
end;
При выполнении этого фрагмента переменная y получит значение переменной х, если только это значение не превышает мах, в противном случае y станет равно мах.
Условными называются выражения, имеющие одно из двух возможных значений: истина или ложь. Такие выражения чаще всего получаются при сравнении переменных с помощью операций отношения =, <>, >, >=, <, <=. Сложные логические выражения составляются с использованием логических операций and (логическое И), or (логическое ИЛИ) и not (логическое НЕ). Например:
if (а > b) and (b <> 0) then ...
Примечание
В отличие от других языков программирования в Object Pascal приоритет операций отношения меньше, чем у логинеёкйх" операции, по этому отдельные составные части сложного логического вьфажёния 5 заключаются в скобки. Например, такая запись предыдущего оператора будет неверной:
if a>b and b <> 0 then ...// Ошибка так как фактически (с учетом приоритета операции) компилятор будет транслировать такую строку:
if a>(b and b)<>0 then...
Часть else <оператор2> условного оператора может быть опущена. Тогда при значении True условного выражения выполняется <оператор1>, в противном случае этот оператор пропускается:
var
X, Y, Max: Integer;
begin
if X > Мах then Мах := X;
Y := X;
end;
В этом примере переменная y всегда будет иметь значение переменной х, а в мах запоминается максимальное значение X.
Поскольку любой из операторов <оператор1> и <оператор2> может быть любого типа, в том числе и условным, а в то же время не каждый из “вложенных” условных операторов может иметь часть else <оператор2>, то возникает неоднозначность трактовки условий. Эта неоднозначность в Object Pascal решается следующим образом:
любая встретившаяся часть else соответствует ближайшей к ней сверху по тексту программы части then условного оператора. Например:
var
a,b,c,d : Integer;
begin a := 1;
b := 2;
с := 3;
d := 4;
if a < b then // Да
if с < d then // Да
if с < 0 then // Нет
с := 0 // Этот оператор не выполняется
else
а : = b; // а равно 2
if а < b then // Да
if с < d then // Да
if с < 0 then // Нет
с := 0 // с равно 0
else // if с < О
else //if с < d
else // If a < b
а := b; // Этот оператор не выполняется
end;
 
Учебная программа INTTEST
Игра “Угадай число”: программа случайным образом выбирает целое число в диапазоне О... 1000 и запоминает его. Пользователь пытается угадать его и вводит свое число. Сравнив ввод с запомненным числом, программа сообщает - больше, меньше или равно введенное число запомненному. Ввод продолжается до угадывания, после чего программа предлагает сыграть еще раз.
Поскольку пользователь вводит только числа, изменим форму fmExample: как и в предыдущей программе intmult вместо компонента edinput типа TEdit поместим на форму одноименный компонент типа TMaskEdit. Выберите опцию File | New | Application, щелкните по компоненту edinput и удалите его с помощью клавиши Delete, затем поместите на его место компонент MaskEdit (страница Additional), назовите его edInput (свойство Name) и в его свойство
EditMask поместите строку
0999;1;
В секцию private описания класса fmExampie поместите объявление целочисленного поля х:
private
{ Private declarations }
X: Integer;
Для обработчика события OnActivate формы fmExampie Напишите такой код:
procedure TfmExample.FormActivate(Sender: TObject);
begin
X := Random (1001) ; // Загадываемслучайноечисло
edinput.SetFocus; // Передаемстроке edinput фокусввода
Caption := 'Угадай целое число в диапазоне О...1000';
IbOutput.Caption :== 'Введите число:';
end;
Поместите в обработчик события onciick кнопки bbRun такой код:
procedure TfmExample.bbRunClick(Sender: TObject);
var
Y: Integer;
begin
if edinput.Text = '' then
Exit; // Если нет входного текста, прекращаем работу
// Преобразуем ввод в число:
Y := StrToInt(Trim(edInput.Text));
edinput.Text := ''; // Очищаемввод
edinput.SetFocus; // Устанавливаемфокусввода
{ Параметр Tag = 0 означает угадывание числа, иначе - ответ на вопрос, будет ли пользователь играть после угадывания }
if Tag = 0 then
if X < Y then // Угадываниечисла
mmOutput.Lines.Add('X < '+IntToStr(Y))
else if X > Y then
mmOutput.Lines.Add('X > '+IntToStr (Y))
else // X = Y begin
mmOutput.Lines.Add("X = +IntToStr(Y));
MessageBeep(MB_OK); // Звук для привлечения внимания
IbOutput.Caption :='Вы угадали! Введите 1, если хотите повторить:';
Tag := 1; // Следующий ввод - ответ на вопрос
end;
else // Анализответа
if Y = 1 then
begin
X := Random(1001); // Новоечисло
IbOutput.Caption := 'Введите число:';
Tag := 0; // Следующий ввод - угадывание
edinput.SetFocus
end
else
Close;
end;
Комментарий к программе
При активизации окна программы обработчик FormActivate с помощью оператора
Х := Random(1001) ;
помещает в поле X случайное целое число в диапазоне от 0 до 1001 -1 = 1000 (параметр обращения к генератору псевдослучайных чисел Random на единицу больше верхней границы диапазона).
Каждый компонент Delphi имеет целочисленное свойство Tag, которым программист может распоряжаться по своему усмотрению. Программа использует это свойство формы fmExampie для разделения алгоритма обработки события OnClick кнопки bbRun на два варианта: пользователь угадывает число (тад = 0) или отвечает на предложение сыграть еще раз (тад = 1). В момент создания экземпляра класса TfmExmple - объекта fmExample - все его поля обнуляются, поэтому первоначально Tag = 0 и программа анализирует угадывание числа. При угадывании срабатывает составной оператор
begin
mmOutput.Lines.Add('X = Ч-IntToStr(Y)) ;
MessageBeep(MB OK); // Звук для привлечения внимания
IbOutput.Caption :='Вы угадали! Введите 1, если хотите повторить:';
Tag := 1; // Следующий ввод - ответ на вопрос
end
и Tag получает значение 1 (стандартная процедура MessageBeep заставляет звуковую систему ПК издать короткий звуковой сигнал).
Теперь очередной щелчок по кнопке bbRun будет означать, что пользователь подготовил ответ на вопрос, и программа анализирует его. Если пользователь ввел число отличное от 1, произойдет обращение к методу close формы fmExample и программа прекратит работу.
Операторы повторений
В языке Object Pascal имеются три различных оператора, с помощью которых можно запрограммировать повторяющиеся фрагменты программ.
Счетный оператор цикла FOR имеет такую структуру:
for <параметр цикла> := <нач_знач> to <кон знач> do <оператор>;
Здесь for, to, do - зарезервированные слова (для, до, выполнить);
<параметр_цикла> - переменная типа Integer (точнее, любого по-, рядкового типа, см. гл. 7); <нач_знач> - начальное значение - выражение того же типа; <кон_знач> - конечное значение - выражение того же типа; <оператор> - произвольный оператор Object Pascal.
При выполнении оператора for вначале вычисляется выражение <нач_знач> и осуществляется присваивание <параметр_цикла> := <нач_знач>. После этого циклически повторяется:

  • проверка условия <параметр_цикла> <= <кон_знач>; если условие не выполнено, оператор for завершает свою работу;
  • выполнение оператора <оператор>;
  • наращивание переменной <параметр_цикла> на единицу.

Учебная программа INTSLJMM


В качестве иллюстрации применения оператора for рассмотрим программу, осуществляющую ввод произвольного целого числа n и вычисление суммы всех целых чисел от 1 до N.
Для нового приложения (опция File | New | Application) соз дайте такой обработчик bbRunСlick:
procedure TfmExample.bbRunClick(Sender: TObject);
var
i,N,Sum : Integer;
begin
try // Преобразуем ввод с контролем правильности:
N := StrToInt(edInput.Text);
except // Следующие операторы выполняются, если есть ошибка ShowMessage('Ошибка ввода целого числа');
dinput.SelectAll; // Выделяем неверный ввод
Exit // Завершаем работу обработчика
end;
edInput.Text :=' ';
edinput.SetFocus;
Sum := 0; // Начальное значение Sum
for i := 1 to N
do // Цикл формирования суммы
Sum := Sum+i;
mmOutput.Lines.Add('Сумма всех целых чисел '+'в диапазоне 1...'+IntToStr(N)+' равна '+IntToStr(Sum));
end ;
Комментарий к программе
Прежде всего обратите внимание на операторы
try // Преобразуем ввод с контролем правильности:
N := StrToInt(edinput.Text);
except // Следующие операторы выполняются, если есть ошибка ShowMessage("Ошибка ввода целого числа');
edinput.SelectAll; // Выделяем неверный ввод
Exit // Завершаем работу обработчика
end;
С помощью зарезервированных слов try (попробовать), except (исключение) и end реализуется так называемый защищенный блок. Такими блоками программист может защитить программу от краха при выполнении потенциально опасного участка (подробнее см. п. 14.1). В отличие от предыдущих программ мы не изменили компонент edinput, поэтому пользователь может ввести в нем произвольный текст. Если этот текст не содержит правильное представление целого числа, попытка выполнить оператор
N := StrToInt(edInput.Text);
в обычной программе привела бы к аварийному завершению программы. Чтобы этого не произошло, мы защитили этот оператор, расположив его за try и перед except. Если ошибки нет, все операторы, стоящие за except и до end, пропускаются и обработчик нормально срабатывает. Если обнаружена ошибка, возникает так называемая исключительная ситуация (исключение) и управление автоматически передается оператору, стоящему за except, - начинается обработка исключения. Вначале с помощью стандартной процедуры ShowMessage мы сообщаем пользователю об ошибке[ Если вы запустите программу из среды Delphi, исключение будет сначала перехвачено средой и на экране появится сообщение на английском языке о характере и месте возникновения ошибки. В этом случае закройте окошко с сообщением и нажмите F9 - программа продолжит свою работу, и вы увидите окно процедуры ShowMessage. ], затем с помощью edInput. SeiectAll выделяем ошибочный текст в компоненте edinput и, наконец, с помощью вызова стандартной процедуры Exit аварийно завершаем работу обработчика (но не программы!).
Отметим также два обстоятельства. Во-первых, условие, управляющее работой оператора for, проверяется перед выполнением оператора <оператор>: если условие не выполняется в самом начале работы оператора for, исполняемый оператор не будет выполнен ни разу. Другое обстоятельство - шаг наращивания параметра цикла строго постоянен и равен (+1). Существует другая форма оператора:
for <пар_цик>: = <нач_знач> downto <кон_знач> do <оператор>;
Замена зарезервированного слова to на downto означает, что шаг наращивания параметра цикла равен (-1), а управляющее условие Приобретает вид <параметр__цикла> = <кон_знач>.
Предыдущий пример можно модифицировать так, чтобы сделать его пригодным для подсчета любых сумм - положительных и отрицательных:
Sum := 0;
if N >= 0 then
for i := 1 to N do
Sum := Sum + i
else
for i := -1 downto N do
Sum := Sum + i ;
Два других оператора повторений лишь проверяют условие выполнения или повторения цикла, но не связаны с изменением счетчика цикла.
Оператор цикла WHILE с предпроверкой условия:
while <условие> do <оператор>;
Здесь while, do - зарезервированные слова {пока [выполняется условие], делать), <условие> - выражение логического типа; <оператор> - произвольный оператор Object Pascal.
Если выражение <условие> имеет значение True, то выполняется <оператор>, после чего вычисление выражения <условие> и его проверка повторяются. Если <условие> имеет значение False, оператор while прекращает свою работу.
Учебная программа EPSILON
Программа отыскивает так называемое “машинное эпсилон” -такое минимальное, не равное нулю вещественное число, которое после прибавления его к 1,0 еще дает результат, отличный от 1,0. Замечу, что для хранения и преобразования дробных чисел в Object Pascal предназначены так называемые вещественные типы (см. гл. 7). В учебной программе используется один из этих типов - Real, занимающий 8 смежных байт и представляющий дробные (вещественные) числа в диапазоне от 10- 324 до 10+ 308 с точностью 15... 16 значащих цифр 10 .
У читателя, привыкшего к непрерывной вещественной арифметике, может вызвать недоумение утверждение о том, что в дискретной машинной арифметике всегда существуют такие числа o<x<eps, что i,o+x°i,o. Дело в том, что внутреннее представление типа Real может дать “лишь” приблизительно 10 19 возможных комбинаций значащих разрядов в отведенных для него 8 байтах. Конечно же, это очень большое число, но оно несопоставимо с бесконечным множеством вещественных чисел. Аппроксимация бесконечного непрерывного множества вещественных чисел конечным (пусть даже и очень большим) множеством их внутреннего машинного представления, и приводит к появлению “машинного эпсилон”.
Для нового приложения (опция File I New I Application) создайте такой обработчик bbRunСlick:
procedure TfmExample.bbRunClick(Sender: TObject) ;
var
Epsilon: Real;
begin
Epsilon := 1;
while l+Epsilon/2>l do
Epsilon := Epsilon/2;
IbOutput.Caption := 'Машинное эпсилон = ' +FloatToStr(Epsilon)
end;
Комментарий к программе
Для вещественных чисел можно использовать операцию деления без отбрасывания дробной части ( символ “/”). После применения этой операции результат всегда имеет вещественный тип, поэтому такой фрагмент программы ошибочен:
var
X : Integer; begin
X := 4/2; // Ошибка!Вещественный результат нельзя
// присвоить целой переменной
end;
Стандартная функция FloatToStr преобразует вещественное число в строку символов.
Оператор цикла REPEAT... UNTIL с постпроверкой условия:
repeat <тело цикла> Until <условие>;
Здесь repeat, until - зарезервированные слова (повторять [до тех пор}, пока [не будет выполнено условие]); <тело_цикла> - произвольная последовательность операторов Object Pascal; <условие> - выражение логического типа.
Операторы <тело_цикла> выполняются хотя бы один раз, после чего вычисляется выражение <условие>: если его значение есть False, операторы <тело_цикла> повторяются, в противном случае оператор repeat... until завершает свою работу.
Обратите внимание: пара repeat... unti1 подобна операторным скобкам begin ... end, поэтому перед until ставить точку с запятой необязательно.
Замечу, что для правильного выхода из цикла условие выхода должно меняться внутри операторов, составляющих тело цикла while или repeat... until. Следующие циклы никогда не завершатся “естественным” способом:
while True do begin
end;
и
repeat
until False;
Для гибкого управления циклическими операторами for, while и repeat в состав Object Pascal включены две процедуры без параметров:
break - реализует немедленный выход из цикла; действие процедуры заключается в передаче управления оператору, стоящему сразу за концом циклического оператора;
continue - обеспечивает досрочное завершение очередного прохода цикла; эквивалент передачи управления в самый конец циклического оператора.
Введение в язык этих процедур практически исключает необходимость использования операторов безусловного перехода goto.
Оператор выбора
Оператор выбора позволяет выбрать одно из нескольких возможных продолжений программы. Параметром, по которому осуществляется выбор, служит ключ выбора - выражение любого порядкового типа (из уже рассмотренных к порядковым относятся integer, char и логический).
Структура оператора выбора такова:
case <ключ_выбора> of <список_выбора> [ else <операторы>] end;
Здесь case, of, else, end - зарезервированные слова (случай, из, иначе, конец); <ключ_выбора> - ключ выбора (выражение порядкового типа); <список_выбора> - одна или более конструкций вида:
<константа_выбора> : <оператор>;
<константа_выбора> - константа того же типа, что и выражение <ключ_выбора>; <оператор> - произвольный оператор Object Pascal.
Оператор выбора работает следующим образом. Вначале вычисляется значение выражения <ключ_выбора>, а затем в последовательности операторов <список_выбора> отыскивается такой, которому предшествует константа, равная вычисленному значению. Найденный оператор выполняется, после чего оператор выбора завершает свою работу. Если в списке выбора не будет найдена константа, соответствующая вычисленному значению ключа выбора, управление передается операторам, стоящим за словом else. Часть else <операторы> можно опускать. Тогда при отсутствии в списке выбора нужной константы ничего не произойдет, и оператор выбора просто завершит свою работу.
Любому из операторов списка выбора может предшествовать не одна, а несколько констант выбора, разделенных запятыми. Например:
var
ch : Char;
begin
case ch of
'n','N','H','H': IbOutput.Caption := 'Нет';
'у','Y','д','Д': IbOutput.Caption := 'Да';
end
end;
Учебная программа CALC
Составим программу, имитирующую работу микрокалькулятора. Программа вводит два операнда и знак математического действия, после чего показывает результат (см.
Для упрощения ввода операндов и знака поместим на нашу учебную форму еще два компонента. Выберите File | New | Application, переименуйте компонент ibinput в ibinputi и сделайте его свойство width (длина) равным 121 (стандартная длина компонентов Edit), a свойство Left (слева) - 64. Справа от компонента ibinputi поместите компонент comboBox (страница Standard), назовите его cbSign (свойство Name) и установите для него width =41. Раскройте диалоговое окно свойства items этого компонента и введите четыре строки со знаками математических действий в такой последовательности:
+
-
*
/
И, наконец, справа от cbSign разместите еще один компонент Edit (страница Standard) и назовите его edinput2. He забудьте очистить свойства Text у всех трех компонентов.
Для обработчика события bbRunciick введите такой текст:
procedure TfmExample.bbRunClick(Sender: TObject);
var
X, Y, Z: Real;
begin
{ Блокируем работу, если не введены операнды и не выбрано действие }
if (edInputl.Text='') or (edlnput2.Text='') or (cbSign.Itemlndex<0) then Exit;
// Проверяем правильность ввода 1-го операнда:
try // Начало защищенного блока
Х := StrToFloat(Trim(edinputi.Text));
except // Обработка ошибки
ShowMessage('Ошибочная запись числа: '+edlnputl.Text);
edinputi.SelectAll;
Exit;
end; // Конец защищенного блока
// Проверяем правильность ввода 2-го операнда:
try // Начало защищенного блока
Y := StrToFloat(Trim(edlnput2.Text));
except // Обработка ошибки
ShowMessage('Ошибочная запись числа: '+edlnput2.Text);
edlnput2.SelectAll ;
Exit;
end;
// Конецзащищенногоблока
// Все правильно: вычисляем результат
case cbSign.Itemlndex of
0: Z := X + Y;
1: Z := X - Y;
2: Z := X * Y;
3: try
Z := X / Y; except
Z := l.le+38; // Бесконечность при делении на О
end;
end;
// Показываем результат
IbOutput.Caption := Trim(edinputi.Text)+' '+ cbSign.Items[cbSign.Itemlndex]+' '+ Trim(edlnput2.Text)+' = ';
if Z >= l.le+38 then
IbOutput.Caption := IbOutput.Caption+'бесконечность'
else
IbOutput.Caption := IbOutput.Caption+FloatToStr(Z);
mmOutput.Lines.Add(IbOutput.Caption) ;
// Очищаемвводedinputi.Text := '';
ed!nput2.Text := ' ';
cbSign.ItemIndex := -1;
end;
Комментарий к программе
В качестве операндов в программе выбраны переменные вещественного типа Real. Символьное представление значений Real в общем случае имеет вид:
±ЦЦЦЦЦ.ДДДДДе+ППП
Здесь ± - знак + или -; ццццц - цифры целой части числа; ддддд -цифры дробной части; ппп - цифры десятичного порядка. Символ е (E) в такой записи читается как “умножить на 10 в степени”. Например, 1. 1e+38 читается: “один и одна десятая умножить на 10 в степени плюс тридцать восемь”. Следует учесть, что компилятор Delphi в качестве разделителя целой и дробной частей всегда использует символ “.”, в то время как аналогичный разделитель в Windows зависит от выбранной страны, и для России им обычно является запятая “,”. Это означает, что вещественные константы в тексте программы вы всегда должны записывать с разделителем “.”, а при вводе пользователем программы вещественных чисел он должен использовать разделитель Windows (этот разделитель можно выбрать В Windows 32 С помощью Пуск | Настройка 1 Панель управления | Язык и стандарты).
Поскольку правильная форма записи вещественного числа гораздо богаче формы записи целого, использовать однострочный редактор с маской для фильтрации вещественных чисел невозможно, поэтому в программе используются обычные редакторы edInput1 и edInput2. В этой ситуации контроль за правильностью записи приходится возлагать на функцию преобразования strToFioat (эта функция преобразует строку в вещественное число). Если функция обнаружит ошибку в записи вещественного числа, она инициирует исключительную ситуацию, которая обычно приводит к аварийному завершению работы программы. Чтобы этого не произошло, используются защищенные блоки (см. комментарий к программе INITSUMM). Таким же блоком защищается операция деления: если число долится на ноль или на очень малую величину, результату присваивается большая положительная величина 1,1*10 +38 . При выводе сообщения эта величина заменяется на слово “бесконечность”.
Для выбора операции в программе используется компонент Combовох - раскрывающийся список выбора. Свойство items этого компонента хранит набор строк, которые определяют список выбора. Эти строки пронумерованы начиная с нуля (в нашем случае cbSign.Items[0] = '+', a cbSign. Items [3] = '/'). Номер выбранной строки содержит свойство cbSign.ItemIndex, а если не выбрана ни одна строка, это свойство содержит -1. Программа контролирует выбор за счет условия
cbSign.ItemIndex<0
при проверке операндов, а также в операторе case:
case cbsign.itemindex of
Если вы ввели строки cbSign. items в нужной последовательности, индекс выбранной строки будет соответствовать номеру операции (0 - +, 1- -, 2 - * и 3 - /), и над операндами будет выполнено требуемое действие.
Метки и операторы перехода
Можно теоретически показать, что рассмотренных операторов вполне достаточно для написания программ любой сложности. В этом отношении наличие в языке операторов перехода кажется излишним. Более того, современная технология структурного программирования основана на принципе “программировать без GOTO”: считается, что злоупотребление операторами перехода затрудняет понимание программы, делает ее запутанной и сложной в отладке. Тем не менее в некоторых случаях использование операторов перехода может упростить программу.
Оператор перехода имеет вид:
goto <метка>;
Здесь goto - зарезервированное слово (перейти [на метку]); <метка> - метка.
Метка в Object Pascal - это произвольный идентификатор, позволяющий именовать некоторый оператор программы и таким образом ссылаться на него. В целях совместимости со стандартным языком Паскаль в Object Pascal допускается в качестве меток использование также целых чисел без знака.
Метка располагается непосредственно перед помечаемым оператором и отделяется от него двоеточием. Оператор можно помечать несколькими метками, которые в этом случае отделяются друг от друга двоеточием. Перед тем как появиться в программе, метка должна быть описана. Описание меток состоит из зарезервированного слова label (метка), за которым следует список меток:
Label
loop, Ibl, lb2;
begin
goto Ibl;
 
loop: .........
Ibl:lb2: ......
......
goto lb2;
end;
Действие оператора goto состоит в передаче управления соответствующему меченному оператору.
При использовании меток необходимо руководствоваться следующими правилами:

  • метка, на которую ссылается оператор goto, должна быть описана в разделе описаний, и она обязательно должна встретиться где-нибудь в теле программы;
  • метки, описанные в подпрограмме, локализуются в ней, поэтому передача управления извне подпрограммы на метку внутри нее невозможна.

 

МАССИВЫ


Рассмотренные выше простые типы данных позволяют использовать в программе одиночные объекты - числа, символы, строки и т. п. В Object Pascal могут использоваться также объекты, содержащие множество однотипных элементов. Это массивы - формальное объединение нескольких однотипных объектов (чисел, символов, строк и т. п.), рассматриваемое как единое целое. К необходимости применения массивов мы приходим всякий раз, когда требуется связать и использовать целый ряд родственных величин. Например, результаты многократных замеров температуры воздуха в течение года удобно рассматривать как совокупность вещественных чисел, объединенных в один сложный объект - массив измерений.
При описании массива необходимо указать общее количество входящих в массив элементов и тип этих элементов. Например:
var
а : array [1..10] of Real;
b : array [0..50] of Char;
с : array [-3..4] of String;
Как видим, при описании массива используются зарезервированные слова array и of (массив, из). За словом array в квадратных скобках указывается тип-диапазон, с помощью которого компилятор определяет общее количество элементов массива. Тип-диапазон (подробнее см. в гл. 7) задается левой и правой границами изменения индекса массива, так что массив А состоит из 10 элементов, массив В - из 51, а массив С - из 8 элементов. За словом of указывается тип элементов, образующих массив.
Доступ к каждому элементу массива в программе осуществляется с помощью индекса - целого числа (точнее, выражения порядкового типа, см. гл. 7), служащего своеобразным именем элемента в массиве (если левая граница типа-диапазона равна 1, индекс элемента совпадает с его порядковым номером). При упоминании в программе любого элемента массива сразу за именем массива должен следовать индекс элемента в квадратных скобках, например:
var
a: array [1..10] of Integer;
b: array [0..40] of Char;
c: array [-2..2] of Boolean;
k: Integer;
begin
b[17] := 'F';
c[-2] := a[1] > 2;
for k := 1 to 10 do a[k] := 0;
end;
В правильно составленной программе индекс не должен выходить за пределы, определенные типом-диапазоном. Например, можно использовать элементы а [ 1 ], в[38], с[0], но нельзя а [0 ] илис[38] (определение массивов см. выше). Компилятор Object Pascal может[ Буквальный перевод array - боевой порядок, упорядоченная масса (войск). В компьютерной терминологии array переводится словом массив. ] контролировать использование индексов в программе как на этапе компиляции, так и на этапе прогона программы.
Учебная программа AVERAGE
Для иллюстрации приемов работы с массивами составим программу, которая создает массив случайных целых чисел, подсчитывает их среднее арифметическое, а также определяет и выводит на экран минимальное и максимальное из этих чисел.
procedure TfmExample.bbRunClick(Sender: TObject);
{Программа создает массив из N случайных целых чисел, равномерно распределенных в диапазоне от 0 до MAX_VALUE-1, подсчитывает среднее арифметическое этих чисел, а также минимальное и максимальное из них.} const
N = 1000; // Количество элементов массива
MAX_VALUE = 100+1;// Диапазон значений случайных чисел var
m: array [1..N] of Integer; // Массивчисел
i: Integer;// Индекс массива
max,min: Integer; // Максимальное и минимальное число
sum: Real;// Сумма чисел
begin
// Наполняем массив случайными числами:
for i := 1 to N do
m[i] := Random(MAX_VALUE);
// Задаем начальные значения переменных:
sum : = m [ 1 ] ;
max : = m [ 1 ] ;
min := m[1] ;
// Цикл вычисления суммы всех случайных чисел и поиска
// минимального и максимального:
for i := 2 to N do
begin
sum := sum + m[i];
if m[i] < min then
min := m[i]
else if m[i] > max then
max := m[i] end;
// Вычисляем среднее значение и выводим результат:
IbOutput.Caption := 'Мин = '+IntToStr(min)+' Макс = '+ IntToStr(max)+' Среднее = '+FloatToStr(sum/N) ;
end;
Для создания массива используется встроенная функция Ran-dom(Max), которая возвращает случайное целое число, равномерно распределенное в диапазоне от 0 до мах-1 (мах - параметр обращения).
ПРОЦЕДУРЫ И ФУНКЦИИ
Процедуры и функции (я часто буду использовать их общее название - подпрограммы} представляют собой важный инструмент Object Pascal, позволяющий писать хорошо структурированные программы. В структурированных программах обычно легко прослеживается основной алгоритм, их проще понять любому читате лю, они удобнее в отладке и менее чувствительны к ошибкам программирования. Все эти свойства являются следствием важной особенности подпрограмм, каждая из которых представляет собой во многом самостоятельный фрагмент программы, связанный с основной программой лишь с помощью нескольких параметров. Самостоятельность подпрограмм позволяет локализовать в них все детали программной реализации того или иного алгоритмического действия, и поэтому изменение этих деталей, например, в процессе отладки обычно не приводит к изменениям основной программы.
Многие примеры в этой книге невелики по размерам (не более 30-40 строк), поэтому в таких программах можно обойтись и без подпрограмм. Иное дело - создание крупных программ в сотни, тысячи и десятки тысяч строк. Писать такие программы как нечто единое целое, без расчленения на относительно самостоятельные фрагменты, т. е. без структурирования, просто невозможно. Практически во всех языках программирования имеются средства структурирования. Языки, в которых предусмотрены такие механизмы, называются процедурно-ориентированными. К их числу принадлежит и Object Pascal.
Процедурой в Object Pascal называется особым образом оформленный фрагмент программы, имеющий собственное имя. Упоминание этого имени в тексте программы приводит к активизации процедуры и называется ее вызовом. Сразу после активизации процедуры начинают выполняться входящие в нее операторы, после выполнения последнего из них управление возвращается обратно в . основную программу и выполняются операторы, стоящие непосредственно за оператором вызова процедуры (
Для обмена информацией между основной программой и процедурой используется один или несколько параметров вызова. Как мы увидим дальше, процедуры могут иметь и другой механизм обмена данными с вызывающей программой, так что параметры вызова могут и не использоваться. Если они есть, то они перечисляются в круглых скобках за именем процедуры и вместе с ним образуют оператор вызова процедуры.
Функция отличается от процедуры тем, что результат ее работы возвращается в виде значения этой функции, и, следовательно, вызов функции может использоваться наряду с другими операндами в выражениях.
С примерами процедур и функций мы уже сталкивались - это
Стандартные процедуры Exit, ShowMessage, функции StrToInt, FioatToStr, Random, математические функции и др. Стандартными они называются потому, что созданы одновременно с системой Delphi и являются ее неотъемлемой частью. В Delphi имеется много стандартных процедур и функций. Наличие богатой библиотеки таких программных заготовок существенно облегчает разработку прикладных программ. Однако в большинстве случаев некоторые специфичные для данной прикладной программы действия не находят прямых аналогов в библиотеках Delphi, и тогда программисту приходится разрабатывать свои, нестандартные процедуры и функции.
Нестандартную подпрограмму необходимо описать, чтобы компилятор смог установить связь между оператором вызова и теми действиями, которые предусмотрены в подпрограмме. Описание подпрограммы помещается в разделе описаний (до начала исполняемых операторов).
Учебная программа UPSTRING
Не вдаваясь в дальнейшие подробности, попробуем составить собственную процедуру, чтобы пояснить сказанное. Пусть в этой процедуре преобразуется некоторая символьная строка таким образом, чтобы все строчные буквы заменялись соответствующими прописными. В Object Pascal имеется стандартная функция upcase (см. гл. 6), которая выполняет аналогичные действия над одиночным символом. Наша процедура (назовем ее upString) будет преобразовывать сразу все символы строки, причем сделаем ее пригодной не только для латинских букв, но и для букв русского алфавита[ В Delphi имеется стандартная функция AnsiUpperCase, реализующая те же действия. ].
Разработку программы проведем в два этапа. Сначала сконструируем основную (вызывающую) часть программы. Ее действия очень просты: она должна получить входную строку из компонента edinput, преобразовать ее с помощью процедуры upString в выходную строку и поместить результат в iboutput.Text. Эти действия нетрудно запрограммировать в обработчике bbRunciick:
procedure TfmExample.bbRunClick(Sender: TObject);
procedure UpString(stinp: String; var stOut: String);
{ Эта процедура преобразует все буквы строки stinp в прописные и помещает результат в выходную строку stOut }
begin
stOut := stinp;
end; // UpString var
SI, S2: String;
begin
SI := edinput.Text; // Получаемисходнуюстроку
UpString(SI,S2); // Преобразуемее
IbOutput.Caption := S2; // Выводимрезультат
edinput.Text := '' ;
edinput.SetFocus ;
end ;
В этой программе используется замещение процедуры UpString так называемой “заглушкой”, т. е. процедурой, в которой на самом деле не осуществляется нужных нам действий, а выходная строка просто копирует входную. (Однако эта программа синтаксически абсолютно правильна, и при желании ее можно запустить на счет.) Заглушка понадобилась нам по двум причинам. Во-первых, приведенная программа очень проста, в ней отсутствует детальная реализация процедуры, и это позволяет наглядно проиллюстрировать механизм ее описания. Во-вторых, на ее примере мы знакомимся с универсальным методом конструирования сложных программ, получившим название нисходящее программирование. В соответствии с этим методом создание программы начинается “сверху”, т. е. с разработки самого главного, генерального алгоритма. На верхнем уровне обычно еще неясны детали реализации той или иной части программы, поэтому эти части следует заменить временными заглушками. Желательно, чтобы временный вариант программы был синтаксически правильным, тогда можно его откомпилировать и убедиться в отсутствии в нем синтаксических ошибок. Такой прогон даст определенную уверенность перед разработкой и реализацией алгоритмов нижнего уровня, т. е. перед заменой заглушек реально работающими процедурами. Если реализуемый в заглушке алгоритм достаточно сложен, его вновь структурируют, выделяя главный алгоритм и применяя новые заглушки, и т. д. Процесс продолжается “вниз” до тех пор, пока не будет создан полностью работоспособный вариант программы.
Как видим, описание процедуры начинается зарезервированным словом procedure, за которым следуют имя процедуры и список формальных параметров. Список параметров заключается в круглые скобки и содержит перечень параметров с указанием их типа. Заметим, что перед параметром stout, с помощью которого в вызывающую программу возвращается результат преобразования, стоит зарезервированное слово var. Именно таким способом компилятору указываются те параметры, в которых процедура возвращает вызвавшей ее программе результат своей работы (подробнее см. гл. 10). Зарезервированное слово procedure, имя процедуры и список ее параметров образуют заголовок процедуры. За заголовком следует тело процедуры, содержащее новый раздел описаний (этот раздел пока еще пуст) и раздел исполняемых операторов (оператор stout:= stInp).
Приступим к разработке алгоритма процедуры. Для этого учтем, что в соответствии с принятой в Windows кодировкой символов (так называемой ANSI-кодировкой) символы кириллицы (русского алфавита) располагаются сплошным массивом от “А” до “я”, за исключением “ё” и “Ё”, которые предшествуют “А”. Кроме того, символ “я” имеет внутренний код 255, т. е. максимально возможное значение одного байта (для каждого символа строки выделяется по одному байту).
Вот возможный вариант процедуры:
Procedure UpString(stinp: String; var stOut: String);
{ Эта процедура преобразует все буквы строки stinp в прописные и помещает результат в выходную строку stOut } var
k: Integer;// Параметрцикла
begin
stOut := stinp;
// Циклпобуквенногопреобразования
for k := 1 to Length(stOut) {Length - длинастроки} do
begin
stOut[k] := UpCase(stOut[k]); // Преобразуемлатиницу
if stOut[k] >= 'a' then // Строчная буква кириллицы?
st0ut[k] := // Да: преобразуем ее
Chr(ord('A') + ord(st0ut[k]) - ord('a'));
if stOut[k]='e' then
stOut[k] := 'Ё'; // ПреобразуемёвЁ
end;
end; // UpString
Комментарий к программе
В процедуре вначале с помощью оператора
stOut := stinp;
исходная строка копируется в выходную строку. Затем реализуется циклический перебор всех символов выходной строки для преобразования букв. Для доступа к отдельным символам строки используется замечательное свойство типа данных string, позволяющее рассматривать строку как набор (массив) символов. Первый символ этого набора имеет индекс 1, второй - 2 и т. д. Индекс указывается сразу за именем строки в квадратных скобках. Таким образом, stOut [i] - это г-ный символ строки stOut. Перебор символов реализован в виде счетного цикла от 1 до длины входной строки stOut (эта длина получается с помощью стандартной функции Length), в ходе которого каждый символ сначала преобразуется функцией UpCase (эта функция возвращает прописную латинскую букву для строчной буквы, передаваемой ей в параметре вызова; функция не работает с кириллицей). Затем осуществляется проверка принадлежности буквы к русской строчной (оператор if st0ut[k] >= 'a' then; символ “а” - русская буква) и осуществляется необходимая коррекция ее внутреннего кода. При коррекции используются отмеченные выше свойства непрерывности и монотонности массивов кодов, т. е. за “А” идет “Б”, за “Я” - “а”, за “а” - “б” и т. д. Стандартная функция ord возвращает внутренний код символа, который передается ей в качестве параметра обращения, а функция chr преобразует код в символ. Поскольку буква “ё” стоит особняком, ее преобразование осуществляется отдельным оператором.
Рассмотрим иной способ реализации той же программы - оформим алгоритм преобразования в виде функции:
procedure TfmExample.bbRunClick(Sender: TObject) ;
Function UpString(stinp: String): String;
{ Эта функция преобразует все буквы строки stinp в прописные и помещает результат в выходную строку Result }
var
k: Integer; // Параметрциклаbegin
Result := stinp;
// Циклпобуквенногопреобразования
for k := 1 to Length(Result) do
begin
Result[k] := UpCase(Result[k]);// Преобразуемлатиницу
if Result[k] >= 'a' then // Строчная буква кириллицы?
Result[k] := // Да: преобразуем ее
Chr(ord('A') + ord(Result[k]) - ord('a'));
if Result[k]='e' then
Result[k] := 'Ё'; // ПреобразуемёвЁ
end;
end; // UpString
begin
{ В следующем операторе исходная строка edinput.Text преобразуется и помещается в выходную строку IbOutput.Caption: }
IbOutput.Caption := UpString(edinput.Text);
edinput.Text := '';
edinput.SetFocus ;
end;
Комментарий к программе
При описании функции необходимо за списком используемых для ее вызова параметров указать тип возвращаемого ею результата. Именно поэтому за закрывающей круглой скобкой в заголовке функции стоит двоеточие и тип string. В теле любой функции определена стандартная переменная Result, которая трактуется как результат, возвращаемый функцией.
С помощью оператора
Result := stInp;
мы сначала присвоили результату входную строку, а затем в цикле осуществили перебор символов и их коррекцию. Единственный оператор
IbOutput.Caption := UpString(edInput.Text);
заменил сразу три первых оператора в предыдущей реализации программы.

 

 
На главную | Содержание | < Назад....Вперёд >
С вопросами и предложениями можно обращаться по nicivas@bk.ru. 2013 г. Яндекс.Метрика