Цикли

ред.

Іноді в алгоритмі необхідно повернутися назад і знову виконати вже пройдену послідовність дій. Таке повторення зветься циклом. Так, у вигляді циклу можна записати, скажімо, алгоритм переміщень учня школи протягом тижня (дім - дорога - школа - дорога - дім - повторити). Найпростіше це можна реалізувати мітками, просто вказавши перехід на мітку, що знаходиться раніше команди goto; але, як ми вже казали, користуватися мітками не рекомендовано, тому в Паскалі є оператори циклів while-do, repeat-until та for-do.

Цикл while-do

ред.

Конструкція

while умова do дія

(англ. while - "доки", do - "виконати") або цикл з передумовою перевіряє умову, і якщо вона виконується, виконує дію, після чого знову перевіряє умову і т.д. Таким чином, фрагмент коду

i:=1;
while i<5 do begin
  writeln(i,'. Привіт!');
  i:=i+1
end;

виведе 4 пронумеровані рядки зі словом "Привіт!":

1. Привіт!

2. Привіт!

3. Привіт!

4. Привіт!

П'ятий рядок не буде виведено, оскільки при i=5 не виконується умова i<5. Якби перед циклом значення 'i' було встановлено в 10, то команди всередині циклу (тіло циклу) не були б виконані взагалі жодного разу.

Цикл repeat-until

ред.

Конструкція

repeat дії until умова

(англ. repeat - "повторювати", until - "доки не") або цикл з післяумовою спершу виконує всі дії між repeat та until, після чого перевіряє умову. Якщо вона виконується, цикл завершується. Ось фрагмент програми, аналогічний попередньому:

i:=1;
repeat
  writeln(i,'. Привіт!');
  i:=i+1
until i>=5;

Зверніть увагу на відмінності від циклу while-do:

  • дій між repeat та until може бути декілька, тому нема потреби в операторних дужках begin-end; зверніть увагу на те, як зроблені відступи в цьому фрагменті коду;
  • умова наприкінці є оберненою відносно умови в while-do, в першому випадку цикл продовжується, якщо умова істинна, в другому - завершується!
  • якщо встановити заздалегідь істинне значення умови виходу, наприклад i:=10, то тіло циклу все одно буде виконано хоча б один раз.

Цикл for-do

ред.

Конструкція

for змінна:=початок to кінець do дія

(англ. for - "для", to - "до", do - "виконати") буде виконана рівно стільки разів, скільки треба, щоб змінити (додаючи по 1) значення змінної - лічильника від початкового значення до кінцевого. Так, попередня програма може бути записана в формі

for i:=1 to 4 do writeln(i,'. Привіт!');

Основні відмінності циклу for-do від попередніх:

  • дія після do одна, тому якщо треба виконати кілька дій в циклі, слід використовувати операторні дужки begin-end;
  • кількість повторень циклу фіксована; більше того - кількість повторень обчислюється до початку циклу, і її неможливо змінити всередині циклу. Наприклад,
s:=3;
for i:=1 to s*s do begin
  s:=5;
  writeln(i)
end;

виведе числа від 1 до 9, хоча значення s при цьому зміниться!

  • немає потреби у встановленні початкових значень до циклу, як і в "ручній" зміні параметра цикла - все буде виконано автоматично;
  • якщо кінцеве значення менше за початкове, цикл не буде виконано жодного разу;
  • лічильник (в прикладі i) має бути зліченого (цілого) типу і його не можна змінювати всередині циклу.

Загальні прийоми роботи із циклами

ред.
  • Треба бути обережним при написанні циклів: якщо всередині циклу не відбувається дій, які б змінювали істинність умови, цикл буде повторюватися нескінченно, доки програма не буде перервана системними засобами ("зависне"). Крім того, варто особливо уважно придивитися до першого і останнього проходу циклу, помилки частіше виникають в них. З огляду на це, якщо кількість проходжень циклу відома завчасно, слід використовувати цикл for-do: в ньому неможливе зациклювання, а перше і останнє значення лічильника одразу виписані.

