Глава 4

4.5. Оператори за цикъл


Операторите за цикъл се използват за реализиране на циклични изчислителни процеси.
Изчислителен процес, при който оператор или група оператори се изпълняват многократно за различни стойности на техни параметри, се нарича цикличен.
Съществуват два вида циклични процеси:
индуктивни и
итеративни.
Цикличен изчислителен процес, при който броят на повторенията е известен предварително, се нарича индуктивен цикличен процес.

Пример: По дадени цяло число n и реално число x, да се намери сумата

Ако S има начална стойност 1, за да се намери сумата е необходимо n пъти да се повторят следните действия:

а) конструиране на събираемо

б) добавяне на събираемото към S.


Цикличен изчислителен процес, при който броят на повторенията не е известен предварително, се нарича итеративен цикличен процес. При тези циклични процеси, броят на повторенията зависи от някакво условие.
Пример: По дадени реални числа x и e > 0, да се намери сумата

където сумирането продължава до добавяне на събираемо, абсолютната стойност на което е по-малка от e.
Ако S има начална стойност 1, за да се намери сумата е необходимо да се повторят следните действия:

а) конструиране на събираемо

б) добавяне на събираемото към S
докато абсолютната стойност на последното добавено към сумата S събираемо стане по-малка от e.
В този случай, броят на повторенията зависи от стойностите на x и e.
В езика C++ има три оператора за цикъл:
оператор for
Чрез него могат да бъдат реализирани произволни циклични процеси, но се използва главно за реализиране на индуктивни циклични процеси.
оператори while и do/while
Използват се за реализиране на произволни циклични процеси – индуктивни и итеративни.

4.5.1. Оператор for

Използва се основно за реализиране на индуктивни изчислителни процеси. Чрез пример ще илюстрираме използването му.

Задача 26. Да се напише програма, която по зададено естествено число n, намира факториела му.

Тъй като n! = 1.2. … .(n-1).n, следната редица от оператори го реализира:
int fact = 1;
fact = fact * 1;
fact = fact * 2;

fact = fact * (n-1);
fact = fact * n;
В нея операторите за присвояване са написани по следния общ шаблон:
fact = fact * i;
където i е цяла променлива, получаваща последователно стойностите 1, 2, …, (n-1), n.
Следователно, за да се намери n! трябва да се реализира повтаряне изпълнението на оператора fact = fact * i, за i = 1, 2, …, n. Това може да стане с помощта на оператора for.

