Циклюем циклы в Delphi

Эх, раз, ещё раз, Ещё много-много раз!

Цыганская песня о циклах

Терпенье и труд всё перетрут.

Пословица

Очень часто в программах встречаются ситуации, когда одни и те же дей­ствия нужно повторить многократно. Для таких случаев в языке Delphiприпасены аж три оператора циклов - for, whileи repeat.

Примеры циклов мы можем найти и в повседневной жизни: вре­мена года (циклически сменяют друг друга весна - лето - осень - зима), время суток (утро - день - вечер - ночь), фазы Луны, враще­ние планет вокруг Солнца и Солнечной системы вокруг центра Га­лактики, спортивные состязания, учебный год, режим дня, дыхание и кровообращение, часы, биоритмы активности человека - можно даже утверждать, что уникальны именно неповторяющиеся собы­тия, а не циклические.

 

Оператор FOR

Цикл forвстречается в программах чаще других. Его используют, когда число повторений оператора заранее известно.

 

Цикл forзаписывается в одной из форм:


forпеременная:= начальное значение to конечное значение doоператор;
forпеременная:= начальное значение downtoконечное значение doоператор;

 

Оператор (или составной оператор) называется телом цикла. Число по­вторений (они также называются итерациями) определяется переменной (управляющей переменной, счётчиком цикла, параметром цикла), которая автоматически увеличивается или уменьшается при каждом выполнении тела цикла.

 

Переменная цикла - это локальная переменная порядкового типа (обыч­но целого). Она не должна изменяться в теле цикла (да вы и не сможете этого сделать - Delphiне позволит!), но её значение может использоваться в выражениях внутри цикла.

 

Первая форма действует так:

1.Переменной цикла присваивается начальное значение.

2.Текущее значение переменной цикла сравнивается с её конечным значением. Если оно меньше или равно конечному значению, то выполняется тело цикла - оператор(ы). Если больше, то выполнение цикла заканчивается и управление переходит к следующему за структурой forоператору.

3.Если цикл не завершён в п.2, то значение переменной цикла увели­чивается на 1 и цикл возвращается к п.2.

Понятно, что выполнение цикла forрано или поздно закончится. Более то­го, он может вообще не выполняться ни разу, если начальное значение сразу больше конечного, либо будет выполнен только 1 раз, если началь­ное значение равно конечному.

Важно помнить, что после завершения цикла значение переменной цикла не определено, то есть её нельзя использовать в выражениях!

Вторая форма действует аналогично, за исключением того, что в п.3 зна­чение переменной цикла уменьшается на 1. Оператор forс downtoне бу­дет выполнен ни разу, если начальное значение переменной цикла мень­ше конечного.

Рассмотрим простой цикл, считающий до пяти:


procedure 5; 
var i: integer; 
begin 
for i:= 1 to 5 do
//^ Заголовок цикла
print(inttostr(i)
); //^ Тело цикла
end;
 

 

Здесь i- переменная цикла (их обычно именуют буквами i, j, к, l, m, n).

Начальное значение переменной цикла равно 1, конечное 5.

Таким обра­зом, цикл будет выполнен 5 раз, при этом на экране будут напечатаны числа 1 2 3 4 5

Циклюем циклы в Delph

Оператор FOR... IN

В последних версиях Delphiпоявилась новая разновидность оператора цикла For. Оператор For... inперебирает все элементы коллекции - это могут быть символы строки, элементы массивов и записей. 

for переменная in коллекция do оператор;

 

В языке C# подобный оператор называется foreach.

 

Переменная цикла должна быть объявлена в том же блоке, что и оператор цикла, а её тип должен быть совместим с типом элемен­тов в коллекции.

Изменять значение переменной цикла внутри цикла нельзя!

 

Установите на форме текстовое поле Edit1, щёлкните по кнопке Button1 и напишите код в методе Button1Click:


procedure TForm2.Button1Click(Sender: TObject); var
s: string; ch: char; begin
s:= Edit1.Text; for ch in s do
ListBox1.Items.Add(ch);
end;

Здесь мы считываем строку, которую ввёл пользователь в текстовое поле, в цикле for .inперебираем все символы этой строки и добавляем их в спи­сок

