Оператори повторення (циклу)

При складанні програм часто виникає потреба повторити якусь певну команду чи групу команд кілька разів. Для цього існують спеціальні конструкції, що називаються циклами (або командами повторення) які просто зазначають, скільки разів потрібно повторити певну команду (групу команд), чи до яких пір повторювати ці команди. В мові Паскаль існує три види циклів, які починаються службовими словами WHILE (поки), REPEAT (повторювати) і FOR (для).

Перш, ніж перейти до розгляду варіантів організації циклів розглянемо задачу, яка просто розв’язується з використанням теорії, що буде описана нижче.

Існує така легенда. Одного разу вчитель математики, бажаючи звільнити себе під час уроку для більш важливих справ, запропонував дітям знайти суму перших ста натуральних чисел. Операція додавання та солідна кількість чисел повинна була забезпечити йому комфортний стан на протязі деякого часу. І яке ж було його невдоволення (?), коли один з учнів повідомив правильний результат через якусь хвилину. Ідея розв’язання цієї задачі, можливо, стала початком створення теорії арифметичної прогресії, а кмітливий учень став великим математиком. Все можливо. А якщо твоя цікавість переможе лінь, то ти знайдеш простий метод розв’язання такої задачі.

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

Задача 1.

Знайти суму перших ста натуральних чисел.

Але спочатку теорія.

Цикл WHILE

Записується у такому вигляді:

WHILE логічний вираз DO оператор

або

WHILE логічний вираз DO

BEGIN

оператор;

……..;

оператор

END;

Читається це так: ПОКИ "логічний вираз" вірно, ВИКОНАТИ "оператор (складений оператор). Ту частину, яку потрібно виконувати, називають тілом циклу. Працює ця конструкція таким чином. Спочатку обчислюється значення "логічного виразу". Якщо воно дорівнює TRUE (істина), виконується тіло циклу після службового слова DO після чого виконується повернення на початок циклу і все повторюється знову починаючи з обчислення "логічного виразу". Цикл виконується доти, поки значенням "логічного виразу" не стане FALSE (хибність). Після цьогопродовжують виконуватись оператори, що записані після циклу (відразу за його тілом). Якщо при початковій перевірці значенням "логічного виразу" відразу стало FALSE, то тіло циклу не виконується жодного разу. В тілі циклу необхідно передбачити зміну даних для "логічного виразу", в протилежному випадку його значення може постійно опинятися TRUE, і цикл буде виконуватися без кінця (зациклювання).

Var s:integer; {тут буде накопичуватися наша сума}

i:integer; {це буде змінна для організації циклу}

begin

s:=0; {положили число, нейтральне до додавання}

i:=1; {почнемо перегляд з 1}

whilei<=100 do begin {виконуємо, якщо і ще менше-рівне 100}

s:=s+i; {додаємо чергове число у нашу суму}

i:=i+1;{переходимо до наступного}

end;

writeln(s);{вивестисуму}

end.

Неважко бачити,що при першому проході циклу до змінної s буде додано 1, при другому – 2, при третьому – 3 і при останньому- 100. Як тільки і стане рівним 101, умоваi<=100 набуде значення False і програма перейде до наступної команди, що знаходиться після циклу, тобто writeln(s), де і буде організоване виведення результату на екран.

Наступний спосіб організації циклічних обчислень.

Цикл REPEAT

має вигляд:

REPEAT

оператор(и)

UNTIL логічний вираз

Читається так:

ПОВТОРЮВАТИ "оператор(и)" ДОТИ, ПОКИ "логічний вираз" не стане вірним (TRUE). Зверніть увагу, що цикл завершується, коли логічний вираз стає TRUE, а не FALSE, як у циклі WHILE. Якщо в тілі циклу використано кілька операторів, не обов'язково обмежувати їх словами BEGIN та END у вигляді складеного оператора, оскільки слова REPEAT та UNTIL і без цього чітко визначають початок і кінець циклу. Тому, що умовавиходу зциклу перевіряється в кінці, тіло циклу виконується ЗАВЖДИ як мінімум один раз. Якщо "логічний вираз" постійно залишатиметься FALSE, відбудеться зациклювання. Цикл REPEAT використовується у тих ситуаціях, коли виконується певна група операторів, а потім, в залежності від результатів виконаних дій, чи далі продовжується робота програми, чи ця група операторів виконується знову.

