Введение
Запись последовательных команд не всегда может быть
эффективным способом достижения поставленной цели. Очень часто в программе
требуется выполнить одну и ту же последовательность действий несколько раз.
Например, требуется вывести в текстовое поле (TMemo) числа от 1 до 100. Что
делать в этом случае? Писать 100 строк кода? Конечно нет, это было бы просто
глупо! Примеров можно привести множество. Причём во многих случаях число
повторений может быть заранее неизвестно - в этом случае записать фиксированный
набор команд просто невозможно.
На помощь придут циклы. Цикл - это специальная
конструкция языка, позволяющая запрограммировать многократное выполнение
определённого блока команд. Каждый "проход" цикла называется
итерацией. В языке Pascal существует три типа циклов
- цикл с параметром (цикл по переменной), цикл с
предусловием и цикл с постусловием. В данном уроке мы
познакомимся с циклом по переменной.
Цикл с параметром
Цикл с параметром (другое его название - цикл по переменной)
позволяет выполнить набор команд фиксированное число раз, т.е. число итераций
должно быть известно до начала выполнения цикла. Особенностью данного цикла
является то, что заводится специальная переменная-счётчик, которая
последовательно проходит указанный диапазон значений. Значение этой переменной
может быть использовано в блоке кода, находящемся в цикле.
Цикл с параметром описывается зарезервированным словом
FOR (англ. "для"). Общий вид конструкции
цикла FOR:
FOR переменная-счётчик := начальное_значение [TO / DOWNTO] конечное_значение DO
{Действия}
Переменная-счётчик - объявленная выше
переменная перечислимого типа (в большинстве случаев - число).
Начальное значение и конечное
значение - границы диапазона, который последовательно "пробежит"
переменная-счётчик. Значения, естественно, того же типа данных, что и
переменная-счётчик.
При этом следует обращать особое внимание на указанные
значения. В зависимости от их соотношения используется либо ключевое слово
TO, либо DOWNTO. Слово TO
используется в том случае, когда конечное значение больше начального, а
DOWNTO - наоборот, т.е. когда цикл пойдёт по убыванию. В случае, если
указанные значения не будут соответствовать ключевому слову, то требуемый
результат не будет достигнут - цикл, вероятно, выполнится всего один раз.
В качестве действий указывается какая-либо команда, либо набор
команд. Если команд несколько, их, как обычно, следует заключать в блок
BEGIN .. END.
Пример №1
Рассмотрим пример, речь о котором шла в начале статьи, только
немного усложним его - будем выводить не только числа от 1 до 100, но и их
квадраты.
Итак, мы заранее знаем, что нам следует выполнить одну и ту же
команду - добавление строки в Memo, 100 раз. Запрограммируем это с помощью цикла
FOR. Для начала следует разместить на форме TMemo (Memo1).
Выполнение команд логичнее всего "повесить" на нажатие кнопки. Для добавления
строк в TMemo следует воспользоваться методом Add его свойства
Lines. Lines - это набор всех строк TMemo, а метод Add позволяет добавить
указанную строку. Перед выполнением цикла содержимое Memo очищается.
procedure TForm1.Button1Click(Sender: TObject);
var i: Integer;
begin
Memo1.Lines.Clear;
for i := 1 to 100 do
Memo1.Lines.Add(IntToStr(i)+': '+IntToStr(Sqr(i)))
end;
![](/images/raznoe/16_01.gif)
Разберём, что здесь происходит: мы заводим переменную
i (Integer, целое число) и указываем её как счётчик для цикла.
Поскольку нам нужно вывести числа от 1 до 100, указываем соответствующий
диапазон. Команда - добавление строки в Memo, содержащей текущее число и его
квадрат. Преобразование типов (в данном случае - чисел в строки) обязательно.
Как это будет работать: сначала переменной i будет присвоено значение 1, после
чего выполнится указанная команда, т.е. в Memo добавится строка "1: 1",
далее i станет равным 2 и снова команда повторится. Так произойдёт 100
раз - в результате в Memo и окажется 100 строк.
Замечание
Одна из часто встречающихся ошибок - использование значения
переменной-счётчика после завершена цикла.
После выполнения цикла значение
переменной-счётчика не определено! В данном случае после завершения
цикла значение i не будет 100, хотя по случайности оно может быть. Если
Вы хотите использовать значение переменной далее, присвойте ей это значение
явным образом.
Вложенные циклы
Что такое вложенные циклы, понятно из названия - это циклы,
которые вложены в другие циклы. К примеру, если один цикл позволяет вывести лишь
ряд чисел, то 2 цикла, один из которых вложен в другой, позволят вывести целую
таблицу значений.
Никаких специальных конструкций для вложенных циклов нет. Всё
работает точно также. Переменные-счётчики циклов, как правило, называют буквами
I, J, K, хотя название, конечно, может быть любое.
Пример №2
Простейший пример применения вложенного цикла - вывод таблицы
умножения. Для начала продумаем алгоритм: для вывода таблицы для одного
конкретного числа (например, для 5), нужно создать цикл, который пройдёт
значения от 1 до 9 и выведет произведение числа 5 на каждое из этих чисел. А
чтобы вывести таблицу для самих чисел от 1 до 9, нужен ещё один такой же цикл.
procedure TForm1.Button1Click(Sender: TObject);
var i,j: Integer;
begin
Memo1.Lines.Clear;
for i := 1 to 9 do
for j := 1 to 9 do
Memo1.Lines.Add(IntToStr(i)+' x '+IntToStr(j)+' = '+IntToStr(i*j))
end;
![](/images/raznoe/16_02.gif)
Прерывание и продолжение цикла
Примечание: то, о чём пойдёт речь далее,
применимо не только к циклу по переменной, но и к циклам с пред- и постусловием.
Не всегда выполнение фиксированного числа итераций приводит к
нужному результату. Иногда в процессе выполнения могут возникнуть ситуации,
когда цикл логично было бы завершить, не выполняя его до конца, т.е. нужно
просто исключить все дальнейшие итерации. Такая возможность существует - для
этого необходимо вызвать команду BREAK.
Данная команда завершает цикл, который выполняется в данный момент, и продолжает
выполнение программы. При этом текущая итерация не выполняется до конца -
прерывание происходит именно в той строке, где указана команда Break.
Замечание: если цикл, выполнение которого прерывается командой
Break, вложен в другой цикл, то "внешний" цикл продолжит своё
выполнение, т.е. команда Break останавливает только один цикл, а не все
имеющиеся.
Завершение цикла - экстренный метод. Иногда же нужно просто пропустить текущую
итерацию и перейти к следующей. Вручную это можно сделать, заключив все команды
в блок условного оператора, однако такой способен неудобен и только загромождает
код. Именно поэтому существует команда продолжения цикла и называется она
совершенно логично - CONTINUE. Эта
команда "заставляет" цикл тут же перейти к следующей интерации, не продолжая
выполнение текущей.
Пример №3
Данный пример призван продемонстрировать применение команды
Break.
Задача. Определить, есть ли среди букв английского алфавита (A
- Z, в верхнем регистре) такие символы, коды которых обладают следующим
свойством: квадрат кода символа больше числа 5000. Если такие символы
существуют, указать первый из них согласно алфавитному порядку.
Во-первых, следует определиться с циклом. Смвольный тип (Char)
- перечислимый, значит его можно использовать для переменной-счётчика цикла
For. Во-вторых, для определения кода символа служит функция Ord().
В-третьих, нам не обязательно просматривать абсолютно все символы - если будет
найден хотя бы один, значит требуемое условие выполнено и этот символ мы должны
вывести как результат работы. Просматривать остальные символы не требуется.
Опишем цикл, который последовательно пройдёт все символы от A
до Z. Коды символов упорядочены согласно следованию соответстующих букв в
алфавите, поэтому "пробег" произойдёт точно по алфавиту, для этого в коде не
требуется дополнительно что-либо писать. Код будет приблизительно таким:
procedure TForm1.Button1Click(Sender: TObject);
var c: Char;
begin
for c := 'A' to 'Z' do
if Sqr(Ord(c)) > 5000 then
begin
ShowMessage('Символ: '+c+' (код: '+IntToStr(Ord(c))+', квадрат: '+IntToStr(Sqr(Ord(c)))+')');
Break
end
end;
Как сработает этот цикл: сначала будет взят символ "A",
будет проверен код этого символа, после этого будет взят символ "B",
проверен его код и т.д. Когда условие выполнится (это будет на символе "G"),
будет выведено сообщение с результатом, но после этого цикл не продолжится - он
тут же завершится. Мы уже нашли искомый символ, у нас есть результат, - зачем же
тратить время на проверку остальных символов? В данном случае задержка по
времени будет практически незаметна, ведь в алфавите всего 26 символов. Но что
будет, если обрабатывать несколько тысяч записей?
Цикл с шагом
Цикл с шагом позволяет указать шаг прохода счётчиком
указанного диапазона. Например, в случае, когда требуется пройти все числа от 0
до 1000, которые делятся на 10, шагом будет число 10, а границами диапазона - 0
и 1000. Цикл при этом будет выполняться таким образом: сначала будет взято
первое число и выполнена соответствующая итерация, затем к счётчику будет
прибавлена не 1, как обычно, а шаг, т.е. 10 - следующая итерация выполнится при
значении счётчика, равном 10, далее - 20, 30 и т.д.
Однако есть одна проблема - в Pascal возможности задавать шаг... нет! Да, так уж
сложилось, что этой конструкции не предусмотрено. В некоторых языках
программирования она есть (например, в Basic), в некоторых - нет.
Однако не составляет труда написать небольшую надстройку над
обычным циклом, которая позволит это сделать. Этот пример также продемонстирует
использование команды Continue.
Всё просто - нам достаточно проверить, отстаёт ли текущее
значение счётчика на целое число шагов от начального значения и, если да, то
выполнить текущую итерацию, а если нет - продолжить цикл.
procedure TForm1.Button1Click(Sender: TObject);
var i,First,Last,Step: Integer;
begin
First:=3;
Last:=100;
Step:=10;
Memo1.Lines.Clear;
for i := First to Last do
if ((i - First) mod Step) <> 0 then
Continue
else
Memo1.Lines.Add(IntToStr(i))
end;
Для тех, кто забыл: оператор mod выполняет
деление с остатком. Разберёмся, как работает данный цикл: переменная-счётчик
проходит значения указанного диапазона (в примере - от 3 до 100). Для проверки,
является ли итерация "попадающей" под шаг, выполняется проверка, делится ли
пройденное число единиц нацело на указанный шаг. В данном примере после 3
"попадание" будет на числе 13, т.к. 13 - 3 = 10 = Шаг * 1. Далее - 23,
33 и т.д. При этом первое значение диапазона всегда будет попадать в шаг, какое
бы оно ни было, а последнее - не всегда (в данном случае 100 не попадёт).
Блок команд для выполнения в цикле в данном случае указывается
после else.
Заключение
Сегодня мы познакомились с циклами, определили, для чего они
нужны, а также познакомились с циклом по переменной - каким образом этот цикл
записывается и как работает. Помимо этого мы разобрались, как организовать цикл
с шагом, и как применять команды остановки и продолжения цикла.
Автор: © Ерёмин А.А., 2007
|