5.4.3. Операторы повторений
В языке Object Pascal имеются три различных оператора, с помощью которых можно запрограммировать повторяющиеся фрагменты программ.
Счетный оператор цикла FOR имеет такую структуру:
for <параметр цикла> := <нач_знач> to <кон знач> do <оператор>;
Здесь for, to, do - зарезервированные слова (для, до, выполнить);
<параметр_цикла> - переменная типа Integer (точнее, любого по-, рядкового типа, см. гл. 7); <нач_знач> - начальное значение - выражение того же типа; <кон_знач> - конечное значение - выражение того же типа; <оператор> - произвольный оператор Object Pascal.
При выполнении оператора 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 (см. ниже п. 5.4.5).