Наприклад, якщо щось відбувається при значеннях змінної 2, 1, 0.5 і 0.25, то варто вручну перевірити, що відбудеться при значеннях 2 і 0.25, і чи дійсно в вашій програмі будуть такі значення, а не 4 і 0.125, бо зайвий прохід циклу - поширена помилка

  • Треба бути обережним при використанні циклу repeat-until: тіло циклу в ньому обов'язково буде хоча б один раз виконане, що при некоректних початкових умовах може бути небажаним. Завжди продумуйте в цьому циклі, що станеться, якщо умови некоректні; розгляньте можливість переробки програми в інший цикл.
  • Лічильником зветься змінна, що обраховує кількість повторень (і, відповідно, номер поточного повторення).

У всіх наведених вище циклах є лічильник; в циклі for-do лічильник є обов'язково, згідно з конструкцією цього циклу. Лічильник змінюється в кожному циклі за очевидним законом (зазвичай - на одиницю: i:=i+1). Для лічильників часто використовуються змінні з назвами i,j,k і т. д., хоча в цілому бажано давати змінним змістовніші імена.

  • Якщо умова зміни лічильника складніша, все одно іноді можна використовувати цикл for-do. Наприклад, щоб вивести на екран всі парні числа від 2 до 10, можна скористатися циклом while-do з додаванням 2 до лічильника:
i:=2;
while i<=10 do begin
  writeln(i);
  i:=i+2;
end;

а можна циклом for-do:

for i:=1 to 5 do
  writeln(2*i);
  • Акумулятор - змінна, що "накопичує" в собі певне значення; вона є певним узагальненням лічильника. Ось програма, що обчислює кількість і суму введених чисел, доки не введуть 0:

program CountInput;
var chyslo,lik,sum:integer;
begin
  writeln('Вводьте числа по одному, для закінчення введіть 0');
  lik:=0;
  sum:=0;
  chyslo:=0;
  repeat
    lik:=lik+1;
    sum:=sum+chyslo;
    readln(chyslo)
  until chyslo=0;
  writeln('Введено ', lik, ' чисел, сума = ', sum)
end.

Зверніть увагу, що в цьому циклі є і акумулятор, і лічильник, але умова виходу із ними не пов'язана.

Акумулятор і лічильник перед циклом слід встановлювати в початкові значення ("занулювати"). В циклі for-do початкове значення лічильника встановлюється конструкцією циклу.

Переривання роботи циклу

ред.

Крім умови виходу і команди goto, є ще дві команди для переривання роботи циклу: continue і break. Перша припиняє виконання тіла і переходить на перевірку умови виходу з циклу; друга одразу переходить на наступну за циклом команду. Таким чином, цикл

a:=0;
while a<100 do begin
  a:=a+1;
  write(a,' ');
  if a<20 then continue;
  writeln('не менше 20');
  if a=30 then break;
end;

буде виконано 30 разів, причому перші 19 буде виведено додаткове повідомлення. Одразу зауважте, що у випадку вкладених циклів ці оператори впливають тільки на внутрішній цикл. Як і у випадку з goto, використовувати ці команди небажано; але якщо є потреба, краще використовувати їх.

Структурне програмування

ред.

Спосіб написання програм без неочікуваних переходів (goto, break і continue), за допомогою трьох основних алгоритмів - лінійного виконання, розгалужень і циклів - зветься структурним програмуванням. Структурна програма зазвичай значно простіша для розуміння, що полегшує її розробку і підтримку. Для переробки неструктурованого циклу в структурований доводиться змінювати деякі умови і, іноді, вводити додаткові змінні, що містять ознаку певного стану - прапорці; зазвичай їх роблять типу boolean. Наприклад, код з попереднього підрозділу може бути записаний так:

a:=0;
while a<=30 do begin
  a:=a+1;
  write(a,' ');
  if a>=20 then 
    writeln('не менше 20')
end;

Завдання

ред.

1. Як переробити програму CountInput, щоб вона закінчувала роботу при перевищенні певної суми? 2. Написати програму, що виводить максимальний елемент серед введених чисел.