Pascal/Цикли
Цикли
[ред.]Іноді в алгоритмі необхідно повернутися назад і знову виконати вже пройдену послідовність дій. Таке повторення зветься циклом. Так, у вигляді циклу можна записати, скажімо, алгоритм переміщень учня школи протягом тижня (дім - дорога - школа - дорога - дім - повторити). Найпростіше це можна реалізувати мітками, просто вказавши перехід на мітку, що знаходиться раніше команди 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. Написати програму, що виводить максимальний елемент серед введених чисел.