Цикл

Четыре вида циклов: for / while / repeat / for-in

Сначала изучите приведенные ниже примеры. Измените кодовый файл из предыдущего урока mydemo.dpr и замените расширение на pas, получится mydemo.pas. Это стандартное расширение для исходных файлов Pascal. Затем скачайте редактор кода с подсветкой синтаксиса, например Notepad++, он сделает код гораздо читаемее.

Ниже приведён полный рабочий пример с комментариями к каждой строке кода. После примера мы последовательно разберем каждый оператор.

// 2.8 Операторы цикла: for, while, repeat, for..in
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
// Директивы компилятора FPC: включить объектно-ориентированный режим, длинные строки, отключить автоматический подсчет ссылок строк
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
// Платформа Windows: указать программу как консольное приложение (без графического окна)
{$R+} // Включить проверку границ массива, очень полезно для отладки ошибок индексации
var
  MyArray: array [0..9] of Integer; // Целочисленный массив из 10 элементов, индексы от 0 до 9
  I: Integer; // Счетчик цикла
begin
// 1. Прямой цикл for: инициализируем массив квадратами чисел от 0 до 9
for I := 0 to 9 do
    MyArray[I] := I * I;

// 2. Базовый цикл for для обхода индексов массива и вывода квадратов
for I := 0 to 9 do
    WriteLn('Квадрат равен ', MyArray[I]);

// 3. Функции Low/High автоматически получают границы массива, не нужно жестко прописывать 0 и 9, лучшая масштабируемость
for I := Low(MyArray) to High(MyArray) do
    WriteLn('Квадрат равен ', MyArray[I]);

// 4. Цикл while: сначала проверяем условие, тело выполняется только при истинном условии
  I := 0;
while I < 10 do
begin
    WriteLn('Квадрат равен ', MyArray[I]);
    I := I + 1; // Три эквивалентные записи: I+=1 / Inc(I)
end;

// 5. Цикл repeat-until: сначала выполняем тело один раз, условие выхода проверяем в конце
  I := 0;
repeat
    WriteLn('Квадрат равен ', MyArray[I]);
    Inc(I); // Увеличить счетчик на единицу
until I = 10;

// 6. Обход for-in: напрямую считываем значения элементов без работы с индексами
for I in MyArray do
    WriteLn('Квадрат равен ', I);
end.Code language: PHP (php)

Ниже код без всех комментариев

{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$R+}

var
  MyArray: array [0..9] of Integer;
  I: Integer;

begin

for I := 0 to 9 do
    MyArray[I] := I * I;

for I := 0 to 9 do
    WriteLn('Квадрат равен ', MyArray[I]);

for I := Low(MyArray) to High(MyArray) do
    WriteLn('Квадрат равен ', MyArray[I]);

  I := 0;
while I < 10 do
begin
    WriteLn('Квадрат равен ', MyArray[I]);
    I := I + 1;
end;

  I := 0;
repeat
    WriteLn('Квадрат равен ', MyArray[I]);
    Inc(I);
until I = 10;

for I in MyArray do
    WriteLn('Квадрат равен ', I);

end.Code language: PHP (php)

Далее мы по шагам разберем код каждого цикла

Цикл for

Присвоение значений элементам массива с помощью цикла for

{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$R+}

var
  MyArray: array [0..9] of Integer;
  I: Integer;

begin

for I := 0 to 9 do
    MyArray[I] := I * I;

end.Code language: PHP (php)

Этот код разделен на три части: сверху директивы препроцессора, блок var для объявления переменных (один массив и одна целая переменная), основной блок выполнения между begin и end., где расположен цикл for, последовательно присваивающий значения от 0 до 9 переменной I и заполняющий массив по индексам.

Мы заполняем десять элементов массива от MyArray[0] до MyArray[9]. Звездочка * — оператор умножения.

MyArray[0] := 0 * 0;

MyArray[1] := 1 * 1;

MyArray[9] := 9 * 9;

Далее под первым циклом for добавим еще один цикл для чтения каждого сохраненного элемента массива.

После компиляции и запуска все значения выведутся в консоль

Все выводимые числа — квадраты чисел от 0 до 9, что совпадает с нашими ожиданиями.

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

Функция Low(ИмяМассива) возвращает минимальный индекс массива

  • Low(Тип/Переменная): получить минимальное значение / нижнюю границу для порядковых типов, массивов, множеств
  • High(Тип/Переменная): получить максимальное значение / верхнюю границу для порядковых типов, массивов, множеств

Циклы while и repeat

