- •Передмова
- •Передмова до першого видання
- •Вступ
- •Вступний урок
- •Твердження for
- •Масиви
- •Аргументи - виклик за значенням
- •Типи, оператори та вирази
- •Константи
- •Оголошення
- •Оператори приросту та спаду
- •Оператори та вирази присвоєння
- •Вирази умов
- •Керування потоком
- •Вирази та блоки
- •If-else
- •Else if
- •Switch
- •Цикли while та for
- •Файли заголовка
- •Препроцесор C
- •Покажчики та масиви
- •Покажчики й адреси
- •Покажчики та масиви
- •Арифметика адрес
- •Аргументи командного рядка
- •Структури
- •Масиви структур
- •Покажчики на структури
- •Typedef
- •Сполуки
- •Ungetc
- •Виконання команд
- •Генератор випадкових чисел
- •Open, creat, close, unlink
Роздiл 3
Керування потоком
Вирази керування потоком якоїсь мови вказують на послiдовнiсть в якiй виконуються обчислювальнi дiї. Ми вже ознайомилися з бiльшiстю звичайних конструкцiй керування потоком у попереднiх прикладах; у цьому роздiлi ми поповнимо набiр i будемо точнiшими стосовно того, що обговорювалося ранiше.
3.1Вирази та блоки
Вираз на зразок x = 0 або i++ або printf(...) стають твердженням, якщо за ними слiдує крапка з комою, як от
x = 0; i++;
printf(...);
У C, крапка з комою позначає закiнченням твердження, а не роздiлювач, як це прийнято в таких мовах як Pascal.
Фiгурнi дужки { та } використовуються для згуртовування оголошень i тверджень разом у складне твердження, або блок, тож вони синтаксично еквiвалентнi єдиному твердженню. Яскравим прикладом цього є фiгурнi дужки, що оточують твердження всерединi функцiй, так само як дужки пiсля if, else, while або for. (Змiннi може бути оголошено всерединi будь-якого блоку; ми обговоримо це в Роздiлi 4.) Крапка з комою не потрiбнi пiсля правої фiгурної дужки, яка завершує блок.
3.2If-else
Вирази if-else застосовуються для вираження ймовiрних рiшень. Формально синтаксис наступний:
if (вираз)
61
62 |
РОЗДIЛ 3. КЕРУВАННЯ ПОТОКОМ |
твердження1 else
твердження2
де else-частина не є обов’язковою. Вираз обчислюється; якщо вiн iстинний (тобто вираз не має нульового значення), виконується твердження1. Якщо хибний (вираз має нульове значення) i наявна else-частина, тодi виконується твердження2, натомiсть.
Оскiльки if просто перевiряє числове значення виразу, це дозволяє використовувати певнi скорочення в кодуваннi. Найочевиднiшим є написання
if (вираз)
замiсть
if (вираз != 0)
Iнодi це виглядає природньо i зрозумiло, а iнколи занадто зашифровано. Оскiльки else-частина у виразi if-else не обов’язкова, то може виникнути не-
однозначнiсть, коли якийсь else пропущено у гнiздованiй послiдовностi виразiв if. Це вирiшується шляхом пов’язування else iз найближчим попереднiм if, що не має вiдповiдного else. Так, наприклад, у
if (n > 0)
if (a > b) z = a;
else
z = b;
else вiдповiдає if, що знаходиться всерединi, що ми також пiдкреслили вiдступами. Якщо це не те, чого ви хотiли, тодi потрiбно використати фiгурнi дужки, щоб змусити до вiдповiдної належностi:
if (n > 0) { if (a > b)
z = a;
}
else
z = b;
Неоднозначнiсть особливо небезпечна в ситуацiях як наступна:
3.3. ELSE IF |
63 |
if (n > |
0) |
for (i = 0; i < n; i++) |
|
|
if (s[i] > 0) { |
|
printf("..."); |
|
return i; |
|
} |
else |
/* ПОМИЛКА */ |
printf("error -- n is negative\n");
Не зважаючи на те, що вiдступи нiби недвозначно вказують на те, що саме ви маєте на увазi, компiлятор не збагне цього i пов’яже else з if всерединi. Таку помилку буває дуже важко знайти пiзнiше, тому у випадку гнiздованих if краще вживати фiгурнi дужки.
До речi, звернiть увагу на крапки з комою пiсля z = a
if (a > b) z = a;
else
z = b;
Вони там тому, що граматично за if слiдує твердження, а стверджувальнi вирази на зразок a = z; завжди мають закiнчуватися крапкою з комою.
3.3Else if
Конструкцiя
if (вираз) твердження
else if (вираз) твердження
else if (вираз) твердження
else if (вираз) твердження
else твердження
зустрiчаються настiльки часто, що вимагають невеликого обговорення. Ця форма ifвиразiв є найбiльш узагальненим способом написання виразiв вибору з-помiж багатьох напрямкiв. Умови (вираз) розглядаються по-черзi, якщо якась з умов справджується,
64 |
РОЗДIЛ 3. КЕРУВАННЯ ПОТОКОМ |
твердження, пов’язанi з цiєю умовою буде виконано, i це покладе кiнець усьому ланцюжку. Звичайно, що код кожного виразу може складатися як з одного рядка, так i з групи, включеної у фiгурнi дужки.
Останнє else має справу з випадками, що не збiглися з жодною умовою вище, це те що виконуватиметься поза вибором, якщо всi умови не справдилися. Iнодi може не бути жодної дiї яку потрiбно би було виконати поза вибором, у таких випадках кiнцеве
else твердження
можна не включати, або його можна використати для вловлювання помилок на кшталтнеможливих умов.
Для iлюстрацiї вибору у трьох напрямках, ось функцiя двiйчастого пошуку, яка виявляє чи певне значення x з’являється у масивi v. Елементи v мають знаходитись у порядку зростання. Функцiя повертає позицiю (число мiж 0 та n-1), якщо значення x знайдено у v, i -1 — якщо нi.
Двiйчастий пошук спочатку порiвнює (введене) значення x iз середнiм елементом масиву v. Якщо x менший за значення посерединi, тодi пошук зосереджується на нижнiй частинi списку, якщо навпаки — бiльший, то на верхнiй. В обох випадках, наступним кроком буде порiвняння x iз середнiм елементом вибраної половини. Цей процес подiлу вiдрiзкiв на два продовжується доти, доки значення не буде знайдено, або дiапазон виявиться порожнiм.
/* 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 |
/* знайдено збiг */ |
return mid; |
|
} |
|
return -1; |
/* збiгу немає */ |
}
