MySQL Java JavaScript PHP Python HTML-CSS C-sharp C++ Go

Bucle (Cicluri)

Ciclurile permit executarea unui set de instrucțiuni de mai multe ori, atât timp cât este îndeplinită o anumită condiție. În limbajul C++ există următoarele tipuri de cicluri:

  • for
  • while
  • do...while

Ciclu while

Ciclul while execută un anumit cod atâta timp cât condiția sa este adevărată, adică returnează true. Are următoarea definiție formală:

while (condiție)
{
    // acțiuni de executat
}

După cuvântul-cheie while, între paranteze urmează expresia condițională, care returnează true sau false. Apoi, între acolade, se află setul de instrucțiuni care formează corpul ciclului. Și atâta timp cât condiția returnează true, se vor executa instrucțiunile din corpul ciclului.

De exemplu, să afișăm pătratele numerelor de la 1 la 9:

#include <iostream>
 
int main()
{   
    int i {1};
    while(i < 10)
    {
        std::cout << i << " * " << i << " = " << i * i << std::endl;
        i++;
    }
}

Aici, atâta timp cât condiția i < 10 este adevărată, se va executa ciclul while, în care se afișează în consolă pătratul numărului și se incrementează variabila i. La un moment dat, variabila i va ajunge la valoarea 10, condiția i < 10 va returna false, iar ciclul se va încheia.

Afișarea în consolă a programului:

1 * 1 = 1
2 * 2 = 4
3 * 3 = 9
4 * 4 = 16
5 * 5 = 25
6 * 6 = 36
7 * 7 = 49
8 * 8 = 64
9 * 9 = 81

Fiecare trecere individuală prin ciclu se numește iterație. Așadar, în exemplul de mai sus au avut loc 9 iterații.

Dacă ciclul conține o singură instrucțiune, acoladele pot fi omise:

int i {};
while(++i < 10)
    std::cout << i << " * " << i << " = " << i * i << std::endl;

Ciclu for

Ciclul for are următoarea definiție formală:

for (inițializator; condiție; iterație)
{
    // corpul ciclului
}
  • Inițializatorul se execută o singură dată la începutul ciclului și reprezintă setarea condițiilor inițiale — de obicei, inițializarea unor contoare (variabile speciale folosite pentru controlul ciclului)
  • Condiția este expresia care, dacă este adevărată, permite executarea ciclului. De regulă, este o operație de comparație; dacă aceasta returnează o valoare nenulă (adică true), corpul ciclului este executat, după care urmează pasul de iterație
  • Iterația are loc după fiecare execuție a blocului ciclului și stabilește modificarea parametrilor ciclului. De obicei, aici are loc incrementarea contorului ciclului

De exemplu, să rescriem programul de afișare a pătratelor numerelor folosind ciclul for:

#include <iostream>
 
int main()
{   
    for(int i {1}; i < 10; i++)
    {
        std::cout << i << " * " << i << " = " << i * i << std::endl;
    }
}

Prima parte a declarației ciclului – int i {1} – creează și inițializează contorul i. Practic, este același lucru cu o declarație și inițializare de variabilă. Contorul nu trebuie neapărat să fie de tip int. Poate fi și un alt tip numeric, de exemplu float. Înainte de executarea ciclului, valoarea acestuia va fi 1.

A doua parte este condiția în care ciclul va fi executat. În acest caz, ciclul se va executa atâta timp cât variabila i nu devine egală cu 10.

A treia parte reprezintă incrementarea contorului cu o unitate. Dar nu este obligatoriu să incrementăm cu 1. Putem și să decrementăm: i--. Sau să modificăm cu o altă valoare: i += 2.

În cele din urmă, blocul ciclului se va executa de 9 ori, până când variabila i va deveni egală cu 10. Și de fiecare dată această valoare va crește cu 1. Și, practic, vom obține același rezultat ca în cazul ciclului while:

1 * 1 = 1
2 * 2 = 4
3 * 3 = 9
4 * 4 = 16
5 * 5 = 25
6 * 6 = 36
7 * 7 = 49
8 * 8 = 64
9 * 9 = 81

Nu este obligatoriu să specificăm toate cele trei expresii în definiția ciclului — putem omite una sau chiar toate dintre ele:

int i {1};
for(; i < 10;)
{
    std::cout << i << " * " << i << " = " << i * i << std::endl;
    i++;
}

Formal, definiția ciclului rămâne aceeași, doar că acum prima și a treia expresie din definiția ciclului lipsesc: for (; i < 10;). Variabila-contor este definită și inițializată în afara ciclului, iar incrementarea ei are loc în interiorul ciclului.

