C _Учебник_МОНУ
.pdf
|
Програмування базових алгоритмів |
139 |
int kol = 0; // кількості правильних відповідей, |
|
|
int i; |
// лічильнику циклів |
|
time_t t; |
// поточного часу – для ініціалізації генератора випадкових чисел. |
|
printf("*** Перевірка знань таблиці множення ***\n"); |
|
|
printf("Введіть відповідь і натисніть <Enter>\n"); |
|
srand((unsigned) time(&t)); |
// Ініціалізація генератора випадкових чисел |
||
for(i = 1; i <= 10; i++) |
// 10 тестів |
||
{ numbl = rand()%7 + |
2 |
; |
// Два випадкових числа |
numb2 = rand()%7 + |
2 |
; |
// у межах від 2 до 9 |
res = numbl * numb2;
printf("%i x %i=", numbl, numb2); scanf("%i",&otv);
if(otv == res)kol++;
else printf("Ви помилились! %i x %i = %i \n
Спробуйте ще раз\n", numbl, numb2, res);
}
printf("\nПравильних відповідей: %i\n", kol); printf("Ваша оцінка: ");
switch (kol)
{case 10: puts("Відмінно"); break; case 9: puts("Добре"); break; case 8: puts("Добре"); break;
case 7: puts("Задовільно"); break; default: puts("Погано"); break;
}
printf("\nДля завершення натисніть <Enter>"); getch();
return 0;
}
Результати виконання програми:
*** Перевірка знань таблиці множення ***
Введіть відповідь і натисніть <Enter> 8 х 4 = 32 3 х 2 = 6 5 х 7 = 35 9 х 6 = 56
Ви помилились! 9 x 6 = 54 Спробуйте ще раз
6 х 7 = 42
9 х 3 = 27
8 х 8 = 64
4 х 3 = 12
2 х 6 = 12
7 х 8 = 56
Правильних відповідей: 9 Ваша оцінка: Добре
Для завершення натисніть <Enter>");
140 |
Розділ 4 |
4.4.3 Вкладені цикли
Цикли може бути вкладено один в одного. При використанні вкладених циклів треба складати програму в такий спосіб, щоб внутрішній цикл повністю вкладався в тіло зовнішнього циклу, тобто цикли не повинні перетинатися. Своєю чергою, внутрішній цикл може містити власні вкладені цикли. Імена параметрів зовнішнього та внутрішнього циклів мають бути різними. Припускаються такі конструкції:
for(k=1; k<=10; k++)
{. . .
for(i=1; i<=10; i++) { . . .
for(m=1; m<=10; m++)
{ |
... |
} |
|
} |
|
}
Приклади проектів програм із вкладеними циклами
m |
i |
i 1 k 3 |
|
||
Приклад 4.44 Обчислити S |
|
|
|
|
, зна- |
|
|
|
|||
i 1 i 2 k 1 |
k |
|
чення m ввести з екрана. З обчислень вилучити доданки та множники, які дорівнюють нулю в чисельнику чи то знаменнику.
Розв‟язок. В цьому прикладі програми наведені цикли є вкладеними один в одного, оскільки параметр внутрішнього циклу k залежить від параметра зовнішнього циклу і (k змінюється від 1 до і). Добуток
k 3 є співмножником доданка і обчислюється у
kk 1i 1
внутрішньому циклі у змінній P. Оскільки внутрішній цикл складається лише з одного оператора, то операторні дужки { } не є обов‟язковими.
Перед зовнішнім циклом для обчислення суми слід обнулити змінну S, в якій будуть накопичуватись доданки, а перед зовнішнім циклом для обчислення добутку змінній p слід присвоїти значення 1.
Оскільки при обчислюванні добутку беруть участь лише цілі числа, то, щоб при діленні не втратити дробову частину, слід перетворити чисельник до дійсного типу; для цього можна дописати крапку до числа 3: (k+3.)/k.
|
Початок |
|
m |
|
s = 0 |
|
i 1, m |
Ні |
i≠2 |
|
|
|
Так |
|
p = 1 |
|
k 1, i 1 |
|
p=p (k+3)/k |
|
s=s+p i/(i – 2) |
|
s |
|
Кінець |
Програмування базових алгоритмів |
141 |
Текст програми для кнопки “Розв‟язок”:
void __fastcall TForm1::Button1Click(TObject *Sender)
{int i, k, m = StrToInt(Edit1->Text); float S = 0, p;
for(i = 1; i <= m; i++) if( i != 2)
{p = 1;
for(k = 1; k <= i+1; k++)
p*=(k+3.)/k;
S += i/(i-2.) * p;
}
Edit2->Text = FloatToStr(S);
}
7
Приклад 4.45 Обчислити суму ряду S , де i = 1, 2, …, 7.
i 1 3(2i 1)!
Розв’язок. Для обчислення суми S треба підсумувати сім доданків, для обчислення кожного з яких слід сформувати вкладений цикл для підрахунку факторіалів (2i 1)!. У даній програмі кожний доданок обчислюється в окремій
змінній а.
Текст програми:
void __fastcall TForm1::Button1Click(TObject *Sender)
{int i, k, fact;
float s=0, a, x=StrToFloat(Edit1->Text); for(i=1; i<=7; i++)
{fact=1;
for(k=1; k<=2*i–1; k++) fact *= k;
a = 2*pow(x,2*i–1)/(3*fact);
s += a;
}
Edit2->Text = FloatToStrF(s, ffGeneral, 4, 3);
}
Приклади консольних програм із вкладеними циклами
Приклад 4.46 Написати програму, котра генерує три послідовності з десяти випадкових чисел в діапазоні від 1 до 10, виводить на екран і обчислює середнє арифметичне кожної послідовності.
Текст програми:
// Обчислення середнього арифметичного послідовностей випадкових чисел
#include <vcl.h> #include <stdio.h> #include <conio.h> #include <time.h>
142 |
Розділ 4 |
#pragma argsused //------------------------------------------------------------
int main(int argc, char* argv[])
{int |
r; |
// Випадкове число |
int sum; |
// Сума чисел послідовності |
|
float sr; |
// Середнє арифметичне |
|
int i,j; |
// Лічильники циклів |
|
time_t t; |
// Поточний час – для ініціалізації генератора випадкових чисел |
// Ініціалізація генератора випадкових чисел (див. докладніше підрозд. 3.7) srand((unsigned) time(&t));
for(i = 1; i <= 3; i++) // Організуються три послідовності
{printf("\n Випадкові числа: "); sum =0;
for(j = 1; j <= 10; j++) { r = rand() % 10 +1 ; printf ("%i ", r) ;
sum += r;
}
sr = (float)sum / 10;
printf("\n Середнє арифметичне: %3.2f\n", sr);
}
printf("\n Для завершення натисніть <Enter>"); getch(); return 0;
}
Результат виконання програми:
Випадкові числа: 6 4 5 2 4 5 6 5 1 8 Середнє арифметичне: 4.60
Випадкові числа: 8 9 8 3 6 6 8 7 6 6 Середнє арифметичне: 6.70
Випадкові числа: 10 3 8 4 7 4 7 5 2 2 Середнє арифметичне: 5.20
Для завершення натисніть <Enter>
Приклад 4.47 Вивести на екран квадрат Піфагора – таблицю множення.
Текст основної програми:
#include <vcl.h> #pragma hdrstop #include <conio.h> #include <iostream.h> #pragma argsused
//------------------------------------------------------------
int main(int argc, char* argv[])
{ int i,j; // Номер рядка і стовпчика таблиці
printf("\n Квадрат Піфагора - таблиця множення \n\n"); for(j=1; j<=10; j++) printf("%4i", j);
Програмування базових алгоритмів |
143 |
printf("\n \n"); for(i=1; i<=10; i++)
{ printf("%4i ", i);
for(j=1; j<=10; j++) printf("%4i", i*j); printf("\n");
}
printf("\n Для завершення натисніть <Enter>\n"); getch(); return 0;
}
Результат виконання програми:
Квадрат Піфагора – таблиця множення
|
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
1 |
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
2 |
2 |
4 |
6 |
8 |
10 |
12 |
14 |
16 |
18 |
20 |
3 |
3 |
6 |
9 |
12 |
15 |
18 |
21 |
24 |
27 |
30 |
4 |
4 |
8 |
12 |
16 |
20 |
24 |
28 |
32 |
36 |
40 |
5 |
5 |
10 |
15 |
20 |
25 |
30 |
35 |
40 |
45 |
50 |
6 |
6 |
12 |
18 |
24 |
30 |
36 |
42 |
48 |
54 |
60 |
7 |
7 |
14 |
21 |
28 |
35 |
42 |
49 |
56 |
63 |
70 |
8 |
8 |
16 |
24 |
32 |
40 |
48 |
56 |
64 |
72 |
80 |
9 |
9 |
18 |
27 |
36 |
45 |
54 |
63 |
72 |
81 |
90 |
10 |
10 |
20 |
30 |
40 |
50 |
60 |
70 |
80 |
90 |
100 |
Для завершення натисніть <Enter>
Приклад 4.48 Увести цілі числа m і n та вивести на екран:
**********
**********
**********
де m – кількість рядків “зірочок” і n – кількість “зірочок” у рядку.
Розв‟язок. Для розв‟язання поставленого завдання слід організувати два вкладені цикли: зовнішній – для організації виведення окремих m рядків, тобто переходу на новий рядок, і внутрішній – для безпосереднього виведення n “зірочок” у рядок.
Текст основної програми:
#include <conio.h> #include <iostream.h>
//------------------------------------------------------------
int main(int argc, char* argv[])
{int i, j, m, n;
cout << "Ввести кількість рядків m: "; cin >> m;
cout << "Ввести кількість рядків n: "; cin >> n;
clrscr();
144 |
Розділ 4 |
for(i=1;i<=m;i++) |
|
{ for(j=1;j<=n;j++) cout << "*"; |
// Виведення рядка з n “зірочок” |
cout << endl; |
// Перехід на новий рядок |
} |
|
getch(); return 0; |
|
} |
|
Результат виконання програми:
Ввести кількість рядків m: 2 Ввести кількість рядків n: 8
Приклад 4.49 Увести кількість рядків і вивести на екран трикутник “зірочок”:
*
**
***
****
. . .
Розв‟язок. Як і у попередньому прикладі, для виведення одного рядка слід сформувати окремий цикл, а для виведення кількох таких рядків необхідно вкласти перший цикл у цикл, який буде формувати перехід до наступного рядка. У першому рядку має бути лише одна “зірочка”, у другому – дві, у третьому
– три і т. д. Тобто рядок з номером і має складатися з і “зірочок”, тому внутрішній цикл виконуватиметься і разів.
Текст програми:
#include <conio.h> #include <iostream.h>
//------------------------------------------------------------
int main(int argc, char* argv[])
{int i, j, m;
cout << "Ввести кількість рядків m: "; cin >> m;
clrscr();
for(i=1; i<=m; i++)
{for(j=1; j<=i; j++) cout << "*"; cout << endl;
}
getch(); return 0;
}
Результат виконання програми:
Ввести кількість рядків m: 5
Програмування базових алгоритмів |
145 |
4.4.4Оператори циклу з передумовою while та післяумовою do-while
Оператори з передумовою та післяумовою використовуються для організації циклів і є альтернативними операторові for. Зазвичай цикл з передумовою використовується, якщо кількість повторювань заздалегідь є невідома або немає явно вираженого кроку змінювання параметра циклу. А для багаторазових повторювань тіла циклу відомим є вираз умови, за істинності якої цикл продовжує виконання. Цю умову слід перевіряти кожного разу перед черговим повторенням. Приміром, при зчитуванні даних з файла умовою є наявність цих даних у файлі, тобто повторювати читання даних слід аж допоки вказівник не добудеться кінця файла (докладніше див. розд. 12).
Синтаксис циклу з передумовою:
while (<умова>) |
|
|
|
{ <тіло циклу> }; |
|
|
|
Послідовність операторів (тіло циклу) виконуєть- |
|
Ні |
|
ся, допоки умова є істинна (true, має ненульове значен- |
Умова? |
||
|
|||
ня), а вихід з циклу здійснюється, коли умова стане хиб- |
|
||
Так |
|
||
ною (false, матиме нульове значення). Якщо умова є |
|
||
Оператори |
|
||
хибною при входженні до циклу, то послідовність опе- |
|
||
|
|
||
раторів не виконуватиметься жодного разу, а керування |
|
|
|
передаватиметься до наступного оператора програми. |
|
|
|
Цикл з післяумовою використовується, якщо є потреба перевіряти умову |
|||
кожного разу після чергового повторення. Відмінність циклу з передумовою від |
|||
циклу з післяумовою полягає в першій ітерації: цикл з післяумовою завжди ви- |
|||
конується принаймні одноразово незалежно від умови. |
|
|
|
Синтаксис циклу з післяумовою: |
|
|
do {
<тіло циклу>
} while (<умова>);
Послідовність операторів (тіло циклу) виконуєть-
ся один чи кілька разів, допоки умова стане хибною
(false чи дорівнюватиме нулю). Якщо умова є істинна (ненульова), то оператори тіла циклу виконуються поТак вторно. Оператор циклу do-while використовується в
тих випадках, коли є потреба виконати тіло циклу хоча б одноразово, оскільки перевірка умови здійснюється після виконання операторів.
Якщо тіло циклу складається з одного оператора, то операторні дужки {} не є обов‟язкові.
Оператори while та do-while можуть завчасно завершитись при виконуванні операторів break (див. п. 4.4.5), goto (див. п. 4.3.2), return (вихід з поточної функції, див. підрозд. 8.1) усередині тіла циклу.
146 |
Розділ 4 |
Варто зауважити, що в тілі циклу слід передбачати змінювання параметрів, які беруть участь в умові, інакше умову виходу з циклу ніколи не буде виконано й відбуватиметься зациклювання.
Розглянемо відмінність роботи різних операторів циклу на прикладі обчислювання суми всіх непарних чисел у діапазоні від 10 до 100:
1) з використанням оператора for
int i, s=0;
for(i=11; i<100; i += 2) s += i;
2) з використанням оператора while
int s=0, i=11;
while(i<100) { s += i; i += 2; }
3) з використанням оператора do-while
int s=0, i=11;
do { s += i; i += 2;} while(i<100);
Приклади програм із застосуванням циклів while та do-while
|
|
x2k 1 |
|
Приклад 4.50 |
Обчислити суму ряду S |
|
, підсумовуючи чле- |
(2k 1)! |
|||
|
k 1 |
|
|
ни ряду, значення яких за модулем перевищують задану точність 10 4. Визначити кількість доданків. Значення х (– 2 < x < 2) вводити з клавіатури.
Розв‟язок. Для цього завдання в програмі недоцільно використовувати оператор циклу з параметром for, оскільки кількість повторювань попередньо є невідома. Доцільним буде використання оператора циклу з післяумовою do-while, оскільки на момент першої перевірки умови вже треба знати значення першого доданка.
Текст програми:
void __fastcall TForm1::Button1Click(TObject *Sender)
{ float x, a, s=0; |
// Оголошення змінних і встановлення |
int f, i, k=0; |
// їхніх початкових значень |
x=StrToFloat(Edit1->Text); |
// Введення значення х |
do |
// Цикл з післяумовою |
{ k++; |
// Збільшення змінної k на 1 |
for(i=1,f=1; i<=2*k-1; i++) f *= i; // Обчислення факторіала |
|
a=pow(x, 2*k+1)/ f; |
// Обчислення k-го доданка |
s+=a; |
// Підсумовування доданків |
} |
|
while(fabs(a)>=1e-4); |
|
Edit2->Text=FloatToStr(s) ; |
// Виведення обчисленої суми |
Edit3->Text=IntToStr(k); |
// та кількості доданків |
} |
|
|
Програмування базових алгоритмів |
|
|
|
147 |
|
|
5 |
( 1) |
i |
x |
i 1 |
|
Приклад 4.51 |
Обчислити суму знакозмінного ряду S |
|
|
трьома |
||
i! |
|
|||||
|
i 1 |
|
|
|||
|
|
|
|
|
|
варіантами, використовуючи різні оператори циклу.
Розв‟язок. Тут (–1)i+1 за непарних значень i (1, 3, 5, …) дорівнює 1, а за парних значень i (2, 4, 6, …) – (–1), тобто розглядається знакозмінний ряд, де всі парні доданки будуть від‟ємними, а всі непарні – зі знаком “+”.
Схеми алгоритмів усіх трьох програм наведено нижче.
|
Початок |
|
|
Початок |
|
|
|
|
|
|
|
Початок |
||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
S = 0, i=1 |
|
|
|
|
|
|
|
|
|
||||
|
S = 0 |
|
|
|
|
|
|
|
|
|
|
|
|
|
S = 0, i=1 |
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
Введення |
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Введення |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
Введення |
|
|
|
|
|
|
|
|
|
||||||||||||
|
|
|
|
х |
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
х |
|
|
|
|
|
|
|
|
|
|
|
|
|
х |
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
|
|
|
|
|
|
|
|
i <= 5 |
|
|
|
Ні |
|
|
|
|
|
||||
|
i = 1, 5 |
|
|
|
|
|
|
|
|
f=1, k=1 |
|
|||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
Так |
|
|
|
|
||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||
|
|
|
|
|
|
|
|
|
f = 1, k=1 |
|
|
|
|
|
|
|
|
|
||||
|
f = 1 |
|
|
|
|
|
|
|
|
|
|
|
|
|
f=f*k, k=k+1 |
|
||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
Ні |
|
|
|||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||
|
|
|
|
|
|
|
|
|
k <= i |
|
|
|
Так |
|||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
k = 1, i |
|
|
|
|
|
|
Так |
|
|
|
|||||||||||
|
|
|
|
|
|
|
|
|
|
k <= i |
||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
|
|
f=f*k, k=k+1 |
|
|
|
|
|
|
Ні |
|||||||
|
f = f * k |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
S=S+(–1) i xi+1/f |
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
S=S+(–1) |
i |
x |
i+1 |
/f |
|
|
|
|
|
|
i = i + 1 |
||||
|
|
|
|
|
|
|
|
|
|
|
|
|||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
S=S+(–1) i xi+1/f |
|
|
|
|
|
|
|
|
|
|
|
|
|
Так |
|
|
|
|||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
||||||||
|
|
|
i = i + 1 |
|
|
|
|
|
i <= 5 |
|||||||||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||||||
|
Виведення |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Ні |
||||||
|
|
|
Виведення |
|
|
|
Виведення |
|||||||||||||||
|
S |
|
|
|
|
|
||||||||||||||||
|
|
|
|
S |
|
|
|
|
|
|
|
|
|
|
S |
|||||||
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|||
|
Кінець |
|
|
Кінець |
|
|
|
|
|
|
|
|
Кінець |
|||||||||
|
a |
|
|
|
б |
|
|
|
|
|
|
|
|
|
|
в |
Схеми алгоритмів програм з різними операторами циклу: a – for; б – while; в – do-while
Програма з використанням різних операторів циклу:
void __fastcall TForm1::Button1Click(TObject *Sender) // for
{ int i, f, k; |
float S=0, x=StrToFloat(Edit1->Text); |
for(i=1; i<=5; |
i++) |
{for(k=1, f=1; k<=i; k++) f *= k; S += pow(–1,i)*pow(x,i+1)/f;
}
Edit2->Text = FloatToStr(S);
}
//------------------------------------------------------------
148 |
Розділ 4 |
void __fastcall TForm1::Button2Click(TObject *Sender) // while
{int i=1, f, k;
float S=0, x=StrToFloat(Edit1->Text); while(i<=5)
{f=1; k=1;
while(k<=i) { f *= k; k++; }
S += pow(–1, i) * pow(x, i+1) / f;
i++;
}
Edit3->Text = FloatToStr(S);
}
//------------------------------------------------------------
void __fastcall TForm1::Button3Click(TObject *Sender) // do-while
{int i=1, f, k;
float S=0, x=StrToFloat(Edit1->Text); do
{f=1; k=1; do
{f *= k;
k++;
}
while(k <= i);
S += pow(–1, i) * pow(x, i+1) / f; i++;
}
while(i <= 5);
Edit4->Text = FloatToStr(S);
}
|
|
1 |
x |
|
|
|
k |
|
2k |
||
Приклад 4.52 |
Обчислити суму ряду y |
|
, підсумовуючи |
||
2k(2k 1)! |
|||||
|
k 1 |
|
|
|
|
члени ряду, значення яких за модулем є більшими за задану точність . Визначити кількість доданків. Значення х (– 2 < x < 2) та 10 4 вводити з клавіатури.
Розв‟язок. Наведемо два способи розв‟язання цього завдання. Для наочності й контролю правильності окремо виведемо усі доданки.
П е р ш и й с п о с і б р о з в ‟ я з а н н я
#include <math.h>
void __fastcall TForm1::Button1Click(TObject *Sender) {Memo1->Clear();
float x, y = 0, u, eps;
x = StrToFloat(Edit1->Text); eps = StrToFloat(Edit2->Text); int i, f, k = 1;
do