Добавил:
Upload Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз: Предмет: Файл:
Мова програмування С.docx
Скачиваний:
3
Добавлен:
01.05.2025
Размер:
490 Кб
Скачать
☆

3.1 Вирази та блоки

Вираз на зразок x = 0 або i++ або printf(...) стають твердженням, якщо за ними слідує крапка з комою, як от

x = 0;

i++;

printf(...);

У C, крапка з комою позначає закінченням твердження, а не розділювач, як це прийнято в таких мовах як Pascal.

Фігурні дужки { та } використовуються для згруповування оголошень і тверджень разом ускладне твердження, або блок, тож вони синтаксично еквівалентні єдиному твердженню. Яскравим прикладом цього являються фігурні дужки, що оточують твердження всередині функцій, так само як дужки після if, else, while або for. (Змінні може бути оголошено всередині будь-якого блока; ми обговоримо це в Розділі 4). Крапка з комою не потрібні після правої фігурної дужки, що завершує блок.

3.2 If-else

Вирази if-else застосовуються для вираження ймовірних рішень. Формально, синтаксис наступний:

if (вираз)

твердження1

else

твердження2

де else-частина не є обов'язковою. Вираз обчислюється; якщо він істинний (тобто вираз не має нульового значення), буде виконано твердження1. Якщо хибний (вираз має нульове значення) і наявна else-частина, тоді виконується твердження2, натомість.

Оскільки if просто перевіряє числове значення виразу, це дозволяє використовувати певні скорочення в кодуванні. Найочевиднішим є написання

if (вираз)

замість

if (вираз != 0)

Іноді це виглядає природньо і зрозуміло, а інколи занадто зашифровано.

Оскільки else-частина у виразі if-else не обов'язкова, то може виникнути неоднозначність, коли якийсь else пропущено у гніздованій послідовності виразів if. Це вирішується шляхом пов'язування else із найближчим попереднім if, що не має відповідного else. Так, наприклад, у

if (n > 0)

if (a > b)

z = a;

else

z = b;

else відповідає if, що знаходиться всередині, що ми також підкреслили відступами. Якщо це не те, чого ви хотіли, тоді потрібно використати фігурні дужки, щоб змусити до відповідної приналежності:

if (n > 0) {

if (a > b)

z = a;

}

else

z = b;

Неоднозначність особливо небезпечна в ситуаціях як наступна:

if (n > 0)

for (i = 0; i < n; i++)

if (s[i] > 0) {

printf("...");

return i;

}

else /* ПОМИЛКА */

printf("error -- n is negative\n");

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

До речі, зверніть увагу на крапки з комою після z = a

if (a > b)

z = a;

else

z = b;

Вони там тому, що граматично за if слідує твердження, а стверджувальні вирази на зразок «a = z;» завжди мають закінчуватися крапкою з комою.

3.3 Else if

Конструкція

if (вираз)

твердження

else if (вираз)

твердження

else if (вираз)

твердження

else if (вираз)

твердження

else

твердження

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

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

else

твердження

можна не включати, або його можна використати для вловлювання помилок на кшталт «неможливих» умов.

Для ілюстрації вибору у трьох напрямках, ось функція двійчастого пошуку, яка виявляє чи певне значення x з'являється у масиві v. Елементи v мають знаходитись у порядку зростання. Функція повертає позицію (число між 0 та n-1), якщо значення x знайдено у v, і -1 — якщо ні.

Двійчастий пошук спочатку порівнює (введене) значення x із середнім елементом масиву v. Якщо x менший за значення посередині, тоді пошук зосереджується на нижній частині списку, якщо навпаки — більший, то на верхній. В обох випадках, наступним кроком буде порівняння xіз середнім елементом вибраної половини. Цей процес поділу відрізків на два продовжується доти, доки значення не буде знайдено, або діапазон виявиться порожнім.

/* binsearch: знаходить x серед v[0] <= v[1] <= ... <= v[n-1] */

int binsearch(int x, int v[], int n)

{

int low, high, mid;

low = 0;

high = n - 1;

while (low <= high) {

mid = (low+high) / 2;

if (x < v[mid])

high = mid - 1;

else if (x > v[mid])

low = mid + 1;

else /* знайдено збіг */

return mid;

}

return -1; /* збігу немає */

}

Фундаментальним рішенням є, чи x менший, більший, чи рівний середньому елементу v[mid]при кожному поступі; це дуже властиво else-if.

Вправа 3-1. Наш двійчастий пошук здійснює дві перевірки всередині циклу, тоді як однієї може вистачити (за умови додаткових перевірок поза циклом). Напишіть версію із одним тестуванням всередині циклу і порівняйте різницю в швидкості виконання програми.