De asemenea, un ciclu nu este obligat să conțină un corp. De exemplu, să calculăm cu ajutorul unui ciclu suma numerelor de la 1 la 5:

#include <iostream>
  
int main()
{  
    int sum {};
    for (unsigned i {}; i < 6; sum += i++);
    std::cout << "Sum: " << sum << std::endl;   // Sum: 15
}

Aici, pentru a stoca suma numerelor, este definită variabila sum, care are valoarea implicită 0. În ciclu este definită variabila-contor i, iar ciclul se execută până când i devine egală cu 6.

Acordă atenție celei de-a treia părți a definiției ciclului – sum += i++. Aici adunăm la variabila sum valoarea lui i, apoi incrementăm i. Astfel, am calculat suma numerelor fără a folosi corpul ciclului.

Expresia de inițializare poate defini mai mult de o variabilă. De exemplu, să definim două variabile și să afișăm în consolă produsul lor:

#include <iostream>
  
int main()
{   
    int numbers[]{1, 2, 3, 4};
    int sum {};
    for (int i {1}, j {5}; i < 6 && j < 10; i++, j++)
    {
        std::cout  << i << "*" << j << "="<< i * j << std::endl;   // Sum: 15
    }
     
}

Aici, ciclul se execută atâta timp cât fie variabila i nu devine egală cu 6, fie variabila j nu devine egală cu 10. Afișarea în consolă va fi următoarea:

1*5=5
2*6=12
3*7=21
4*8=32
5*9=45

Parcurgerea valorilor în stil for-each

Există și o formă specială a ciclului for, destinată în mod special lucrului cu secvențe de valori. Această formă are următoarea definiție formală:

for (tip variabilă : secvență)
{
    instrucțiuni;
}

De exemplu:

#include <iostream>
  
int main()
{   
    for (int n : {2, 3, 4, 5})
    {
        std::cout << n << std::endl;
    }
}

Aici, expresia {2, 3, 4, 5} reprezintă o secvență de valori — numere de tip int. Ciclul parcurge întreaga secvență și plasează fiecare valoare în variabila n, a cărei valoare este apoi afișată în consolă.

Un alt exemplu: un șir de caractere (string) reprezintă, de fapt, o secvență de caractere, care poate fi, de asemenea, parcursă folosind acest tip de ciclu:

#include <iostream>
  
int main()
{   
    for (char c : "Hello")
    {
        std::cout << c << std::endl;
    }
}

Aici, fiecare caracter al șirului este plasat în variabila c, a cărei valoare este apoi afișată în consolă.

În continuare, vom analiza diferite tipuri de secvențe care pot fi parcurse cu ajutorul acestui tip de ciclu.

Ciclu do

În ciclul do, codul din corpul ciclului este executat mai întâi, iar apoi se verifică condiția în instrucțiunea while. Atâta timp cât această condiție este adevărată (adică diferită de 0), ciclul se repetă. Definiția formală a ciclului:

do
{
    instrucțiuni
}
while (condiție);

De exemplu:

#include <iostream>
 
int main()
{   
    int i {6};
    do
    {
        std::cout << i << std::endl;
        i--;
    }
    while(i>0);
}

Aici, codul din ciclul do se va executa de 6 ori, până când i devine egal cu zero.

Dar este important de menționat că ciclul do garantează executarea acțiunilor cel puțin o dată, chiar dacă condiția din instrucțiunea while nu este adevărată. Adică putem scrie:

int i {-1};
do
{
    std::cout << i << std::endl;
    i--;
}
while(i>0);
}

Deși variabila i este mai mică decât 0, ciclul tot se va executa o singură dată.

Să analizăm încă un exemplu. În multe programe de consolă este implementat un ciclu similar, care continuă să ruleze până când utilizatorul introduce un anumit caracter.

Să presupunem că utilizatorul introduce numere, iar programul trebuie să calculeze media aritmetică a acestor numere. Utilizatorul poate introduce un număr nedeterminat de valori, iar dacă dorește să încheie introducerea, poate introduce caracterul "y" sau "Y":

#include <iostream>
  
int main()
{
    char reply {};          // răspunsul utilizatorului
    int count {};           // numărul de valori introduse
    double number {};       // pentru introducerea unui număr
    double total {};        // suma totală a numerelor
    do
    {
        std::cout << "Enter a number: ";
        std::cin >> number; // Introducem numărul
        total += number;    // îl adăugăm la suma totală
        ++count;            // creștem numărul valorilor introduse cu 1
        std::cout << "Finish? (y/n): ";
        std::cin >> reply;  // citim răspunsul utilizatorului
    } while (reply != 'y' && reply != 'Y');     // cât timp utilizatorul nu introduce caracterul y sau Y
     
    std::cout << "The average value is " << total / count << std::endl;
}