Циклюем циклы в Delphi

 

 

 И для этого нам даже не нужно знать длину строки - оператор for...inуме­ет работать самостоятельно!

 

Очень часто в программах приходится перебирать и элементы массива. Дополним нашу программу целочисленным массивом arr, в который по­местим восемь первых простых чисел:


var 
Form2: TForm2; 
arr: array[1..8] of integer = (2,3, 5, 7, 11, 13, 17, 19); 
implementation 
{$R *.dfm} 
procedure TForm2.Button1Click(Sender:
TObject);
var 
s: string; 
ch: char; 
i: integer; 
begin 
s:= Editl.Text; 
if s <> 'Editl' then 
for ch in s do 
ListBoxl.Items.Add(ch) 
else 
for i in arr do 
end;

В метод Button1Clickдобавим проверку строки в текстовом поле. Если пользователь не ввёл строку, то мы печатаем элементы массива (Рис. У8.3), в противном случае - строку.

delphi

Оператор WHILE

Любовь - кольцо, а у кольца Начала нет и нет конца

Песня о зацикливании

Цикл while называется также циклом с предусловием и имеет следую­щий вид:

while выражение do оператор;

Выражение должно быть логического типа (boolean) и называется также условием выполнения цикла.

 

Работает он так:

1. Вычисляется логическое выражение.

2. Если оно ложно (значение равно FALSE), то выполнение цикла за­канчивается.

3. Если оно истинно (значение равно TRUE), то выполняется оператор и управление передаётся в п.1.

 

Поскольку условие проверяется до выполнения тела цикла, то операторы могут быть вообще не выполнены ни одного раза - если выражение с са­мого начала ложно.

 

Как мы видим, цикл заканчивается, когда условие станет ложным. А по­чему изменяется значение выражения? - Да потому, что изменились зна­чения переменных, входящих в это условие. И это может произойти только в теле цикла. Отсюда грустный вывод: цикл whileможет вообще никогда не закончиться, и программа зациклится навечно, что очень часто и бы­вает!

 

Пример 1. Найдём все числа Фибоначчи, которые не больше некоторого заданного числа n.

 

Результаты вычислений мы будем выводить в список lstProtocol задавать нужное нам число от 2 до 99999 в компоненте speNUM а понуждать программу к этому - с помощью кнопки sbtGo:

delphi

Вводим в однострочныйй редактор число и попадаем в процедуру обработки:


procedure TfrmMain.sbtGoClick(Sender: TObject);
var n: integer;
begin
n:= speNum.Value; fibo(n); end;
Здесь вызывается процедура, которая и проводит нужные нам расчёты:
//РЕШИТЬ ЗАДАЧУ procedure fibo(n: integer);
var f,f1,f2: integer; begin f:=0; f1:=1; f2:=1;
frmMain.lstProtokol.Clear; while f2 <= n do begin 
frmMain.lstProtokol.Items.add(inttostr(f2)); f2:= f1 + f; f:=f1; f1:=f2;
end;
end;

Чтобы понять, как действует в этом примере оператор while, уде­лим немного времени числам Фибоначчи (а эти числа очень инте­ресны!). Нетрудно догадаться, что их открыл Фибоначчи (он же Леонардо Пизанский), средневековый математик, внимательно наблюдавший за размножением кроликов.

Первые два числа равняются 1:

f1:=1;
f2:=1;

а все последующие равны сумме двух предыдущих, то есть третье число 1 + 1 = 2, четвёртое 1 + 2= 3, пятое 2 + 3 = 5 и так далее, до бесконечности:


f2:= f1+f;
f:=f1;
f1:=f2;

 

А цикл while f2 <= n do только проверяет, не достигло ли очередное число Фибоначчи заданного нами предела. 

Исходный код программы находится в папке fibonacci.

 

 

Оператор REPEAT

Цикл repeatназывается также циклом с постусловием и имеет следую­щий вид:


repeat
оператор untilвыражение;

Выражение (условие выполнения цикла) должно быть логического типа.

Оператор repeatдействует почти так же, как while, но с одним важным отличием: условие продолжение цикла проверяется после выполнения оператора. Это значит, что цикл обязательно будет исполнен по крайней мере 1 раз, даже если логическое выражение истинно с самого начала.

