5.4.3. Операторы повторений

В языке 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 (см. ниже п. 5.4.5).