break, continue și ieșirea din bucle

Cum ieși dintr-o buclă mai devreme, ce face break într-o buclă imbricată și când e mai bine să nu le folosești deloc.

break

break oprește bucla imediat și trece la instrucțiunea de după ea.

for (int i = 1; i <= n; i++) {
    if (v[i] == x) {
        cout << "găsit pe poziția " << i;
        break;
    }
}

Fără break, bucla ar continua degeaba până la n. Iar dacă x apare de mai multe ori, ar afișa fiecare apariție.

continue

continue sare peste restul corpului și trece direct la pasul următor al buclei.

for (int i = 1; i <= n; i++) {
    if (v[i] < 0) continue;    // sar peste negative
    suma += v[i];
}

Același efect îl obții scriind condiția inversă:

for (int i = 1; i <= n; i++)
    if (v[i] >= 0)
        suma += v[i];

A doua variantă este mai scurtă și mai limpede. continue e util când ai mai multe condiții de eliminat la început și nu vrei să indentezi tot corpul de trei ori.

Atenție la continue într-un while: dacă modificarea contorului este la sfârșitul corpului, continue sare peste ea și bucla devine infinită.

int i = 0;
while (i < n) {
    if (v[i] < 0) continue;    // i nu se mai incrementează niciodată
    suma += v[i];
    i++;
}

Într-un for, pasul se execută oricum, deci problema nu apare.

break în bucle imbricate

break iese numai din bucla în care se află, nu din toate.

for (int i = 1; i <= n; i++) {
    for (int j = 1; j <= m; j++) {
        if (a[i][j] == x) {
            gasit = true;
            break;          // iese doar din bucla lui j
        }
    }
}

Bucla exterioară continuă. Dacă vrei să te oprești de tot, ai nevoie de un indicator testat și în condiția exterioară:

bool gasit = false;
for (int i = 1; i <= n && !gasit; i++)
    for (int j = 1; j <= m && !gasit; j++)
        if (a[i][j] == x) {
            gasit = true;
            linia = i;
            coloana = j;
        }

Aici nu mai e nevoie de niciun break, pentru că oprirea o fac condițiile buclelor. Majoritatea profesorilor preferă varianta aceasta, fiindcă vezi din antet când se oprește bucla, fără să cauți prin corp.

Când merită și când nu

break e potrivit când ai găsit ce căutai și restul buclei nu mai are rost.

break devine o problemă când îl folosești ca să ieși din mijlocul unui corp lung, de la mai multe niveluri de indentare. Atunci nu se mai vede din antet unde se termină bucla, iar la corectare asta contează.

La bac, pe hârtie, un algoritm cu condiție compusă în antet se urmărește mai ușor decât unul cu break-uri împrăștiate. În pseudocod nici nu există break. Așa că, dacă transcrii un algoritm din C++ în pseudocod, trebuie oricum să-l rescrii cu indicator.

Un exemplu complet

Se citește un număr natural n > 1. Să se afișeze cel mai mic divizor al său mai mare decât 1.

#include <iostream>
using namespace std;

int main() {
    int n;
    cin >> n;

    int d = 2;
    while (n % d != 0)
        d++;

    cout << d;
    return 0;
}

Nu are nevoie nici de break, nici de o limită superioară. Bucla se oprește sigur, pentru că în cel mai rău caz d ajunge la n, iar n % n este 0. Dacă răspunsul este chiar n, atunci n este prim.

Exemplul arată că de multe ori break nu e necesar. Dacă poți scrie condiția de oprire în antet, scrie-o acolo.

De reținut

  • break oprește bucla, continue sare la pasul următor.
  • break iese dintr-un singur nivel de imbricare.
  • continue într-un while poate sări peste incrementare, iar bucla devine infinită.
  • Condiția compusă în antet este de obicei mai limpede decât break în corp.
  • În pseudocod nu există break; algoritmul se scrie cu indicator.