Програма Zad26.cpp решава задачата.
Program Zad26.cpp
#include <iostream.h>
int main()
{cout << "n= ";
int n;
cin >> n;
if (!cin)
{cout << "Error, Bad Input! \n";
return 1;
}
if (n <= 0)
{cout << "Incorrect Input! \n";
return 1;
}
int fact = 1;
for (int i = 1; i <= n; i++)
fact = fact * i;
cout << n << "! = " << fact << "\n";
return 0;
}
Операторът for е в одебелен шрифт. Той започва със запазената дума for (за). В кръгли скобки след нея е реализaцията на конструкцията i = 1, 2, …, n. Тя се състои от три части: инициализация (int i = 1, условие (i <= n) и корекция (i++), отделени с ;. Забележете, че операторът i++ не завършва с ;. След този фрагмент е записан операторът fact = fact * i;, описващ действията, които се повтарят. Нарича се тяло на цикъла.
Изпълнението на програмата започва с въвеждане стойност на променливата n и проверка валидността на въведеното. Нека n = 3. След дефиницията на цялата променлива fact, в ОП за нея са отделени 4 байта, инициализирани с 1. Изпълнението на оператора for предизвиква за цялата променлива i да бъдат заделени 4 байта, които да се инициализират също с 1. Следва проверка на условието i<=n и тъй като то е истина (1<=3), се изпълнява операторът fact = fact*i;, след което fact получава стойност 1. Изпълнението на оператора i++ увеличава текущата стойност на i с 1 и новата й стойност вече е 2. Отново следва проверка на условието i<=n и тъй като то е истина (2<=3), се изпълнява операторът fact = fact*i;, след което fact получава стойност 2. Изпълнението на оператора i++ увеличава текущата стойност на i с 1 и новата й стойност вече е 3. Пак следва проверка на условието i<=n и тъй като то отново е истина (3 <= 3), се изпълнява операторът fact = fact*i;, след което fact получава стойност 2*3, т.е. 6. Изпълнението на оператора i++ увеличава текущата стойност на i с 1 и новата й стойност вече е 4. Условието i<=n е лъжа и изпълнението на оператора for завършва.
Въпреки, че променливата i е дефинирана в оператора for, тя е “видима” (може да се използва) след изпълнението му, като стойността й е първата, за която стойността на условието i<=n не е в сила (в случая 4).
На Фиг. 9 е дадено детайлно описание на оператора for.

Синтаксис
for (<инициализация>; <условие>; <корекция>)
<оператор>
където
- for (за) е запазена дума.
- <инициализация> е или точно една дефиниция с инициализация на една или повече променливи, или няколко оператора за присвояване или въвеждане, отделени със , и не завършващи с ;.
- <условие> е булев израз.
- <корекция> е един или няколко оператора, незавършващи с ;. В случай, че са няколко, отделят се със ,.
- <оператор> е точно един произволен оператор. Нарича се тяло на цикъла.
Семантика
Изпълнението започва с изпълнение на частта <инициализация>. След това се намира стойността на <условие>. Ако в резултат се е получило false, изпълнението на оператора for завършва, без тялото да се е изпълнило нито веднъж. В противен случай последователно се повтарят следните действия:
- Изпълнение на тялото на цикъла;
- Изпълнение на операторите от частта <корекция>;
- Пресмятане стойността на <условие>
докато стойността на <условие> е true.
Следната схема илюстрира изпълнението му:

false

true
for (<инициализация>; <условие>; <корекция>)

<оператор>



Фиг. 9.

Възможно е частите <инициализция>, <условие> и <корекция> поотделно или заедно, да са празни. Разделителите ( между тях обаче трябва да фигурират. Ако частта <условие> е празна, подразбира се true.

Забележки:
1. Тялото на оператора for е точно един оператор. Ако повече оператори трябва да се използват, се оформя блок.
2. Частта <инициализация> се изпълнява само веднъж – в началото на цикъла. Възможно е да се изнесе пред оператора for и остане празна (Пример 1). В нея не са допустими редици от оператори и дефиниция на променливи, т.е. недопустими са:
for (int i, i = 4; …
или
int i;
for (i = 4, int j = 5; …
а също две дефиниции, например
for(int i=3, double a = 3.5; …
Нарича се така, тъй като в нея обикновено се инициализират една или повече променливи.
3. Частта <корекция> се нарича така, тъй като обикновено чрез нея се модифицират стойностите на променливите, инициализирани в частта <инициализация>. Тя може да се премести в тялото на оператора for като се оформи блок от вида {<оператор> <корекция>;} (Пример 2).
4. Ако частта <условие> е празна, подразбира се true. За да се избегне зацикляне, от тялото на цикъла при определени условия трябва да се излезе принудително, например чрез оператора break (Пример 3). Това обаче е лош стил на програмиране и ние не го препоръчваме.
5. Следствие разширената интерпретация на true и false, частта <условие> може да бъде и аритметичен израз. Това също е лош стил на програмиране и не го препоръчваме.

Примери:
1. int i = 1;
for (; i<= n; i++)
fact = fact* i;
2. for (int i = 1; i<= n
{fact = fact* i;
i++;
}
3. for (int i = 1; ; i++)
if (i > n) break;
else fact = fact* i;

Област на променливите, дефинирани в заглавната част на for

Под област на променлива се разбира мястото в програмата, където променливата може да се използва. Казва се още където тя е “видима”.
Съгласно стандарта ANSI, областта на променлива, дефинирана в заглавната част на цикъла for започва от дефиницията й и продължава до края на цикъла.
Това значи, че тези променливи не са видими след оператора for, в който са дефинирани, т.е. фрагментът
for (int i = 1; i <= n; i++)
{…
}
for (i = 1; i <= m; i++)
{…
}
е недопустим - ще предизвика синтактична грешка заради недефинирана променлива i в заглавната част на втория оператор for.
Но тъй като това е ново решение на специалистите, поддържащи езика, повечето реализации в т.число и реализацията на Visual C++ 6.0, използват стария вариант, според който областта на променлива, дефинирана в заглавната част на цикъла for започва от дефиницията й и продължава до края на блока, в който се намира оператора for. Така, за реализацията на Visual C++ 6.0, горният фрагмент е напълно допустим. А фрагментът
for (int i = 1; i <= n; i++)
{…
}
for (int i = 1; i <= m; i++)
{…
}
сигнализира повторна дефиниция на променливата i.


Задачи върху оператора for

Задача 27. За какво може да бъде използвана следната програма?

Program Zad27.cpp
#include <iostream.h>
int main()
{cout << "n= ";
int n;
cin >> n;
if (!cin)
{cout << "Error, Bad input! \n";
return 1;
}
if (n <= 0)
{cout << "Incorrect input! \n";
return 1;
}
int f = 1;
for (int i = 1; i <= n; cin >> i)
f = f * i;
cout << f << "\n";
return 0;
}
Забележете, че тази програма илюстрира използването на оператора for за реализиране на итеративни циклични процеси. Това обаче се счита за лош стил за програмиране.

Препоръка: Използвайте оператора for само за реализиране на индуктивни циклични процеси. Освен това, ако for има вида:
for(i = start; i < (или i <= ) end; i = i + increment)
{ …
}
не променяйте i, start, end и increment в тялото на цикъла. Това е лош стил за програмиране. Ако цикличният процес, който трябва да реализирате, не се вмества в тази схема, не използвайте оператора for.


Задача 28. Да се напише програма, която по зададени x – реално и n – естествено число, пресмята сумата

Програма Zad28.cpp решава задачата.
Program Zad28.cpp
#include <iostream.h>
int main()
{cout << "x= ";
double x;
cin >> x;
if (!cin)
{cout << "Error, Bad input! \n";
return 1;
}
cout << "n= ";
short n;
cin >> n;
if (!cin)
{cout << "Error, Bad input! \n";
return 1;
}
if (n <= 0)
{cout << "Incorrect input! \n";
return 1;
}
double x1 = 1;
double s = 1;
for (int i = 1; i <= n; i++)
{x1 = x1 * x/i;
s = s + x1;
}
cout << "s= " << s << "\n";
return 0;
}


Задача 29. Нека n и m са дадени естествени числа, n ≥ 1, m > 1. Да се напише програма,която определя броя на елементите от серията числа

които са кратни на m.

Програма Zad29.cpp решава задачата.
Program Zad29.cpp
#include <iostream.h>
int main()
{cout << "n= ";
int n;
cin >> n;
if (!cin)
{cout << "Error, Bad input! \n";
return 1;
}
if (n < 1)
{cout << "Incorrect input! \n";
return 1;
}
cout << "m= ";
int m;
cin >> m;
if (!cin)
{cout << "Error, Bad input! \n";
return 1;
}
if (m <= 1)
{cout << "Incorrect input! \n";
return 1;
}
int br = 0;
for (int i = 1; i <= n; i++)
if ((i*i*i + 7*i*i + n*n*n) % 7 == 0) br++;
cout << "br= " << br << "\n";
return 0;
}

Задача 30. Дадено е естественото число n, n ≥ 1. Да се напише

програма, която намира най-голямото число от серията числа:

Програма Zad30.cpp решава задачата.
Program Zad30.cpp
#include <iostream.h>
#include <math.h>
int main()
{cout << "n= ";
int n;
cin >> n;
if (!cin)
{cout << "Error, Bad input! \n";
return 1;
}
if (n < 1)
{cout << "Incorrect input! \n";
return 1;
}
double max = cos(n+1/n);
for (int i = 2; i <= n; i++)
{double p = i*i*cos(n+i/n);
if (p > max) max = p;
}
cout << "max= " << max << "\n";
return 0;
}

Задача 31. Да се напише програма, която извежда върху екрана таблицата от стойностите на функциите sin x и cos x в интервала [0, 1].
Програма Zad31.cpp решава задачата.
Program Zad31.cpp
#include <iostream.h>
#include <iomanip.h>
#include <math.h>
int main()
{cout << setprecision(5) << setiosflags(ios :: fixed);
for (double x = 0; x <= 1; x = x + 0.1)
cout << setw(10) << x << setw(10) << sin(x)
<< setw(10) << cos(x) << "\n";
return 0;
}