Розгалуження

З матеріалу цього уроку ви дізнаєтесь, як "примусити" програму робити вибір своїх подальших дій

Чи доводилося вам коли-небудь приймати рішення під впливом обставин? Звісно, що так! Ми постійно це робимо! "Сходи в магазин, купи пачку масла, а якщо залишаться гроші, то ще й булочок до чаю!" Було колись щось подібне? Було! І такі ситуації трапляються з нами мало не щодня! Якщо їде машина, то потрібно зупинитися біля краю дороги і її пропустити. Якщо йде дощ, то візьми парасольку. Якщо обидва множника від'ємні, то добуток буде з "плюсом"... І так далі... Ми вирішуємо, що робити, в залежності від того, виконуються чи не виконуються певні умови. Наприклад, якщо умова "йде дощ" виконується (дійсно, йде дощ), то ми беремо парасольку, якщо умова "йде дощ" не виконується (немає дощу), то ми парасольку залишаємо вдома, бо вона нам не потрібна.

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

Кожне таке розгалуження - це як стояти на роздоріжжі й аналізуючи зовнішні чинники й свої внутрішні спонукання вирішувати, що робити далі: "Ліворуч підеш - багатство здобудеш, праворуч підеш - коня втратиш, прямо підеш - об камінь довбонешся!" :)

В.Васнецов "Витязь на роздоріжжі"

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

В будь-якому разі розгалуження в мові програмування Pascal має такий вигляд:

if <умова> then <дія "плюс"> else <дія "мінус">;

якщо <умова, виконання чи невиконання якої перевіряється> тоді <дія "плюс" - команда чи набір команд, які повинні бути виконані. якщо умова виконується> інакше <дія "мінус" - команда чи набір команд, які повинні бути виконані, якщо умова НЕ виконується>;

Зверніть увагу на ВІДСУТНІСТЬ будь-яких знаків пунктуації всередині усієї цієї конструкції.

Окрім повної форми розгалуження if <умова> then <дія "+"> else <дія "-">; використовується також і неповна: if <умова> then <дія "+">;. У цьому випадку так само перевіряється виконання умови (після if). Якщо вона виконується, тоді виконується усе те, що слідує після then. Якщо ж умова не виконується, то програма шукає else, а оскільки ми його не написали, то вона його і не знаходить! Що робити, якщо умова не виконується? А невідомо! Нічого не написано! От програма нічого й не робить і переходить на наступний рядок, щоб виконати команду, яка розміщена наступною.

Схема повної форми розгалуження
Схема неповної форми розгалуження

Слід зауважити, що форма if <умова> then; взагалі не має сенсу, адже, навіть, якщо умова й виконується, то після then замість команди стоїть крапка з комою - кінець команди, тобто не написано не тільки, що робити, в разі невиконання умови, а й що робити в разі її виконання! При компіляції цей рядок не викликає повідомлення про помилку, але ж він узагалі нічого й не робить! То для чого він тоді потрібен?

ЗАВДАННЯ 8

Дано три кута. Перевірити, чи існує трикутник з такими кутами

Математичною моделлю цієї задачі буде відома вам з курсу геометрії теорема про суму кутів трикутника. Будемо додавати введені з клавіатури величини і порівнювати їх суму зі 180°. Якщо утворена сума дорівнює 180, то будемо виводити повідомлення, що такий трикутник існує, а в протилежному випадку - що не існує.

Ось який вигляд матиме код цієї програми:

1. program sum_kut_tryk;
2. var a,b,c,s:integer;
3. begin
4.    writeln('Введіть кути трикутника');
5.    readln(a,b,c);
6.    s:=a+b+c;
7.    if s=180 then writeln('Трикутник з такими кутами існує!')
8.             else writeln('Трикутник з такими кутами не існує!')
9. end.

Пояснення:

Рядок 2: Не будемо морочити собі голову з дробовими числами, беремо усі кути цілі, тому тип даних - integer. Змінних у програмі - 4: три кута і змінна s, куди запишемо їх суму.