Внутри тела цикла while, обрамленного begin end;, переменная I увеличивается на единицу в конце блока. После инкремента поток возвращается к строке while I < 10 do для повторной проверки условия. Если условие истинно, тело выполняется снова, I опять увеличивается, проверка повторяется. Цикл завершается, когда I < 10 станет ложным, то есть при I равном 10.

Основные различия while и repeat-until

  1. Противоположная логика проверки условия
  • while Условие do: условие истинно — продолжаем цикл; условие ложно — выходим
  • repeat ... until Условие: условие истинно — выходим; условие ложно — продолжаем цикл
  1. Разное гарантированное число запусков тела цикла
  • while: если начальное условие ложно, тело цикла не выполнится ни разу
  • repeat-until: независимо от условия тело цикла обязательно выполнится минимум один раз

Если вы изучали языки C, C++, Java, то легко разберетесь: repeat-until полностью повторяет поведение do-while. Сначала выполняем тело один раз, затем проверяем условие после until; если оно ложное — повторяем цикл.

Для repeat-until блоки begin и end не нужны, конструкция repeat … until сама является полным кодовым блоком. Можно добавить begin end вручную, но это не рекомендуется.

Дословный перевод repeat-until — «повторять … до тех пор, пока», назначение конструкции понятно по названию.


При обходе значения из массива MyArray последовательно присваиваются переменной I, которую можно напрямую использовать внутри цикла. Не нужно вручную увеличивать индекс, индексы вообще не требуются, пока не закончится обход всех элементов.

Описание стандартного цикла for (for I := ... to/downto)

  1. Аналог цикла for из языка C, но с более строгими ограничениями: работает только с непрерывными порядковыми значениями (целые числа, перечислимые типы);
  2. Поддерживает обратный обход через downto: for I := 9 downto 0 do;
  3. Границы Low(xx) / High(xx) вычисляются всего один раз при запуске цикла, высокая скорость выполнения;
  4. После нормального завершения цикла значение переменной I не определено, компилятор выдаст предупреждение. При досрочном выходе через Break или Exit I сохранит текущее число.

Обход for-in (современный стиль foreach)

Позволяет обходить четыре типа данных без ручной работы с индексами:

  1. Массивы: прямое считывание значения каждого элемента (показано в предыдущих примерах)
  2. Перечислимые типы
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
{$R+}

type TAnimalKind = (Duck,Cat,Dog);

var AK:TAnimalKind;
begin
  for AK in TAnimalKind do 
    WriteLn(AK);
end.Code language: PHP (php)
  1. Типы множеств
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}

type
  // Определить перечислимый тип
  TAnimalKind = (Duck, Cat, Dog);
  // Определить тип множества на основе перечисления
  TAnimals = set of TAnimalKind;

var
  Animals: TAnimals;
  AK: TAnimalKind;
begin
  // Присвоить множеству два значения перечисления: Duck и Cat
  Animals := [Duck, Cat];

  // Обойти все существующие элементы множества через for-in
  for AK in Animals do
  begin
    WriteLn('Найдено животное: ', AK);
  end;
end.Code language: PHP (php)
  1. Обобщенные списки (рассматриваем в последующих главах)
{$ifdef FPC} {$mode objfpc}{$H+}{$J-} {$endif}
{$ifdef MSWINDOWS} {$apptype CONSOLE} {$endif}
uses
  SysUtils, Generics.Collections; // Подключить модуль обобщенных контейнеров

type
  TMyClass = class  // Пользовательский класс для хранения числа и его квадрата
    I, Square: Integer;
  end;
  // Создать экземпляр обобщенного списка объектов с автоуправлением жизненного цикла
  TMyClassList = {$ifdef FPC}specialize{$endif} TObjectList&lt;TMyClass&gt;;
var
  List: TMyClassList;
  C: TMyClass;
  I: Integer;
begin
  List := TMyClassList.Create(true); // true: автоматически освобождать внутренние объекты при уничтожении списка
try
  // Создавать объекты в цикле и добавлять в список
for I := 0 to 9 do
begin
      C := TMyClass.Create;
      C.I := I;
      C.Square := I * I;
      List.Add(C);
end;
  // Обойти каждый пользовательский объект списка напрямую через for-in
for C in List do
      WriteLn('Квадрат числа ', C.I, ' равен ', C.Square);
finally
    FreeAndNil(List); // Безопасно освободить список, предотвратить утечку памяти
end;
end.
Code language: HTML, XML (xml)

Примечание: данный пример использует классы и обобщения. Начинающие могут временно пропустить этот фрагмент, детальный разбор будет в главе по объектно-ориентированному программированию.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *