SHAPE \ * MERGEFORMAT
Цикл з постусловіем | SHAPE \ * MERGEFORMAT
Цикл з передумовою |
Незважаючи на те, що результат
роботи обох алгоритмів однаковий, існує різниця в їх організації. Відмінність пов'язана з розташуванням умови продовження циклу: у першому випадку перевірка відбувається після
того, як виконано черговий крок, у другому - перед черговим кроком.
Відповідно до цього, запропоновані алгоритми називаються
циклом з пост-умовою і
циклом з перед-умовою, відповідно. Мінливу k будемо називати
лічильником циклу, а повторюються в циклі оператори -
тілом циклу. У С + + існує декілька мовних конструкцій для організації циклів. У цій роботі ми розглядаємо цикл for, що іноді також називають
ітераційним циклом. Загальний формат його записи
for (<ініціалізація>; <условіе_продолженія>;
<ізмененіе_счетчіка>) { <Блок операторів>;
} Цикл for починається з виконання блоку <ініціалізації>, де, як правило, визначається початкове значення лічильника циклу. Далі слід перевірка <условія_продолженія>, і в разі, якщо це умова істинна, цілком виконується <блок_операторов> у тілі циклу.
SHAPE \ * MERGEFORMAT
На цьому завершується перший крок циклу, і
управління знову передається заголовку for, який виробляє <ізмененіе_счетчіка>. Наступний крок також буде включати в себе перевірку <условія_продолженія> і, в разі його істинності, послідовне виконання операторів тіла циклу. Циклічне повторення буде продовжено до тих пір, поки <условіе_продолженія> не стане хибним. На цьому виконання циклу припиняється, і управління передається наступному оператору за межами тіла циклу for.
Блок-схема цього алгоритму представлена на малюнку справа. Таким чином, for за визначенням є циклом з перед-умовою. Відзначимо, що блок ініціалізації в ньому виконується тільки один раз.
Як приклад використання цієї конструкції, розглянемо лістинг програми, вирішальної сформульовану вище завдання про виведення на екран всіх цілих чисел від 0 до 99.
//----------- Висновок значень у циклі ------------
# Pragma hdrstop
# Include <iostream.h>
# Include <conio.h>
# Pragma argsused
int main (int argc, char * argv [])
{
int k; / / оголошуємо змінну-лічильник
for (k = 0; k <100; k = k +1) / / цикл по k від 0 до 99 з кроком 1
{
cout <<k <<endl; / /
тіло циклу: виведення на екран k
}
getch (); / / затримка
return 0;
}
//-----------------------------------------------
Ще раз відзначимо тут деякі особливості запису циклу for. По-перше, кожен їх блоків заголовка (всередині круглих дужок) відокремлюється від іншого
символом крапки з комою. По-друге, крапка з комою після заголовка не ставиться (так як запис оператора на цьому не закінчена). По-третє, безпосередньо після заголовка має бути розташоване повторюване тіло циклу, виділене фігурними дужками.
У наведеному прикладі змінна-лічильник k оголошена в програмі окремої записом int k. Однак C + + також допускає оголошення лічильника безпосередньо в заголовку циклу
for
(int k = 0; k <100; k = k +1)
{
cout <<k <<endl;
}
У Turbo C + + така змінна буде дійсна і видно тільки
всередині циклу for, тоді як область дії змінної k з прикладу вище поширюється до кінця програми.
В якості лічильника циклу може використовуватися не тільки цілочисельна, але і речова змінна. Крок зміни лічильника також може бути будь-яким, в тому числі дробовим і від'ємним. Наприклад, наступний фрагмент коду виводить на екран значення функції sin (x) на інтервалі [0, 2p] з кроком p/180
for
(float x = 0; x <2 * M_PI; x = x + M_PI/180)
{
cout <<x <<"" <<sin (x) <<endl;
}
Аналогічно if-else, оператори в тілі циклу for (усередині фігурних дужок) прийнято зміщувати на декілька позицій праворуч для поліпшення читаності програмного коду.
2. Скорочені варіанти запису У випадку, коли тіло циклу складається лише з одного оператора, допускається відсутність обмежують його фігурних дужок, що досить часто використовується для скорочення запису. В іншому конструкція залишається незмінною
for (<ініціалізація>; <условіе_продолженія>;
<ізмененіе_счетчіка>) оператор;
Окремі (або всі) блоки в заголовку циклу for можуть бути порожніми, однак розділові крапки з комою є обов'язковими. Наприклад, запис
for (;;;)
{
<Оператори>;
}
є припустимою і означає нескінченний цикл повторення блоку операторів. Незважаючи на гадану абсурдність такого циклу в працюючій програмі, конструкції подібного виду іноді використовуються програмістами. Тут
вихід з циклу організовується за допомогою оператора break, який означає завершення циклу і вихід з нього.
for (;;;)
{
<Оператори>;
if (<умова>) break;
}
У заголовку циклу for також часто використовуються скорочені варіанти запису деяких арифметичних операцій, наприклад, операцій інкремента і декремента. Деякі (але далеко не всі) із таких скорочень наведено в
таблиці нижче
Стандартна запис
| Опис
| Скорочена запис
| Приклад використання
|
A = A + 1;
| збільшити значення змінної A на 1
| A + +;
| i + +;
|
A = A - 1;
| зменшити значення змінної A на 1
| A -;
| index -;
|
A = A + B;
| збільшити значення A на величину B
| A + = B;
| x + = 0.1;
|
A = A - B;
| зменшити значення A на величину B
| A -= B;
| result -= 10;
|
A = A * C;
| збільшити значення A в C раз
| A *= C;
| R *= rs;
|
A = A / D;
| зменшити значення A в D разів
| A / = D;
| S / = 10.;
|
Зокрема, записи
k = k + 1;
k + +;
k + = 1;
в програмі є еквівалентними, і означають одне і те ж дію - збільшення значення k на одиницю.
Приклад 2. Розрахуйте суму
доданків ряду
. Заданими вважаються: 1-е доданок
a 0, і рекурентне співвідношення, що зв'язує k-е доданок
a k з попереднім (k-1)-м доданком
a k -1 в вигляді
(Арифметична прогресія). Значення
вводяться з клавіатури.
Рішення. Будемо використовувати допоміжну змінну ak для зберігання значення чергового члена
a k, і змінну sum для обчислення суми.
Розрахунок організуємо з допомогою циклу for, в якому будемо послідовно обчислювати значення
a k, додавати його до sum і виводити на екран поточну інформацію (номер кроку k, значення чергового доданка, поточну суму).
//-------------- Розрахунок суми ряду --------------
# Pragma hdrstop
# Include <iostream.h>
# Include <conio.h>
# Pragma argsused
int main (int argc, char * argv [])
{
float d, a0, ak; / / речові d, a0, ak
int k, N; / / цілочисельні k, N
cout <<"Vvedite N ="; / / вводимо з клавіатури вихідні
cin>> N; / / значення - N, a0, d
cout <<"Vvedite a0 =";
cin>> a0;
cout <<"Vvedite d =";
cin>> d;
float sum = 0; / / Допоміжна змінна
for (k = 0; k <= N; k + +) / / цикл по k від 0 до N
{/ / Початок тіла циклу
ak = a0 + d * k; / / 1. обчислюємо ak
sum = sum + ak; / / 2. додаємо ak до sum
cout <<"shag" <<k <<": ak =" / / 3. виводимо на екран
<<Ak <<", S =" <<sum <<endl;
} / / Закінчення тіла циклу
cout <<"Summa -" <<sum; / / результат на екран
getch ();
return 0;
}
//-----------------------------------------------
Наберіть і відкомпілюйте код цієї програми. Дослідіть результати її роботи. Зобразіть блок-схему і поясніть алгоритм роботи програми.
3. Вкладені оператори циклу Аналогічно операторам умови if-else, цикли for можуть бути вкладені одна в одну, причому ступінь «вкладеності» також може бути довільною. В якості
лічильників такі цикли, як правило, використовують різні змінні.
Основне застосування вкладених циклів в комп'ютерних програмах пов'язано з перебором значень
у декількох вимірах (тобто кількох координат). В якості прикладу розглянемо задачу про розрахунок значень функції 2-х змінних
всередині квадрата хÎ [-p, p], yÎ [-p, p] з кроком p / 8 по обом сторонам. Завдання може бути вирішена програмно за допомогою вкладених циклів, як показано нижче (наведено тільки фрагмент)
for
(float x =- M_PI; x <M_PI; x + = M_PI / 8)
for
(float y =- M_PI; y <M_PI; y + = M_PI / 8)
cout <<x <<"" <<y <<"" <<exp (-x) * sqrt (y) <<endl;
Тут зовнішній цикл перебирає всі значення x-координати точки, і запускає вкладений у нього цикл по y-координатах. У внутрішньому циклі шукані значення функції виводяться на екран.
Розглянемо ще один приклад використання вкладених циклів.
Приклад 3. На порожній шахівниці знаходиться чорний ферзь в позиції (n, m). Знайдіть всі можливі положення білого короля, в яких він не знаходиться під ударом. Поточні координати ферзя вводяться з клавіатури.
Рішення. У
найпростішому варіанті завдання може бути вирішена перебором всіх можливих положень короля (k, l) і вибором тих з них, де він в безпеці. Враховуючи можливості ферзя атакувати по вертикалі, по горизонталі і по обох діагоналях, можна легко сформулювати умови «безпечної» позиції
· K! = N - ні атаки по вертикалі
· L! = M - ні атаки по горизонталі
· L - k! = M - n - ні атаки по діагоналі «північний схід»
· L + k! = M + n - ні атаки по діагоналі «північно-захід»
У силу того, що всі умови повинні бути дотримані одночасно, їх необхідно об'єднати з допомогою логічної операції «І».
Нижче наведено лістинг програми, вирішальної поставлене завдання
//------------ Шахова завдання 2 --------------
# Pragma hdrstop
# Include <iostream.h>
# Include <conio.h>
# Pragma argsused
int main (int argc, char * argv [])
{
int n, m, k, l, num = 0;
cout <<"Enter black
queen position:" <<endl;
cout <<"colunm n =";
cin>> n;
cout <<"row m =";
cin>> m;
cout <<endl <<"Safe white king positions:" <<endl;
for (k = 1; k <= 8; k + +) / / цикл по стовпцях
{
for (l = 1; l <= 8; l + +) / / цикл по рядках
{
if ((k! = n) & &
(L! = m) & &
(Lk! = mn) & &
(L + k! = m + n)) / / якщо всі умови виконані
{/ / Виводимо позицію (k, l) на екран
cout <<"(" <<k <<"," <<l <<")" <<endl;
num + +; / / і збільшуємо лічильник на 1
}
} / / Кінець циклу по рядках
} / / Кінець циклу по стовпцях
cout <<"number of safe positions -" <<num;
getch ();
return 0;
}
//---------------------------------------------