По записи цикла видно, что зарезервированные слова repeatи untilигра­ют роль операторных скобок, поэтому в теле цикла можно просто пере­числять операторы - использовать составной оператор нет необходимости (но это и не запрещено). По этой же причине перед untilточку с запятой разрешается не ставить.

Работает оператор repeat так:

  1. Выполняется оператор в теле цикла.
  2. Вычисляется логическое выражение. Если оно ложно (значение рав­но FALSE), то управление передаётся в п.1. Если оно истинно (значе­ние равно TRUE), то выполнение цикла заканчивается.

Теперь мы можем найти и второе различие циклов whileи repeat: первый заканчивается, когда условие не выполняется (значение выражения ста­новится равным FALSE), второй - когда условие выполняется (значение выражения становится равным TRUE).

 

Пример 2. Найдём все числа Фибоначчи, которые не больше некоторого заданного числа n.

 

Внешне («интерфейсно») программа ничем не отличается от первого при­мера, но теперь мы найдём числа Фибоначчи с помощью оператора repeat:

 


//РЕШИТЬ ЗАДАЧУ
procedure fibo(n: integer); var f,f1,f2: integer; begin f:=0; f1:=1; f2:=1;
frmMain.lstProtokol.Clear;
repeat
frmMain.lstProtokol.Items.add(inttostr(f2)); f2:= f1 + f; f:=f1; f1:=f2; until f2 >= n;
end;

 

Легко заметить, что нам пришлось изменить только небольшую часть ко­да: заменить один оператор цикла другим и «инвертировать» условие продолжения цикла. Как говорится, лёгким движением руки whileпре­вращается в элегантный repeat!

 

Исходный код программы находится в папке fibonacci2.

 

Вложенные циклы

Довольно часто внутри одного цикла нужно выполнить другой цикл, например, при поиске нужного элемента в двумерном массиве. Хорошим примером вложенных циклов может быть русская матрёшка: каждая меньшая по размерам кукла целиком посещается внутри большей. При из­вестном мастерстве удаётся создать глубоко вложенные матрёшки:


for . . .     //начало  первого цикла
begin
for . . . //начало второго цикла begin
for . . . //начало третьего цикла
begin
end;                      //конец    третьего цикла
end;                       //конец     второго цикла

 

Как и всегда, отступами выделяйте отдельные циклы! Вложенных циклов может быть любое количество и это могут быть не только циклы for, но и whileи repeatв любых сочетаниях.

Пример. В своё время мне пришлось на городской олимпиаде по матема­тике решать такую задачу: Подсчитать, сколько раз пятёрка входит в представление чисел от 1 до 1000 в виде произведения простых чисел: 2, 3, 5, 7, 11,. (например, 24 = 2 * 2 * 2 * 3; 25 = 5 * 5). Мы не на олимпиаде, по­этому пусть задачу решает компьютер, а мы составим для него простень­кую программу:


//РЕШИТЬ ЗАДАЧУ
procedure TfrmMain.sbtGoClick(Sender: TObject);
var i, n, n5: integer; begin n5:=0;
for i:= 1 to 1000 do begin //проверяем все заданные числа n:= i;
while TRUE do begin
if n mod 5 = 0 then begin n:= n div 5; inc(n5); end
else break; end; end;
frmMain.lstProtokol.Items.add(inttostr(n5));
end;

Здесь мы легко найдём цикл for, в котором перебираются все заданные числа, и вложенный в него бесконечный цикл while, который и подсчиты­вает их делители. Если число делится нацело на 5, то увеличиваем счёт­чик на 1, иначе переходим к проверке следующего числа. Олимпиадный «подвох» этой задачи заключается в том, что полученное после деления на 5 число опять может быть кратно 5, то есть его опять нужно проверить. Если это обстоятельство не учесть, то число пятёрок можно было бы под­считать мгновенно: 1000 : 5 = 200. Таким образом, в первой тысяче чисел ровно 200 делятся на 5. Ещё 40 делятся на 25 (5*5), 8 - на 125 (5*5*5) и од­но - на 625 (5*5*5*5). Зная ответ, и задачу легко решить, а я на олимпиаде намаялся

 delphi

dle

Помоги проекту! Расскажи друзьям об этом сайте: