Implementarea structurilor de control


    Algoritmul proiectat pentru rezolvarea unei anumite probleme trebuie implementat intr-un limbaj de programare; prelucrarea datelor se realizeaza cu ajutorul instructiunilor. Instructiunea descrie un proces de prelucrare pe care un calculator il poate executa. O instructiune este o constructie valida (care respecta sintaxa limbajului) urmata de ; . Ordinea in care se executa instructiunile unui program defineste asa-numita structura de control a programului.

Limbajele moderne sunt alcatuite pe principiile programarii structurate. Conform lui C. Bohm si G. Jacobini, orice algoritm poate fi realizat prin combinarea a trei structuri fundamentale:

  •  structura secventiala;
  •  structura alternativa (de decizie, de selectie);
  •  structura repetitiva (ciclica).

  •   IMPLEMENTAREA STRUCTURII  SECVENTIALE

        Structura secventiala este o insiruire de secvente de prelucrare (instructiuni), plasate una dupa alta, in ordinea in care se doreste executia acestora.

    Reprezentarea structurii secventiale cu ajutorul pseudocodului:

    instr1;
    instr2;
    . . . . .
    Implementarea structurii secventiale se realizeaza cu ajutorul instructiunilor:
             Instructiunea vida
                Sintaxa: ;
    Instructiunea vida nu are nici un efect. Se utilizeaza in constructii in care se cere prezenta unei instructiuni, dar nu se executa nimic (de obicei, in instructiunile repetitive).

    Exemple:
    int a;
    . . . . . .
    int j;
      ;
    for (;;)
    {
    . . . .
    }

     Instructiunea expresie
     Sintaxa:
        expresie;
     sau:
       apel_functie;

    Exemple:
    int b, a=9;
    double c;
    b=a+9;
    cout<<a;
    c=sqrt(a);
    clrcsr();//apelul functiei predefinite care sterge ecranul; prototipul in headerul conio.h

     Instructiunea compusa (instructiunea bloc)
     Sintaxa: {
        declaratii;
    instr1;
        instr2;
        . . . .
       }
    Intr-un bloc se pot declara si variabile care pot fi accesate doar in corpul blocului. Instructiunea bloc este utilizata in locurile in care este necesara prezenta unei singure instructiuni, insa procesul de calcul este mai complex, deci trebuie descris in mai multe secvente.

    IMPLEMENTAREA STRUCTURII DE DECIZIE (ALTERNATIVE, DE SELECTIE)

    Reprezentarea prin schema logica si prin pseudocod a structurilor de decizie si repetitive sunt descrise in capitolul 1. Se vor prezenta in continure doar instructiunile care le implementeaza.

     Instructiunea if:

    Sintaxa:

    if (expresie)
        instructiune1;
     [ else
         instructiune2; ]

    Ramura else este optionala.
    La intalnirea instructiunii if, se evalueaza expresie (care reprezinta o conditie) din paranteze. Daca valoarea expresiei este 1, sau diferita de 0 (conditia este indeplinita) se executa instructiune1; daca valoarea expresiei este 0 (conditia nu este indeplinita), se executa instructiune2. Deci, la un moment dat, se executa doar una dintre cele doua instructiuni: fie instructiune1, fie instructiune2. Dupa executia instructiunii if se trece la executia instructiunii care urmeaza acesteia.

    Observatii:
    1. Instructiune1 si instructiune2 pot fi instructiuni compuse (blocuri), sau chiar alte instructiuni if (if-uri imbricate).
    2. Deoarece instructiunea if testeaza valoarea numerica a expresiei (conditiei), este posibila prescurtarea: if (expresie), in loc de if (expresie != 0).
    3. Deoarece ramura else a instructiunii if este optionala, in cazul in care aceasta este omisa din secventele if-else imbricate, se produce o ambiguitate. De obicei, ramura else se asociaza ultimei instructiuni if.
    Exemplu:
     if (n>0)
      if (a>b)
       z=a;
      else z=b;
    4. Pentru claritatea programelor sursa se recomanda alinierea instructiunilor prin utilizarea tabulatorului orizontal.
    5. Deseori, apare constructia:

     if (expresie1)
           instructiune1;
     else
            if (expresie2)
                 instructiune2;
            else
                 if (expresie3)
                      instructiune3;
                    . . . . . . . . .
                          else
                               instructiune_n;
     

    Aceeasi constructie poate fi scrisa si astfel:
     if (expresie1)
          instructiune1;
     else if (expresie2)
          instructiune2;
     else if (expresie3)
          instructiune3;
     . . . . .. . . . . .
     else
          instructiune_n;
    Expresiile sunt evaluate in ordine; daca una dintre expresii are valoarea 1, se executa instructiunea corespunzatoare si se termina intreaga inlantuire. Ultima parte a lui else furnizeaza cazul cand nici una dintre expresiile 1,2,. . ., n-1 nu are valoarea 1.
    6. In cazul in care instructiunile din cadrul if-else  sunt simple, se poate folosi operatorul conditional.

    Exercitii:
    1. Sa se citeasca de la tastatura un numar real. Daca acesta se afla in intervalul [-1000, 1000], sa se afiseze 1, daca nu, sa se afiseze -1.
    #include <iostream.h>
       int main()
         {
     double nr; cout<<”Astept numar:”; cin>>nr;
     int afis = (nr>= -1000 && nr <= 1000 ? 1 : -1); cout<<afis;
     /* int afis;
    if (nr >= -1000 && nr <= 10000)
      afis = 1;
        else afis= -1;
     cout<<afis; */
         return 0;
    }

    Uneori, constructia if-else este utilizata pentru a compara valoarea unei variabile cu diferite valori constante, ca in programul urmator:

    2. Se citeste un caracter reprezentand un operator aritmetic binar simplu. In functie de caracterul citit, se afiseaza numele operatiei pe care acesta o poate realiza.
    #include <iostream.h>
    int main()
    {
    char oper;
    cout<<”Introdu operator aritmetic, simplu, binar:”; cin>>oper;
    if (oper == ’+’)
     cout<<”Operatorul de adunare!\n”;
    else if (oper==’-’ )
     cout<<”Operatorul de scadere!\n”;
    else if (oper==’*’ )
     cout<<”Operatorul de inmultire!\n”;
    else if (oper==’/’ )
     cout<<”Operatorul de impartire!\n”;
    else if (oper==’%’ )
     cout<<”Operatorul rest!\n”;
    else cout<<”Operator ilegal!!!\n”;
         return 0;
    }

     Instructiunea switch
    In unele cazuri este necesara o decizie multipla speciala. Instructiunea switch permite acest lucru.

    Reprezentare prin pseudocod:

    Daca expresie=expr_const_1
     instructiune1;
     [iesire;]
    Altfel daca expresie=expr_const_2
     instructiune2;
     [iesire;]
    ............................................

    Altfel daca expresie=expr_const_n-1
     instructiune_n-1;
     [iesire;]
    Altfel instructiune_n;
     

    Se testeaza daca valoarea pentru expresie este una dintre constantele specificate (expr_const_1, expr_const_2, etc.) si se executa instructiunea de pe ramura corespunzatoare. In schema logica test_expresie este una din conditiile: expresie=expr_const_1, expresie=expr_const_2, etc.
    Sintaxa:
    switch (expresie)
    {
    case expresie_const_1:  instructiune_1;
        [break;]
    case expresie_const_2:  instructiune_2;
        [break;]
    . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
    case expresie_const_n-1:  instructiune_n-1;
        [break;]
    [ default: instructiune_n; ]
    }

        Este evaluata expresie (expresie aritmetica), iar valoarea ei este comparata cu valoarea expresiilor constante 1, 2, etc. (expresii constante=expresii care nu contin variabile). In situatia in care valoarea expresie este egala cu valoarea expr_const_k, se executa instructiunea corespunzatoare acelei ramuri (instructiune_k). Daca se intalneste instructiunea break, parcurgerea este intrerupta, deci se va trece la executia primei instructiuni de dupa switch. Daca nu este intalnita instructiunea break, parcurgerea continua. Break-ul cauzeaza deci, iesirea imediata din switch.
        In cazul in care valoarea expresiei nu este gasita printre valorile expresiilor constante, se executa cazul marcat cu eticheta default (cand acesta exista). Expresiile expresie, expresie_const_1, expresie_const_2,etc., trebuie sa fie intregi. In exemplul urmator, ele sunt de tip char, dar o data de tip char este convertita automat in tipul int.

    Exercitiu:   Sa rescriem programul pentru problema 2, utilizand instructiunea switch.

    #include <iostream.h>
    int main()
    {
     char oper;
     cout<<”Introdu operator aritmetic, simplu, binar:”;
    cin>>oper;
     switch (oper)
     {
      case (’+’):
             cout<<”Operatorul de adunare!\n”;
                  break;
      case (’-’):
            cout<<”Operatorul de scadere!\n”;
                  break;
    case (’*’):
              cout<<” Operatorul de inmultire!\n”;
                     break;
      case (’/’):
            cout<<”Operatorul de impartire!\n”;
                      break;
      case (’%’):
            cout<<”Operatorul rest!\n”;
                      break;
     default:
              cout<<”Operator ilegal!\n”;
            }
         return 0;
    }

    IMPLEMENTAREA STRUCTURILOR REPETITIVE (CICLICE)

    Exista doua categorii de instructiuni ciclice: cu test initial si cu test final.

         Implementarea structurilor ciclice cu test initial

    Structura ciclica cu test initial este implementata prin instructiunile while si for.
     Instructiunea while
    Sintaxa:

     while (expresie)
       instructiune;

    La intalnirea acestei instructiuni, se evalueaza expresie. Daca aceasta are valoarea 1 - sau diferita de 0 - (conditie indeplinita), se executa instructiune. Se revine apoi in punctul in care se evalueaza din nou valoarea expresiei. Daca ea este tot 1, se repeta instructiune, s.a.m.d. Astfel, instructiunea (corpul ciclului) se repeta atat timp cat expresie are valoarea 1. In momentul in care expresie ia valoarea 0 (conditie neindeplinita), se iese din ciclu si se trece la urmatoarea instructiune de dupa while.

    Observatii:
    1. In cazul in care la prima evaluare a expresiei, aceasta are valoarea zero, corpul instructiunii while nu va fi executat niciodata.
    2. Instructiune din corpul ciclului while poate fi compusa (un bloc), sau o alta instructiune ciclica.
    3. Este de dorit ca instructiunea din corpul ciclului while sa modifice valoarea expresiei. Daca nu se realizeaza acest lucru, corpul instructiunii while se repeta de un numar infinit de ori.

    Exemplu:
     int a=7;
     while (a==7)
      cout<<”Buna ziua!\n”; // ciclu infinit; se repeta la infinit afisarea mesajului

     Instructiunea for
    In majoritatea limbajelor de programare de nivel inalt, instructiunea for implementeaza structura ciclica cu numar cunoscut de pasi . In limbajul C instructiunea for poate fi utilizata intr-un mod mult mai flexibil.

    Reprezentare in pseudocod:
    evaluare expresie1
        CAT TIMP expresie2 REPETA
     INCEPUT
             instructiune
             evaluare expresie3
     SFARSIT

    Sintaxa:
    for (expresie1; expresie2; expresie3)
         instructiune;

    Nu este obligatorie prezenta expresiilor, ci doar a instructiunilor vide.
    for ( ; expresie2; )                  sau:                      for ( ; ; )
        instructiune;                                                     instructiune;
     

    Implementarea structurilor ciclice cu test final

    Instructiunea do-while
    Sintaxa:

        do  instructiune;
            while(expresie);

        Se executa instructiune. Se evalueaza apoi expresie. Daca aceasta are valoarea 1, se executa instructiune. Se testeaza din nou valoarea expresiei. Se repeta instructiune cat timp valoarea expresiei este 1 (conditia este indeplinita). In cazul instructiunii do-while, corpul ciclului se executa cel putin o data.

    Exercitii:
    1. Se citeste cate un caracter, pana la intalnirea caracterului @. Pentru fiecare caracter citit, sa se afiseze un mesaj care sa indice daca s-a citit o litera mare, o litera mica, o cifra sau un alt caracter. Sa se afiseze cate litere mari au fost introduse, cate litere mici, cate cifre si cate alte caractere. Se prezinta trei modalitati de implementare (cu instructiunea while, cu instructiunea for si cu instructiunea do-while).

    #include <iostream.h>
    #include <conio.h>
    int main()
    { char c;
    int lmic=0, lmare=0, lcif=0;
    int altcar=0;
    cout<<"Astept car.:"; cin>>c;
     while (c!='@'){
     if (c>='A' && c<='Z') {
      cout<<"Lit. mare!\n";
      lmare++; }
    else if (c>='a' && c<='z') {
      cout<<"Lit. mica!\n";
      lmica++; }
    else if (c>='0' && c<='9') {
      cout<<"Cifra!\n";
    lcif++; }
     else {
    cout<<"Alt car.!\n";
    altcar++; }
     cout<<"Astept car.:";cin>>c;
       }
    cout<<"Ati introdus \n";
    cout<<lmare<<" litere mari, ";
    cout<<lmic<<" litere mici\n";
    cout<<lcif<<" cifre si \n";

    int lmic=0, lmare=0, lcif=0;
    int altcar=0;
    cout<<"Astept caract.:";cin>>c;
    do {
    //corp do-while
       } while (c!='@');
    cout<<"Ati introdus \n";
    //. . .

         Sa se calculeze suma si produsul primelor n numere naturale, n fiind introdus de la tastatura. Se vor exemplifica modalitatile de implementare cu ajutorul instructiunilor do-while, while, si for.

    cout<<"n="; int n; cin>>n;
    int S=0, P=1, k=1;
    while (k <= n){
         S+=k; P*=k;
         k++;
    }
    cout<<"P="<<P<<"\tS="<<S<<'\n';
     

    cout<<"n="; int n; cin>>n;
    int S=0, P=1, k=1;
    do{
     S+=k; P*=k;
     k++;
    } while (k <= n);
    cout<<"P="<<P<<"\tS="<<S<<'\n';
     
     

    int S=0, P=1, k;
    for (k=1; k<=n; k++){
     S+=k; P*=k;
    }
    cout<<"P="<<P<<"\tS=";
    cout<<S<<'\n';

    FACILITATI DE INTRERUPERE A UNEI SECVENTE

    Pentru o mai mare flexibilitate (tratarea exceptiilor care pot apare in procesul de prelucrare), in limbajul C se utilizeaza instructiunile break si continue. Ambele instructiuni sunt utilizate in instructiunile ciclice. In plus, instructiunea break poate fi folosita in instructiunea switch.

     Instructiunea break
    Este utilizata in cadrul instructiunilor ciclice, instructiunea break "forteaza" iesirea din acestea. Fara a se mai testa valoarea expresiei (conditia) care determina repetarea corpului instructiunii ciclice, se continua executia cu instructiunea care urmeaza instructiunii ciclice. Astfel, se intrerupe repetarea corpului instructiunii ciclice, indiferent de valoarea conditiei de test.
    Utilizarea in cadrul instructiunii switch: In situatia in care s-a ajuns la o valoare a unei expresiei constante egala cu cea a expresiei aritmetice, se executa instructiunea corespunzatoare acelei ramuri. Daca se intalneste instructiunea break, parcurgerea este intrerupta (nu se mai compara valoarea expresiei aritmetice cu urmatoarele constante), deci se va trece la executia primei instructiuni de dupa switch. Daca nu este intalnit break, parcurgerea continua. Instructiunea breakl cauzeaza deci, iesirea imediata din switch.

    Instructiunea continue
    Intalnirea instructiunii continue determina ignorarea instructiunilor care o urmeaza in corpul instructiunii ciclice si reluarea executiei cu testarea valorii expresiei care determina repetarea sau nu a corpului ciclului.