Знову розглянемо розв’язок нашої задачі, але уже з використанням циклу REPEAT.

Var s:integer; {тут буде накопичуватися наша сума}

i:integer; { це буде змінна для організації циклу}

begin

s:=0; {положили число, нейтральне до додавання}

i:=1; {почнемо перегляд з 1}

repeat {початок циклу}

s:=s+i; {додаємо чергове число у нашу суму}

i:=i+1; {переходимо до наступного}

until i=101; {якщо наступне не «наше»- виходимо з циклу}

writeln(s); {вивестисуму}

end.

Тепер уже не важко передбачити результат виконання такої програми.

Цикл FOR

У цьому циклі не перевіряється умова закінчення циклу, а просто рахується, скільки разів виконується його тіло. Тому зациклювання циклу FOR просто неможливе. Рахування йде за допомогою спеціального параметра — лічильника. У зв'язку з цим цикл FOR часто називають циклом з параметром. Існує два різновиди цього оператора:

1) FOR ім'я_змінної:=вираз1 ТО вираз2 DO оператор

2) FOR ім'я_змінної:=вираз1 DOWNTO вираз2 DO оператор

"Оператор" в тілі циклу обох конструкцій може бути складеним. Змінна, яка записана після слова FOR, і є лічильником циклу. Обидва різновиди читаються так:

ДЛЯ лічильника „ім'я_змінної” що змінюється від значення "виразі" ДО значення "вираз2" ВИКОНАТИ "оператор". Лічильник і значення виразів у заголовку циклу повинні бути типу не REAL.

Виконується оператор FOR таким чином. Змінній-лічильнику надається початкове значення, яке дорівнює значенню "вираз1". Потім виконується тіло циклу. Далі в комірку лічильника, згідно з його типом, розміщується наступне значення (для 1-го варіанта) або попереднє (для 2-го варіанта), і знову виконується тіло циклу.

Востаннє цикл буде виконано, коли значення лічильника дорівнюватиме "виразу2". Якщо у першому різновиді оператора FOR значення "виразу 1" більше, а в другому різновиді менше за значення "виразу2", то цикл не виконуватиметься жодного разу. Значення лічильника може використовуватися всередині циклу. Як частковий випадок, замість виразів у заголовку циклу можуть бути використані окремі змінні або константи.

ПОПЕРЕДЖЕННЯ!

Цикп FOR все ж можливо зациклити, якщо в тілі циклу переозначити змінну-лічильник так, щоб вона не змогла б дорівнювати значенню "виразу2". Намагайтеся НЕ ПЕРЕОЗНАЧУВАТИ ЛІЧИЛЬНИК всередині циклу FOR!

Розглянемо задачу знаходження суми ста перших натуральних чисел за допомогою циклу FOR у двох його варіантах.

Варіант 1.

Var s:integer; {тут буде накопичуватися наша сума}

i:integer; { це буде змінна для організації циклу}

begin

s:=0; {положили число, нейтральне до додавання}

for i:=1 to 100 do {початок циклуз перевіркою умови виходу (i<=100)}

s:=s+i; {додаємо чергове число у нашу суму}

writeln(s); {вивести суму}

end.

Оскільки в тілі циклу знаходиться лише одна, то операторні дужки begin end не є обов’язковими. Цикл припинить свою роботу коли змінна і стане рівна 101. Тоді виконається перехід до наступної за циклом команди.

Варіант 2.

Var s:integer; {тут буде накопичуватися наша сума}

i:integer; { це буде змінна для організації циклу}

begin

s:=0; {положили число, нейтральне до додавання}

for i:=100 downto 1 do {початок циклуз перевіркою умови виходу (i>=1)}

s:=s+i;{додаємо чергове число у нашу суму}

writeln(s);{вивести суму}

end.

В чому полягає різниця виконання даних варіантів програм? Лише у порядку додавання чисел. Так, в першому варіанті, спочатку додається 1 і число 100 буде додане до суми останнім, а в другому варіанті число 100 додається першим і 1 буде додана останьою.

Задача 2.

Вивести на екран коди всіх, малих латинських літер в порядку спадання від z до а по 5 кодів у рядку (в останньому рядку вийде 1 код).

CONST count= 5;{кількість кодів у рядку}

VAR ch: сhar;

i: іnteger;{допоміжний лічильник}

BEGIN

writeln ('Коди малих латинських літер');{вивід повідомлення з переходом на новий рядок}