Рядок 5: Оскільки буде введено три числа, то, щоб не виводити тричі запрошення 'Введіть перший кут', 'Введіть другий кут'... можна написати це запрошення один раз, а зчитування даних з клавіатури організувати так: readln(a,b,c); . Тоді відбувається таке:

  1. Після виведення повідомлення 'Введіть кути трикутника' курсор переводиться на наступний рядок (ми ж написали writeln!) і там програма чекає, поки ми введемо перше число.
  2. Ми вводимо з клавіатури перше число і натискаємо Enter.
  3. Програма прочитує це перше число, записує його як a, переводить курсор на наступний рядок (бо readln) і чекає на друге число.
  4. Ми вводимо з клавіатури друге число і натискаємо Enter.
  5. Програма прочитує друге число, записує його як b, знову переводить курсор на наступний рядок і чекає на третє число.
  6. Те саме відбувається і з третім числом.

Рядок 7: Програма перевіряє, чи обчислена сума дорівнює 180. Якщо ця умова ВИКОНУЄТЬСЯ, то спрацьовує команда, розміщена після then - виводиться повідомлення про те, що такий трикутник існує, а написане після else ігнорується. Якщо ця умова НЕ ВИКОНУЄТЬСЯ, то пропускається написане після then і виконується команда, розміщена після else - виводиться повідомлення, що такого трикутника не існує.

Рядки 7,8: Усю послідовність if... then... else... можна було писати і в один рядок, головне, щоб без розділових знаків всередині але саме таке розташування (else на наступному рядку під then) наочно показує розгалуження в коді програми, що полегшує її читання, тому надалі розташовуйте ці елементи розгалуження саме так.

Результат роботи програми перед вами:

Між іншим, на змінній s можна було "зекономити" й не використовувати її зовсім. Тоді програма мала б такий вигляд (зверніть увагу, як в цьому випадку сформульована умова розгалуження в рядку 6):

1. program sum_kut_tryk;
2. var a,b,c:integer;
3. begin
4.     writeln('Введіть кути трикутника');
5.     readln(a,b,c);
6.     if a+b+c=180 then writeln('Трикутник з такими кутами існує!')
7.                  else writeln('Трикутник з такими кутами не існує!')
8. end.

ЗАВДАННЯ 9

Скласти програму для порівняння двох чисел і виведення повідомлення про те, яке з них більше

На перший погляд, аналогічна до попередньої задача:

if a>b then writeln('Перше число більше') else writeln('Друге число більше');

Однак, не все тут так просто. На відміну від попередньої задачі, тут випадків не два ("дорівнює 180", "не дорівнює 180"), а ТРИ:

  1. Перше число більше, ніж друге.
  2. Друге число більше, ніж перше.
  3. Числа рівні.

Тому, якщо умова a>b не виконується, то у нас залишається не одна, а ще дві і з них теж треба вибирати якийсь варіант. Схематично наш вибір матиме такий вигляд:

Якщо умова a>b не виконується, тоді після else повинно з'явитися нове розгалуження з перевіркою чи a<b. І от аж тоді, якщо a не більше b і a не менше b, залишається тільки один випадок: a=b. В результаті матимемо досить складну конструкцію розгалуження в розгалуженні:

1. program bilshe_menshe;
2. var a,b:integer;
3. begin
4.     writeln('Введіть числа');
5.     readln(a,b);
6.     if a>b then writeln('Перше число більше')
7.            else if a<b then writeln('Друге число більше')
8.                        else writeln('Числа рівні')
9. end.

В таких випадках, щоб не заплутуватись, простіше керуватися таким принципом:

  • якщо варіантів тільки два, тоді використовуємо повну форму розгалуження if... then... else...
  • якщо варіантів більше ніж два - тоді неповну if... then...

Такий вигляд матиме наша програма, написана з неповною формою розгалуження:

1. program bilshe_menshe;
2. var a,b:integer;
3. begin
4.     writeln('Введіть числа');
5.     readln(a,b);
6.     if a>b then writeln('Перше число більше');
7.     if a<b then writeln('Друге число більше');
8.     if a=b then writeln('Числа рівні')
9. end.

Як бачимо, довелося ввести ще одну перевірку if a=b... ну і кожне неповне розгалуження тепер закінчується крапкою з комою. Зате тепер в цих трьох простих розгалуженнях легше розібратися, аніж в одному складному.

ЗАВДАННЯ 10

Скласти програму для перевірки, введене число додатне, від'ємне, чи дорівнює нулю

А от тепер уже самотужки :)