În acest caz, citim fiecare număr în variabila number, apoi îl adunăm la variabila total, mărind simultan contorul de numere – count. După fiecare introducere a unui număr, așteptăm și un alt input – dacă utilizatorul introduce "y" sau "Y", ciclul se încheie și afișăm media aritmetică a numerelor. Exemplu de rulare a programului:

Enter a number: 6
Finish? (y/n): n
Enter a number: 5
Finish? (y/n): y
The average value is 5.5

Cicluri for imbricate

Se pot defini cicluri imbricate. De exemplu, să afișăm tabla înmulțirii folosind un ciclu for imbricat:

#include <iostream>
 
int main()
{   
    for (int i {1}; i < 10; i++)
    {
        for(int j {1}; j < 10; j++)
        {
            std::cout << i * j << "\t";
        }
        std::cout << std::endl;
    }
}
1       2       3       4       5       6       7       8       9
2       4       6       8       10      12      14      16      18
3       6       9       12      15      18      21      24      27
4       8       12      16      20      24      28      32      36
5       10      15      20      25      30      35      40      45
6       12      18      24      30      36      42      48      54
7       14      21      28      35      42      49      56      63
8       16      24      32      40      48      56      64      72
9       18      27      36      45      54      63      72      81

Operatorii continue și break

Uneori apare necesitatea de a ieși dintr-un ciclu înainte ca acesta să se încheie. În acest caz, se poate folosi operatorul break. De exemplu, să calculăm suma numerelor de la 1 la 9, până când aceasta devine mai mare decât 20:

#include <iostream>
  
int main()
{
    int result{};
    for(int i{1}; i < 10; i++)
    {   
        result += i;
        std::cout << result << std::endl;
        if(result > 20) break;
    }
}

Aici, când valoarea variabilei result devine mai mare decât 20 (adică atunci când i va fi egal cu 6), are loc ieșirea din ciclu cu ajutorul operatorului break:

1
3
6
10
15
21

Spre deosebire de operatorul break, operatorul continue face trecerea la următoarea iterație. De exemplu, să calculăm suma doar a numerelor impare dintr-un anumit interval:

#include <iostream>
int main()
{
    int result {};
    for (int i {1}; i<10; i++)
    {
        if (i % 2 == 0) continue;
        result +=i;
    }
    std::cout << "result = " << result << std::endl; // result = 25
}

Pentru a verifica dacă un număr este par, obținem restul împărțirii întregi la 2, iar dacă acesta este egal cu 0, atunci folosim operatorul continue pentru a trece la următoarea iterație a ciclului. Iar dacă numărul este impar, îl adunăm la celelalte numere impare.

Cicluri infinite

Uneori este necesar ca un ciclu să se execute la nesfârșit. De exemplu, atunci când trebuie să monitorizăm în mod continuu modificările unor valori sau când nu știm dinainte câte iterații sunt necesare. Ciclurile infinite sunt larg utilizate în diverse domenii, cum ar fi programele grafice, jocurile, aplicațiile de rețea ș.a.m.d.

Pentru a crea un ciclu infinit se poate folosi orice tip de ciclu, însă în toate cazurile condiția trebuie să fie întotdeauna adevărată:

// ciclu infinit for – condiția de terminare lipsește
for (;;)
{
}

// ciclu infinit while – condiția este întotdeauna true
while (true)
{
}

// ciclu infinit do-while – condiția este întotdeauna true
do
{
}
while (true);

Totuși, în aceste cazuri, în funcție de situație, poate exista o anumită condiție la care ciclul trebuie să se încheie. În acest caz, pentru ieșirea din ciclu se poate folosi operatorul break. De exemplu, să presupunem că utilizatorul poate introduce numere la nesfârșit, iar programul afișează pătratul fiecărui număr. Dar dacă utilizatorul introduce 0, ieșim din ciclu:

#include <iostream>
  
int main()
{
    int n {};       // pentru introducerea unui număr
    // ciclu infinit
    while(true)
    {
        std::cout << "Enter a number: ";
        std::cin >> n; // Introducem numărul
        // dacă utilizatorul a introdus 0, ieșim din ciclu
        if(n == 0) break; 
        // altfel afișăm pătratul numărului
        std::cout << n * n << std::endl;   
    }
}