Обучающий курс. 16. Циклы - общее понятие; цикл с параметромИсточник: delphi Еремин Андрей
ВведениеЗапись последовательных команд не всегда может быть эффективным способом достижения поставленной цели. Очень часто в программе требуется выполнить одну и ту же последовательность действий несколько раз. Например, требуется вывести в текстовое поле (TMemo) числа от 1 до 100. Что делать в этом случае? Писать 100 строк кода? Конечно нет, это было бы просто глупо! Примеров можно привести множество. Причём во многих случаях число повторений может быть заранее неизвестно - в этом случае записать фиксированный набор команд просто невозможно. Цикл с параметромЦикл с параметром (другое его название - цикл по переменной) позволяет выполнить набор команд фиксированное число раз, т.е. число итераций должно быть известно до начала выполнения цикла. Особенностью данного цикла является то, что заводится специальная переменная-счётчик, которая последовательно проходит указанный диапазон значений. Значение этой переменной может быть использовано в блоке кода, находящемся в цикле. Цикл с параметром описывается зарезервированным словом 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 очищается.
Разберём, что здесь происходит: мы заводим переменную 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, нужен ещё один такой же цикл.
Прерывание и продолжение циклаПримечание: то, о чём пойдёт речь далее, применимо не только к циклу по переменной, но и к циклам с пред- и постусловием. Не всегда выполнение фиксированного числа итераций приводит к нужному результату. Иногда в процессе выполнения могут возникнуть ситуации, когда цикл логично было бы завершить, не выполняя его до конца, т.е. нужно просто исключить все дальнейшие итерации. Такая возможность существует - для этого необходимо вызвать команду BREAK. Данная команда завершает цикл, который выполняется в данный момент, и продолжает выполнение программы. При этом текущая итерация не выполняется до конца - прерывание происходит именно в той строке, где указана команда Break. Пример №3Данный пример призван продемонстрировать применение команды Break. Во-первых, следует определиться с циклом. Смвольный тип (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 и т.д. Однако не составляет труда написать небольшую надстройку над обычным циклом, которая позволит это сделать. Этот пример также продемонстирует использование команды 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. ЗаключениеСегодня мы познакомились с циклами, определили, для чего они нужны, а также познакомились с циклом по переменной - каким образом этот цикл записывается и как работает. Помимо этого мы разобрались, как организовать цикл с шагом, и как применять команды остановки и продолжения цикла. В следующий раз речь пойдёт о других циклах - циклах с постусловием и циклах с предусловием. |