Варіантів тут три, тому використовуємо неповну форму розгалуження:

1. program dodatne_vidjemne;
2. var a:integer;
3. begin
4.     writeln('Введіть число');
5.     readln(a);
6.     if a>0 then writeln('Число додатне');
7.     if a<0 then writeln('Число від',#39,'ємне');
8.     if a=0 then writeln('Число дорівнює нулю')
9. end.

А в рядку 7 той самий "трюк" з апострофом, який нам уже зустрічався в Уроці 3

ЗАВДАННЯ 11

Скласти програму для обчислення значення виразу:

Можливість обчислення значення цього виразу залежить від того, яке значення матиме змінна х, чи не перетворює вона знаменник на 0. От вам і приклад застосування розгалуження як обробника помилок. Якщо x-3=0, тоді потрібно вивести повідомлення, що виникає загроза ділення на 0, в протилежному разі - обчислюємо значення даного виразу і виводимо результат.

1.  program znach_funkciji;
2.  var x,y:real;
3.  begin
4.      write('x=');
5.      read(x);
6.      if x-3=0 then writeln('Ділення на нуль!')
7.               else 
8.                   begin
9.                        y:=4*sqr(x)/(x-3);
10.                       writeln('y=',y)
11.                  end
12. end.

Зверніть увагу на те, що команди y:=4*sqr(x)/(x-3); і writeln('y=',y) в 9 і 10 рядках довелося виділити службовими словами begin і end (рядки 8 і 11). Це зроблено тому, що ці дві команди повинні виконуватися разом, як одне ціле. Якщо x-3 не дорівнює нулю, тоді написане після then виконуватися не буде, а буде виконуватися те, що написано після else. Значить, потрібно і обчислити значення виразу 4*sqr(x)/(x-3), і вивести результат. Якщо ж begin і end не поставити, то вийде ось що:

begin і end в рядках 8 і 11 "закоментовано", щоб вони програмою не розглядалися

Pascal перевіряє умову, оскільки вона виконується, то спрацьовує те, що написане після then і виводиться повідомлення про ділення на нуль. А от після else ігнорується тільки перша по порядку команда обчислення значення виразу (рядок 9), після цього рядок 10 уже виконується в повному обсязі. От і відбувається виведення значення y, якого в даній ситуації не повинно бути взагалі. Це аналогічно до обчислення значення виразу 2∙3+4 - число 2 буде помножене тільки на 3, а якщо ми хочемо, щоб було виконане множення й на 4, тоді потрібно записати так: 2∙(3+4). Саме з таких міркувань команди y:=4*sqr(x)/(x-3); та writeln('y=',y) і взято в т.зв. "операторні дужки" begin ... end , щоб показати програмі, що те, що міститься між ними, виконується як одне ціле.

ПІДСУМКИ

З матеріалів цього уроку вам стало відомо:

  • що розгалуження є способом визначити, яким шляхом виконання іти програмі;
  • що розгалуження повинне обов'язково містити умову, виконання чи не виконання якої і є критерієм для визначення шляху виконання програми;
  • що розгалуження в Pascal оформлюється або в повній if... then... else... або в неповній if... then... формі, а всередині жодної з цих форм ніякі розділові знаки не ставляться;
  • що повну форму розгалуження найзручніше використовувати тоді, коли варіантів лише два, а неповну - коли більше двох;
  • що після if записується умова, виконання якої перевіряється, після then - команда чи послідовність команд, які повинні виконуватися, якщо умова виконана, а після else - команда чи послідовність команд, які повинні виконуватися. якщо умова не виконана;
  • якщо деяка послідовність команд повинна бути виконана як одне ціле, то їх беруть в операторні дужки begin ... end.

ДОМАШНЄ ЗАВДАННЯ

З клавіатури вводиться число. Якщо воно додатне - додати до нього 2 і вивести отриманий результат, якщо від'ємне - те саме але відняти від нього 3, якщо воно дорівнює нулю - вивести повідомлення про це.

Підказка

Щоб збільшити число на 2 можна зробити так: додаємо до цього числа 2 і записуємо результат у те ж місце, яке було відведене під початкове число. Наприклад, записати таку команду:

a:=a+2;

Другий спосіб - додавати число 2 в тому ж місці, де воно виводитиметься:

writeln(a+2);