i:=1;{лічильник рядків = 1}

for ch: ='z' downto 'a' do begin{початок циклу по символах}

write(ch:3);{виводимо символ}

wirte(':');{у тому ж рядку виводимо роздільник «:»}

write(ord(ch):3);{у тому ж рядку виводимо код символа}

if (i mod count)=0 then writeln;{якщо кількість символів в рядку кратнаcount- переходимо}

i:=i+1;{збільшуємо кількість символів}

end;{кінець циклу}

END.{кінець програми}

У програмі фактично присутні два лічильники. Основний —ch— символьного типу — використовується для друкування самих літер та їх кодів. Другий — і — допоміжний цілого типу, рахує виведені символи. Як тільки їх кількість стане кратною 5, спрацьовує оператор writeln без параметрів. Він тільки переведе курсор на початок наступного рядка. Інші конструкції для тебе вже знайомі.

Задача 3.

Роздрукувати на екрані всі символи зі стандартної таблиці по порядку зростання їх кодів від 30 до 255.

CONST BegCode=30;

EndCode=255;

VAR code:іnteger;

BEGIN

for code:=BegCode to EndCode do

write(chr(code));

writeln;{по закінченню циклу переводимо }

END.{курcop на початок наступного рядка}

Задача 4.

Знайти найбільший спільний дільник двох чисел a і b.

Найбільший спільний дільник можна визначити за допомогою алгоритму Евкліда. Алгоритм ґрунтується на таких властивостях цілих чисел: якщо a>b, то NSD(a,b)=NSD((a-b),b); якщо a<b, то NSD(a,b)=NSD(a,(b-a)); якщо a=b, то NSD(a,b)=a. Застосуємо цю властивість у циклі і отримаємо таку симпатичну програму:

Var a,b: integer;

Begin

Readln(a,b);

While a<>b do

If a>b then a:=a-b else b:=b-a;

Writeln(a);

End.

Задача 5. Протабулювати функціюy=x2+2x-5 на проміжку [-2;2] з кроком 0.5.

Протабулювати – значить вивести значення х, та відповідне значенняy. Виведемо ці значення у вигляді таблиці. В кожному рядку будемо виводи спочатку значення х, а потім відповідне значення функції. Оскільки крок не є цілим числом, то всі змінні мають бути дійсними числами, наприклад, типу REAL.

Var x,y,step:real;

Begin

step:=-2;

while step<=2 do begin

y:=sqr(x)+2*x-5;

writeln(x:4:2,y:4:2);

step:=step+0.5;

end;

end.

Задача 6.

Визначити, чи є задане натуральне число простим.

Згадаємо з математики, що просте — це число, яке цілком без остачі ділиться тільки саме на себе та на одиницю, і складемо алгоритм розв'язання. Найпростіший метод — "лобова атака". Будемо ділити задане число N на всі числа підряд від 2 до N-1, тим більше, що за нас це робить ЕОМ. Якщо хоч при якомусь одному діленні вийде нульовий залишок — число N складене. Інакше — просте.

var n,i: integer; {і-число, на яке будемо ділити}

flag: boolean;{допоміжна змінна -"прапорець"}

BEGIN

readln(n);{вводимо з клавіатури число}

i: = 2;{починаємо ділити з 2}

flag:=true;{"піднімаємо" прапорець як дозвіл}

{почати цикл ділень}

while (i<n) and flag do{працює, поки дільник не перевищує}

{nі прапорець дозволяє ділити}

begin

if (n mod i)=0{у випадку нульового залишку "опускаємо"}

then flag:=false;{прапорець, цикл ділень припиняється}

і:=і+1;{не забуваємо збільшити дільник}

end;

if flag{якщо прапорець залишився "піднятим",}

then writeln(n,' - просте число'){то число просте}

else writetn(n,' - складене число')

END.

Кілька зауважень. Новим для тебе є буде використання прапорця. Такі прапорці (булеві змінні) часто вживаються програмістами в якості індикаторів певних подій або процесів (наприклад, TRUE — дія відбулась, FALSE — ще ні і т.ін.). У вище наведеній програмі прапорець дуже наочно контролює процес ділення. В тілі циклу перевіряємо: якщо ділення дало ненульовий залишок, то значення прапорця не змінюється (це забезпечує повторне виконання циклу), дільник нарощується на 1 і цикл повторюється. Якщо ж залишок дорівнює 0, це означає, що числоnкрім себе і на 1 ділиться ще на "щось", тобто воно є складене. Прапорець скидається в FALSE, після чого дільник ще раз збільшується на 1, потім перевіряється логічний вираз у заголовку циклу (на цей раз він стане FALSE) і цикл завершується. Значення цього ж прапорця зручно використовувати і для виведення результату.

