LABORATORUL 06

Instrucțiuni (2) - structuri repetitive și de salt

Durată: 2 ore Limbaj: C / C++ Precedent: Laboratorul 5 PDF îndrumar EN English version

Structurile repetitive permit executarea unei secvențe de instrucțiuni atât timp cât o condiție rămâne adevărată. Cele trei forme din C/C++ sunt echivalente ca putere de calcul, dar fiecare exprimă mai natural un anumit tip de repetiție.

1Obiectivele lucrării

  • Alegerea buclei potrivite în funcție de problema de rezolvat
  • Înțelegerea diferenței dintre buclele cu test inițial și cele cu test final
  • Construirea corectă a celor trei componente ale instrucțiunii for
  • Utilizarea instrucțiunilor break și continue
  • Identificarea și evitarea buclelor infinite

2Cele trei bucle, comparate

InstrucțiuneTestul condițieiExecuții minimeSe folosește când
whileînainte de corp0numărul de repetări nu este cunoscut dinainte
do-whiledupă corp1corpul trebuie executat măcar o dată (meniuri, validări)
forînainte de corp0numărul de repetări este cunoscut sau se parcurge un interval
while - test înainte condiție? corp ieșire do-while - test după corp condiție? ieșire for - echivalent cu while init; while (cond) { corp; pas; }
Fig. 1 - Diferența de flux între cele trei structuri repetitive

3Instrucțiunile while și do-while

sintaxă
while (expresie)
    instructiune;

do
    instructiune;
while (expresie);          // atentie: punct si virgula obligatoriu aici

La while se testează întâi expresia; dacă este adevărată (nenulă), se execută corpul, apoi se reevaluează. La do-while, corpul se execută înainte de primul test, deci cel puțin o dată, indiferent de condiție.

Condiția trebuie să se poată modificaValoarea expresiei care controlează bucla trebuie schimbată undeva în interiorul corpului. Dacă nu se întâmplă acest lucru, bucla rulează la nesfârșit, iar programul se blochează.

4Instrucțiunea for

structura celor trei componente
for (initializare; conditie; pas)
    instructiune;

for (int i = 0; i < 10; i++) { ... }
      │           │        └── se executa DUPA fiecare iteratie
      │           └─────────── se testeaza INAINTE de fiecare iteratie
      └─────────────────────── se executa O SINGURA DATA, la inceput

Toate cele trei componente sunt opționale. for (;;) este o buclă infinită validă, echivalentă cu while (1).

FormăEfect
for (i = 0; i < n; i++)parcurgere crescătoare clasică
for (i = n - 1; i >= 0; i--)parcurgere descrescătoare
for (i = 0, j = n; i < j; i++, j--)doi indici, folosind operatorul virgulă
for (;;)buclă infinită

5Simulator de bucle

Modificați cei trei parametri și urmăriți tabelul de iterații: de câte ori se execută corpul, ce valori ia contorul și cu ce valoare rămâne după terminarea buclei. Puneți pasul pe 0 pentru a vedea cum se detectează o buclă infinită.

for - tabel de iterații generat automat

6Execuție pas cu pas

Urmăriți cum funcționează continue și break într-o buclă care însumează doar numerele pare, oprindu-se la prima valoare negativă.

break și continue în acțiune

7Instrucțiuni de salt

InstrucțiuneEfectDomeniu de acțiune
breakpărăsește bucla sau switch-ul curentdoar structura cea mai interioară
continuesare la următoarea iterațiedoar bucla cea mai interioară
returnpărăsește funcția, returnând o valoareîntreaga funcție
goto etichetasalt necondiționat la o etichetăîn interiorul aceleiași funcții
exit(cod)termină întreg programultot programul
Despre gotoDeși există în limbaj, goto face codul greu de urmărit și de întreținut. Singura utilizare acceptată în practica modernă este ieșirea rapidă din bucle imbricate adânc, către un punct comun de eliberare a resurselor.
break în bucle imbricateUn break iese doar din bucla interioară. Pentru a părăsi ambele bucle, se folosește un indicator (bool gasit), se scoate codul într-o funcție cu return, sau - rar - goto.

8Erori frecvente

1. Punct și virgulă după for sau while for (i = 0; i < 10; i++); execută bucla de zece ori „în gol", iar blocul de dedesubt se execută o singură dată.
2. Eroarea „off by one" for (i = 0; i <= n; i++) execută n + 1 iterații. La parcurgerea unui tablou cu n elemente, aceasta depășește limita cu o poziție.
3. continue în do-while În do-while, continue sare direct la testul condiției. Dacă incrementarea contorului se afla după continue, ea nu se mai execută și bucla devine infinită.
4. Modificarea contorului în corpul buclei Schimbarea variabilei de control în interiorul lui for face comportamentul greu de urmărit și este o sursă frecventă de bucle care nu se termină.

