Вече се запознахте с циклите с предусловие и постусловие do и while. Днес ще научите за цикъла for. Това е може би най – удобния и използван от всички вид цикъл. Неговия запис ни позволява да спестим ред, два от програмния код. В същото време кода остава достатъчно експресивен.
Синтаксис
for( инициализация; условие; промяна ) {
-- код който ще се изпълнява --
}Ето и пример:
for(int i = 0; i <= 10; i++) {
cout << i << endl;
}Ето как работи:
- Когато влезем в цикъла се изпълнява полето инициализация. Това се прави само веднъж, преди цикъла да започне. Тук става и декларацията и инициализацията на водещата променлива, ако не сте го направили;
- Преди всяка итерация се проверява условието. Както в цикъла while. Итерация се прави само, ако условието е true.
- В края на всяка итерация се изпълнява полето промяна. След което програмата се връща в горната точка и проверява условието. Започва следваща итерация. Или при false цикъла приключва.
В примера, който дадохме е очевидно че се отпечатват числата от 0 до 10 включително. Нашата водеща променлива i участва и в трите полета. Това ни спестява няколко реда програмен код, не мислите ли?
Понякога може да се пропусне някое от условията – инициализация, условие, промяна. Ако това е удачно. Но не трябва да се забравя знака ‘;’, който ги разделя.
// безкраен цикъл
for(;;) {
...
}За какво да внимаваме
Честа грешка е двусмислието в полетата условие и промяна. Относно това което искате да направите. В нашия прост пример отпечатваме числа в нарастващ ред. Но помислете за следните случай?
// пример 1:
for(int i = 0; i < 10; i--)
cout << i << endl;
// пример 2:
for(int i = 0; i > 10; i++)
cout << i << endl;- Пример 1: Инициализираме променливата с 0. Проверката минава. Но декрементираме променливата. Условието винаги е true (променливата не нараства). И програмата изпада в безкраен цикъл;
- Пример 2: Не се отпечатва нищо. Просто защото сме объркали знака на условието. И то винаги връща false.
Друго за което трябва да се внимава е да не излезете от границите на масив. Ако имате масив от 100 елемента индексите са от 0 до 99. Ако се опитате в цикъл да запишете нещо на индекс 100, това е недефинирано поведение. Може да презапишете друга променлива или да достъпите неразрешена област от паметта. Това би довело до срив на програмата ви в най – добрия случай. Или до грешни резултати несъвпадащи с очакванията ви.
int MAX = 100;
int data[MAX];
// грешка, пишем в data[100] !!!
for(int i = 0; i <= MAX; i++)
data[i] = 0;
// това е ОК, правилно
for(int i = 0; i < MAX; i++)
data[i] = 0;Range based for цикъл
Това е друг вариант на for цикъла. По безопасен и по удобен. Тук водещата променлива е скрита от програмиста. А цикъла обхожда целия масив или колекция от данни. Кода е по описателен. Този синтаксис е въведен от C++ 11.
int data[100];
for(int i: data) {
cout << i << endl;
}Горния пример безопасно ще отпечата масива. При всяка итерация стойността на елемент от масива се копира в променливата i и тогава се отпечатва. За прости типове това не е проблем. Но когато елементите на масива (колекцията) са големи, като класове или структури тогава се ползват референции. За референциите ще учим скоро. Тук само ще ги споменем във връзка с този вид цикъл.
Какво е референция?
Референция (&) е просто друго име (alias) за вече съществуваща променлива. Когато използвате референции не се извършва копиране на стойността на самата променлива. Това ни позволява директно да работим с елементите на масива. Референциите работят като указателите. В горния пример се копира стойността на data[n] в променливата i. Копира се самата стойност. Както казахме това е бавно при големи обекти. При референция се копира само адреса на клетката от масива. Което е цяло число. Това намалява товара и програмата работи по бързо.
#include <iostream>
using namespace std;
int main() {
int data[10];
// инициализация на масива
for(int& i: data)
i = -42;
// извеждане
for(const int& a: data)
cout << a << endl;
}Break, continue, return
Тези команди работят по същия начин както при останалите видове цикли. Имат ефект в тялото на цикъла в който са извикани.
Вложени цикли
Вече сме ги илюстрирали и знаете как работят. Тук ще ви покажем два практични примера.
Рисуване на триъгълник в термнала 🙂
#include <iostream>
using namespace std;
int main() {
int n = 5;
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= i; j++) {
cout << "*";
}
cout << "\n";
}
}Сортиране на колекция от цели числа представена в масив
#include <iostream>
using namespace std;
int main() {
int arr[] = {5, 42, 13, 10, 2, 0, 9, 1, 3, 32};
// брой на елементите в масива
int n = sizeof(arr) / sizeof(int);
// извежда несортирания масив
cout << endl;
for(const int &x: arr)
cout << x << ", ";
cout << endl;
// bubble sort
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
// размяна
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
// извежда вече сортирания масив
for(const int &x: arr)
cout << x << ", ";
cout << endl;
}Задачи
1. Въведи N и намери сумата от 1 до N.
Решение
#include <iostream>
using namespace std;
int main() {
int n, sum = 0;
cout << "N = ";
cin >> n;
for (int i = 1; i <= n; i++) {
sum += i;
}
cout << sum << endl;
}2. Намери n! Факториел
Решение
#include <iostream>
using namespace std;
int main() {
int n;
long long fact = 1;
cout << "N = ";
cin >> n;
for (int i = 1; i <= n; i++) {
fact *= i;
}
cout << fact << endl;
}3. Направете масив съдържа числата от 1 до 100. Отпечатайте го. Намерете сумата на всички елементи от масива. Използвайте range based for цикъл.
Pешение
#include <iostream>
using namespace std;
int main() {
int arr[100];
// инициализация
int q = 1;
for(int& k: arr) {
k = q;
q++;
}
// проверка и сумиране
int sum = 0;
for(const int& k: arr) {
cout << k << ", ";
sum += k;
}
cout << endl;
cout << sum << endl;
}4. Имате масива {1,2,3,4,5,6,7,8,9,10} . Запишете във всяка клетка старата и стойност на квадрат. Използвайте референция.
Решение
#include <iostream>
using namespace std;
int main() {
int arr[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
for (int &x : arr) {
x *= x;
}
for (const int& x : arr) {
cout << x << " ";
}
}5. Изведете таблицата за умножение.
Решение
#include <iostream>
using namespace std;
int main() {
for (int i = 1; i <= 10; i++) {
for (int j = 1; j <= 10; j++) {
cout << i * j << "\t";
}
cout << endl;
}
}6. Даден е масив. Сортирайте го.
int arr[20] = {12, 45, 7, 89, 23, 56, 1, 78, 34, 90,
11, 67, 5, 99, 42, 18, 73, 26, 60, 3};Решение
#include <iostream>
using namespace std;
int main() {
int arr[20] = {12, 45, 7, 89, 23, 56, 1, 78, 34, 90,
11, 67, 5, 99, 42, 18, 73, 26, 60, 3};
int n = 20;
// сортиране
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < n - i - 1; j++) {
if (arr[j] > arr[j + 1]) {
swap(arr[j], arr[j + 1]);
}
}
}
// извеждане
for (int x : arr) {
cout << x << " ";
}
}7*. Решете горната задача, като използвате функцията sort ot <algorithms>.
Решение
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int arr[20] = {12, 45, 7, 89, 23, 56, 1, 78, 34, 90,
11, 67, 5, 99, 42, 18, 73, 26, 60, 3};
sort(arr, arr + 20);
for (const int& x : arr) {
cout << x << " ";
}
}8. Намерете най – голямото и най – малкото число в горния масив.
Решение
#include <iostream>
#include <limits>
using namespace std;
int main() {
int arr[20] = {12, 45, 7, 89, 23, 56, 1, 78, 34, 90,
11, 67, 5, 99, 42, 18, 73, 26, 60, 3};
int minVal = numeric_limits<int>::max(); // най-голямото възможно int
int maxVal = numeric_limits<int>::min(); // най-малкото възможно int
for (int x : arr) {
if (x < minVal) minVal = x;
if (x > maxVal) maxVal = x;
}
cout << "Min = " << minVal << endl;
cout << "Max = " << maxVal << endl;
}9*. Решете задача 8 като използвате min_element и max_element от библиотеката с алгоритми на C++ (вижте връзката в задача 7).
Решение
#include <iostream>
#include <algorithm>
using namespace std;
int main() {
int arr[20] = {12, 45, 7, 89, 23, 56, 1, 78, 34, 90,
11, 67, 5, 99, 42, 18, 73, 26, 60, 3};
int* minPtr = min_element(arr, arr + 20);
int* maxPtr = max_element(arr, arr + 20);
cout << "Min = " << *minPtr << endl;
cout << "Max = " << *maxPtr << endl;
}