Корисна інформація

Рядок

REPEAT UNTIL KEYPRESSED;

дозволяє затримати виконання програми до натискання на будь-яку клавішу.Функція KEYPRESSED повертає значення TRUE коли нажата клавіша і цикл, в якому немає жодного оператора, закінчує свою роботу. Я не рекомендую використовувати даний цикл на олімпіадах. Він буде заважати автоматичній перевірці задачі і, швидше всього, задача не буде зарахована.

Просто приклад цікавої програми.

Покупець, заходячи в універсам, повідомляє про суму грошей, яку при собі має. Потім він ходить магазином, вибираючи собі в кошик різні товари. Кишеньковий комп'ютер повинен попередити, коли ціна чергового товару перебільшить суму, що є в наявності.

var suma,cina : real;

BEGIN

write ('Bвeдiть суму готівки:');

readln(suma);

repeat

Write ('Ціна товару:');

readln(cina);

suma := suma - cina;

until suma < 0;

writeln ('Ha цей товар у Вас не вистачає грошей.');

writeln ('Покупки треба припинити.')

END.

Ця програма дозволить тобі краще зрозуміти роботу всіх операторів разом. Її можна було написати за допомогою циклу WHILE, але тоді б вона вийшла довшою на кілька операторів.

Оператор GOTO

Цей оператор сумісно з командою розгалуження також можна використати для утворення циклічних програм, але така реалізація циклу є складнішою та недоцільною у використанні. Оператор GOTO (оператор переходу) можна використовувати для зміни порядку виконання операторів у програмі. Він має такий вигляд:

GOTO мітка

Мітка — це ціле число без знаку, що вміщує не більше чотирьох цифр (тобто від 0 до 9999). Позаду мітки, в тілі програми, ставиться двокрапка.Так можна відмітити будь – яке місце програми з ціллю виконати перехід у це місце, при необхідності, за допомогою оператора GOTO. Всі мітки мають бути описані в розділі опису даних після службового слова LABEL. За допомогою оператора GOTO неможливо ввійти всередину циклу чи складеного оператора, бо інакше програма зустріне кінець структури, не маючи її початку.

Задача 4.

Визначити, чи є послідовність натуральних чисел, що вводяться з клавіатури, впорядкованою за зростанням. Нормальною ознакою закінчення вводу послідовності є число 9999.

label 1,2;

var nach, sled: integer;

BEGIN

repeat

write('Bведіть число:');

rеаdln (sled);

if sled < nach then goto 1 else nach: = sled

until sled=9999;

writeln ('Послідовність впорядкування за зростанням');

goto 2;

1: writeln('Послідовність не впорядковано. Програму перервано.')

2:END.

Це приклад того, як не треба писати програму. Але й у цьому вигляді вона працюватиме. Спробуйте з нею розібратись самостійно. Одне зауваження: якщо програма перейшла до мітки завдяки "вказівкам" оператора GOTO, то продовжують виконуватися оператори й далі після мітки. Якщо ж програма сама у ході послідовного виконання операторів підійшла до мітки, вона її взагалі "не помічає".

Оскільки оператори GOTO з мітками роблять програму заплутанішою, рекомендується їх використовувати якнайрідше, замінюючи еквівалентними конструкціями з операторів IF, REPEAT, WHILE і т.ін.

На закінчення подивіться правила розставлення крапок із комою в тілі програми.

Крапка з комою:

1) обов'язково ставиться після будь-якого оператора, якщо за ним йде інший оператор;

2) ніколи не ставиться перед службовим словом ELSE в операторі IF;

3) може не ставитися після оператора, за яким йде операторна дужка END, що закривається, чи службове слово UNTIL, та перед ELSE в САSЕ.

Кожна лишня крапка з комою в третьому випадку не є помилкою, але додає до коду програми один лишній порожній байт.

Використаний ресурс http://sbs2014.blogspot.com/2014/03/3.html

Файл для завантаження

Кiлькiсть переглядiв: 64