9Cod sursă

medie.c - while cu număr necunoscut de valori
#include <stdio.h>

int main(void)
{
    int n, i = 0;
    double valoare, suma = 0.0;

    printf("Cate valori? ");
    scanf("%d", &n);

    while (i < n) {
        printf("Valoarea %d: ", i + 1);
        scanf("%lf", &valoare);
        suma += valoare;
        i++;                       // FARA aceasta linie: bucla infinita
    }

    if (n > 0)
        printf("Media aritmetica = %.4f\n", suma / n);
    else
        printf("Nicio valoare introdusa\n");

    return 0;
}
meniu.c - do-while pentru meniu repetat
#include <stdio.h>

int main(void)
{
    int optiune;

    do {
        printf("\n--- MENIU ---\n");
        printf("1. Adauga\n2. Sterge\n3. Afiseaza\n0. Iesire\n");
        printf("Alegeti: ");
        scanf("%d", &optiune);

        switch (optiune) {
            case 1: printf("Ati ales adaugarea\n");  break;
            case 2: printf("Ati ales stergerea\n");  break;
            case 3: printf("Ati ales afisarea\n");   break;
            case 0: printf("La revedere!\n");        break;
            default: printf("Optiune invalida\n");
        }
    } while (optiune != 0);        // meniul se afiseaza macar o data

    return 0;
}
primes.c - for cu break și continue
#include <stdio.h>
#include <math.h>

int estePrim(int n)
{
    if (n < 2) return 0;
    for (int d = 2; d <= (int)sqrt(n); d++)
        if (n % d == 0)
            return 0;              // iesire imediata din functie
    return 1;
}

int main(void)
{
    printf("Numerele prime pana la 50:\n");

    for (int n = 1; n <= 50; n++) {
        if (!estePrim(n)) continue;     // sare peste cele neprime
        printf("%d ", n);
    }
    printf("\n");

    // tabla inmultirii, cu bucle imbricate
    printf("\nTabla inmultirii 1-5:\n");
    for (int i = 1; i <= 5; i++) {
        for (int j = 1; j <= 5; j++)
            printf("%4d", i * j);
        printf("\n");                   // linie noua dupa fiecare rand
    }
    return 0;
}

10Atelier de cod

La bucle, modul Pas cu pas este cel mai util instrument: vedeți contorul crescând și condiția fiind reevaluată la fiecare trecere.

Aceeași problemă, trei feluri de bucle
#include <stdio.h>

int main(void)
{
    int i, s;

    s = 0;
    for (i = 1; i <= 5; i++) s += i;
    printf("cu for       : 1+2+3+4+5 = %d\n", s);

    s = 0; i = 1;
    while (i <= 5) { s += i; i++; }
    printf("cu while     : 1+2+3+4+5 = %d\n", s);

    s = 0; i = 1;
    do { s += i; i++; } while (i <= 5);
    printf("cu do-while  : 1+2+3+4+5 = %d\n", s);

    printf("\nTabla lui 7:\n");
    for (i = 1; i <= 10; i++)
        printf("  7 x %2d = %3d\n", i, 7 * i);
    return 0;
}
Exercițiu - numere prime până la N
#include <stdio.h>

int main(void)
{
    int n, i, d, prim;

    printf("N = ");
    scanf("%d", &n);

    printf("Numerele prime pana la %d:\n", n);
    for (i = 2; i <= n; i++) {
        prim = 1;

        /* Completati: verificati daca i are vreun divizor
           intre 2 si i/2. Daca are, puneti prim = 0 si iesiti
           din bucla interioara cu break. */

        if (prim) printf("%d ", i);
    }
    printf("\n");
    return 0;
}

11Sarcini de lucru

  • Calculați media aritmetică a N valori citite de la tastatură, folosind while.
  • Rescrieți același program cu for și apoi cu do-while; comparați lizibilitatea.
  • Implementați un meniu repetitiv care se închide doar la alegerea opțiunii 0.
  • Afișați toate numerele prime până la 100, folosind continue.
  • Generați tabla înmulțirii cu bucle imbricate și aliniere pe coloane.
  • Calculați suma cifrelor unui număr introdus, folosind while.
  • Reproduceți eroarea „off by one" la parcurgerea unui tablou și observați ce se afișează.
  • Scrieți o buclă care caută o valoare într-o matrice și iese din ambele bucle la prima potrivire.

12Aplicație de aprofundare

ExtindereScrieți un program care afișează un triunghi al lui Pascal cu N linii, aliniat corect (fiecare linie centrată față de cea de dedesubt). Folosiți doar bucle, fără tablouri bidimensionale - calculați fiecare coeficient binomial din cel precedent, prin înmulțire și împărțire succesivă. Verificați până la ce valoare a lui N rezultatele rămân corecte, înainte de depășirea tipului int.

13Întrebări de verificare

14Resurse