Sunteți pe pagina 1din 11

5.

Condiii, expresii logice i structuri de control pentru selecie


Pn acum, instruciunile din programele scrise de noi se executau n ordinea n care erau scrise. S presupunem acum c dorim s verificm validitatea unor date de intrare i apoi s facem un calcul sau s afim un mesaj de eroare, dar s nu le facem pe amndou. Pentru aceasta va trebui s punem o ntrebare i, bazndu-ne pe rspuns, s alegem una sau alta dintre variantele de evoluie a programului. Instruciunea if ne permite s executm instruciunile ntr-o alt ordine dect cea fizic.

5.1

Ordinea de execuie a intruciunilor

La un moment dat, calculatorul se gsete sub controlul unei instruciuni. Dup ce aceast instruciune este executat, controlul este trecut urmtoarei instruciuni. n mod obinuit execuia este secvenial.

Instruciunea 1

Instruciunea 2

Instruciunea 3

Acolo unde dorim ca execuia s nu mai fie secvenial, introducem structuri de control. Atunci cnd vrem ca un program s aleag ntre dou aciuni alternative, folosim o structur de control al seleciei. Vom face o presupunere care poate fi adevrat sau fals. Dac este adevrat, calculatorul execut o intruciune. Dac este fals, execut alt instruciune.

Adevrat

Presupunere

Fals

Instruciunea 1A

Instruciunea 1B

De exemplu, programul poate testa la un moment dat dac un angajat va fi pltit pentru ore suplimentare lucrate. Pentru aceasta, el va testa presupunearea c

Programarea calculatoarelor i limbaje de programare I

angajatul a lucrat mai mult de 40 de ore ntr-o sptmn, iar dac este fals calculeaz suma obinuit.

5.2

Condiii i expresii logice

Pentru a pune o ntrebare n C++, facem o presupunere care poate fi adevrat sau fals. Calculatorul evalueaz presupunearea pentru a constata dac este adevrat sau fals.

Expresii logice
n C++ presupunerile iau forma expresiilor logice sau booleene. O astfel de expresie este alctuit din valori logice i operaii. Datele booleene Versiunile actuale ale limbajului de programare C++ includ un tip de dat numit bool al crui domeniu de valori este format din constantele literale true i false. Exemplu const bool checkValue = true; bool dataOK; dataOK = false; Pentru compatibilitatea cu versiunile mai vechi ale standardului C++ n care acest tip de dat nu exista, valoarea true poate fi, de asemenea reprezentat, de orice valoare nenul, iar false poate fi reprezentat de valoarea 0. Exemplu const bool checkValue = 1; bool dataOK; dataOK = 0; Valorile booleene false sunt tiprite n mod implicit ca valoare 0, iar valorile true sunt tiprite ca valoare 1. Operatorul de inserie n stream << tiprete variabilele de tip bool ca ntregi. Exemplu bool dataOK; dataOK = false; cout << dataOK << endl; 0 Manipulatorul boolalpha seteaz stream-ul de ieire ca s afieze valorile de tip bool prin irurile true i false. Exemplu bool dataOK; dataOK = false; cout << boolalpha << dataOK << endl; false Operatori relaionali Unei variabile booleene i poate fi asignat rezultatul comparrii a dou valori. Exemplu bool maiMicDecat; int i, j; cin >> i >> j; maiMicDecat = ( i < j ); Variabilei maiMicDecat i se asigneaz true cnd i < j. Comparnd dou valori, prespunem c o relaie, de exemplu mai mic dect, exist ntre ele. Dac relaia exist ntr-adevr, presupunerea este adevrat. Dac nu, este fals.

Programarea calculatoarelor i limbaje de programare I

n C++ putem testa urmtoarele relaii: Operator Exemplu Semnificaie relaional == x == y x este egal cu y != x != y x este diferit de y > x > y x este mai mare dect y < x < y x este mai mic dect y >= x >= y x este mai mare sau egal dect y <= x <= y x este mai mic sau egal dect y n C++, rezultatul unei comparaii poate fi true sau false. Exemplu Dac x are valoarea 5 i y are valoarea 10, urmtoarele relaii sunt adevrate: x == 5 x != y y > x x < y y >= x x <= y Dac x este M i y este R, expresiile de mai sus sunt de asemenea true deoarece sunt comparate codurile ASCII ale caracterelor. n acest cod, literele mari sunt aezate inaintea celor mici. Exemplu M < R i m < r sunt true m < R este false Trebuie s fim ateni la tipurile de dat ale valorilor pe care le comparm. Cel mai sigur este s comparm int cu int, double cu double etc. Dac nu, apar forrile implicite de tip. Ca i n cazul expresiilor aritmetice, cel mai sigur, n aceste situaii este s folosim cast explicit pentru a ne face inteniile cunoscute: nrDouble >= double(nrInt) sau nrDouble >= static_cast<double>(nrInt) De asemenea, valorile char trebuie comparate doar cu valori char. Exemplu 0 < 9 sau 0 < 9 sunt corecte 0 < 9 se realizeaz cu o forare de tip i rezultatul nu este cel ateptat Se pot folosi operatori relaionali nu doar pentru a compara valori ale variabilelor sau constantelor, ci i pentru a compara valori ale expresiilor aritmetice. Exemplu Dac avem int x = 17, y = 2; atunci urmtoarea expresie este adevrat: x + 3 == y * 10 O eroare des ntlnit n scrierea programelor C++ este confuzia ntre operatorii = i ==. Folosirea operatorului == pentru asignare sau a operatorului = pentru a testa egalitatea sunt erori logice.

Programarea calculatoarelor i limbaje de programare I

Operatori logici n matematic, operatorii logici AND, OR i NOT acioneaz asupra expresiilor logice care joac rolul de operanzi. C++ folosete simboluri speciale pentru fiecare dintre aceti operatori. Operator logic Exemplu Semnificaie && x && y AND logic || x || y OR logic ! !x NOT logic Pentru ca rezultatul operaiei AND (&&) s fie true, ambii operanzi trebuie s fie true. Tabelul de adevr pentru operatorul && este: Expresia 1 Expresia 2 Expresia 1 && Expresia 2 false false false false true false true false false true true true Operaia OR (||) cere ca cel puin un operand s fie true pentru ca rezultatul s fie true. Tabelul de adevr pentru operatorul || este: Expresia 1 Expresia 2 Expresia 1 || Expresia 2 false false false false true true true false true true true true Operatorul NOT (!) precede o singur expresie logic i d un rezultat opus valorii logice a expresiei. Tabelul de adevr pentru operatorul ! este: Expresia 1 ! Expresia 1 false True true False NOT ne d o metod de a inversa sensul unei presupuneri. Exemplu !(oreLucrate > 40) este echivalent cu oreLucrate <= 40 n unele expresii prima form este mai clar, n altele cea de-a doua. Exemple Conform regulilor lui De Morgan avem: !( a == b ) a != b !( a == b || a == c ) a != b && a != c !( a == b && c > d ) a != b || c <= d

Evaluri condiionale
Evaluarea expresiilor logice se face de la stnga la dreapta, aceasta oprindu-se atunci cnd este cunoscut valoarea ntregii expresii. ntrebarea care se pune este cum poate calculatorul s tie dac valoarea unei expresii este true sau false dac nu a evaluat-o pn la capt. O operaie AND este true dac ambii operanzi sunt true. Dac n expresia i == 1 && j > 2 i are valoarea 10, subexpresia din stnga va fi false, deci expresia nu mai poate avea dect valoarea false.

Programarea calculatoarelor i limbaje de programare I

Evaluarea unei expresii OR se oprete cnd una dintre subexpresii este true, deci rezultatul este true.

Precedena operatorilor
Am discutat despre precedena operatorilor n evaluarea expresiilor aritmetice. Regulile de preceden se aplic i operatorilor logici i relaionali. Lista operatorilor i precedena lor este urntoarea: Cea mai nalt preceden ( ) ! * / % + < <= > >= == != && || = Cea mai sczut preceden Parantezele rotunde au prioritate asupra oricrei operaii. Acestea trebuie folosite ntotdeauna n pereche.

Operatori relaionali pentru tipuri reale


Operatorii relaionali pot fi folosii pentru orice tipuri de dat. Vom prezenta cazul valorilor double. Ca regul general, nu studiai egalitatea a dou numere reale pentru c, datorit micilor erori care apar la calculele cu numere reale, dou astfel de valori nu sunt ntotdeauna egale. Pentru instruciunile float oTreime, x; oTreime = 1.1 / 3.0; x = oTreime + oTreime + oTreime; Ne ateptm ca x s aib valoarea 1.1, dar probabil c nu va fi aa. Prima asignare 1 va stoca n variabila oTreime o aproximare lui , probabil 0.366667. Cea de-a 3 doua asignare va stoca in variabila x o valoare egal cu 3*0.366667. Dac vom compara x cu 1.1 rezultatul va fi false. Diferena dintre valorile lui x i 1.1 este un numr foarte mic, de exemplu 2.38419e-008. n loc s testm egalitatea, putem considera c, dac diferena dintre cele dou numere este foarte mic, putem considera c numerele sunt egale. Putem nlocui testul de egalitate cu fabs(x-1.1) < 0.00001

5.3

Instruciunea if

Am vzut cum se scriu expresiile logice, vom vedea acum cum putem afecta fluxul secvenial al programului. Instruciunea if permite ramificarea fluxului normal. Putem pune o ntrebare i n funcie de condiiile existente putem realiza o aciune sau alta.

Programarea calculatoarelor i limbaje de programare I

Structura IF-THEN-ELSE
n C++ instruciunea if poate fi folosit n dou variante: forma IF-THEN-ELSE sau forma IF-THEN. O vom analiza mai nti pe prima. Sintaxa formei IF-THEN-ELSE este if(expresie) Instruciunea 1A else Instruciunea 1B Expresia din paranteze poate avea orice tip simplu de dat. Aproape ntotdeauna aceasta va fi o expresie logic. Dac valoarea expresiei este nenul sau true, calculatorul execut Instruciunea 1A. Dac valoarea expresiei este 0 sau false, se execut Instruciunea 1B. Instruciunea 1A se numete clauza then, iar Instruciunea 1B se numete clauza else. if (expresie)
false true

Instruciunea 1A Instruciunea 1B

Instruciunea 2 De notat c instruciunea if folosete doar cuvintele rezervate if i else, chiar dac structura se numete IF-THEN-ELSE. Exemple if(oreLucrate <= 40) plata = sumaPeOra * oreLucrate; else plata = sumaPeOra * (40.0 + (oreLucrate 40.0) * 1.5); cout << plata; n limbaj natural, aceast instruciune spune urmtorul lucru: Dac numrul de ore lucrate este mai mic sau egal dect 40, atunci calculeaz suma obinuit de plat i apoi treci la instruciunea de tiprire. Dac numrul de ore lucrare este mai mare dect 40, atunci calculeaz suma normal i suma suplimentar , apoi treci la instruciunea de tiprire.

Blocuri
Pentru a evita mprirea la zero ntr-o expresie, s presupunem c atunci cnd numitorul este egal cu 0 facem dou lucruri: tiprim un mesaj de eroare i ncrcm valoarea 9999 n variabila rezultat. Trebuie, aadar, s realizm dou instruciuni pe aceeai ramur, ns sintaxa instruciunii if ne limiteaz la una singur. S ne amintim c orice compilator C++ trateaz blocul { ... } ca o singur instruciune. Folosind o pereche de acolade pentru a ncadra secvena de instruciuni, instruciunile vor deveni un singur bloc.

Programarea calculatoarelor i limbaje de programare I

Exemplu if(numitor != 0) rezultat = numarator / numitor; else { cout << Impartirea la 0 nu este permisa. << endl; rezultat = 9999; } Putem folosi blocuri de instruciuni pe ambele ramuri ale unui IF-THEN-ELSE. Exemplu if(numitor != 0) { rezultat = numarator / numitor; cout << Impartirea este realizata corect. << endl; } else { cout << Impartirea la 0 nu este permisa. << endl; rezultat = 9999; } Dup acolada care nchide blocul nu se pune niciodat semnul ;

Forma IF-THEN
Uneori dorim s realizm o aciune cnd se ndeplinete o condiie, dar s nu se ntmple nimic atunci cnd condiia este fals. Putem lsa ramura else vid. Exemplu if(a <= b) c = 20; else ; Mai simplu, putem s nu scriem deloc ramura else. Ajungem, astfel, la forma IF-THEN: if(Expresie) Instruciune Putem rescrie instruciunea din exemplul anterior astfel: if(a <= b) c = 20; Ca i la forma IF-THEN, ramura din IF-THEN poate fi un bloc de instruciuni. S presupunem c avem de completat un formular pentru efectuarea unei pli. Conform instruciunilor, linia 23 din formular trebuie sczut din linia 17, iar rezultatul trebuie trecut pe linia 24. Dac rezultatul este negativ, pe linia 24 se trece rezultatul 0 i se bifeaz csua 24A. n C++ aceast cerin se implementeaz astfel: rezultat = linia17 linia23; if( rezultat < 0.0 ) { cout << Bifeaza casuta 24A << endl; rezultat = 0.0; } linia24 = rezultat; Ce se ntmpl dac uitm s folosim acoladele?

Programarea calculatoarelor i limbaje de programare I

rezultat = linia17 linia23; if( rezultat < 0.0 ) cout << Bifeaza casuta 24A << endl; rezultat = 0.0; linia24 = rezultat; n ciuda inteniilor noastre, compilatorul trateaz clauza then ca una cu o singur instruciune. Dac rezultatul este negativ, calculatorul execut instruciunea de afiare, seteaz rezultatul cu 0 i apoi l pstreaz n linia24. Pn acum totul este bine. Dac rezultatul este pozitiv, calculatorul ignor clauza then i execut urmtoarea instruciune dup instruciunea if. De aceea, rezultatul este setat cu 0, ceea ce contravine inteniilor noastre. Concluzia este c alinierea instruciunilor nu influeneaz n niciun fel compilatorul.

Instruciuni if imbricate
Nu exist restricii asupra tipului de instruciuni pe care le poate conine o ramur a unui if. Prin urmare, o ramur a unui if poate conine un alt if. Cnd folosim o astfel de construcie, spunem c am creat o structur de if imbricat. IF azi este smbt sau duminic IF plou Rmi n cas ELSE Iei la plimbare ELSE Mergi la coal n general, orice problem care implic multi-ramificare poate fi codat prin instruciuni if imbricate. Pentru a afia numele unei zile din sptmn putem folosi o serie de instruciuni if neimbricate. Exemplu if(zi == 1) cout << Luni; if(zi == 2) cout << Marti; if(zi == 3) cout << Miercuri; if(zi == 4) cout << Joi; if(zi == 5) cout << Vineri; if(zi == 6) cout << Sambata; if(zi == 7) cout << Duminica; Acest cod poate fi rescris cu instruciuni if imbricate. Exemplu if(zi == 1) cout << Luni; else 8

Programarea calculatoarelor i limbaje de programare I

if(zi == 2) cout << Marti; else if(zi == 3) cout << Miercuri; else if(zi == 4) cout << Joi; else if(zi == 5) cout << Vineri; else if(zi == 6) cout << Sambata; else if(zi == 7) cout << Duminica; Este mult mai eficient aceast variant pentru c implic mai puine comparaii. Structura care implementeaz ramificarea multipl se numete IF-THENELSE-IF. Putem realinia structura de mai sus pentru a evita deplasarea continu spre dreapta datorit alinierilor convenite. Exemplu if(zi == 1) cout << Luni; else if(zi == 2) cout << Marti; else if(zi == 3) cout << Miercuri; else if(zi == 4) cout << Joi; else if(zi == 5) cout << Vineri; else if(zi == 6) cout << Sambata; else if(zi == 7) cout << Duminica;

Folosirea greit a lui else


La folosirea instruciunilor if imbricate pot aprea confuzii n legtur cu perechile if-else: crui if i aparine un else? S presupunem c dac nota unui student este mai mic dect 5 dorim s tiprim Respins, dac nota lui este ntre 5 i 6 s tiprim Admis, iar dac nota este mai mare dect 6 s nu tiprim nimic. Putem coda aceast problem astfel: if(media < 6.0) if(media < 5.0) cout << "Respins" << endl; else cout << "Admis" << endl; Cum tim crui if i aparine un else? O regul din C++ spune c, n absena acoladelor, un else este asociat ntotdeauna instruciunii if cea mai apropiat care

Programarea calculatoarelor i limbaje de programare I

nu are nc un else drept pereche. Noi obinuim s aliniem codul astfel nct s reflectm aceast mperechere. Ne propunem s rescriem codul de mai sus n aa fel nct instruciunea else s fie asociat primului if. if(media < 6.0) if(media < 5.0) cout << "Respins" << endl; else cout << "Admis" << endl; Aceast versiune nu rezolv problema aa cum dorim noi pentru c simpla aliniere a instruciunilor nu este suficient. Conform regulii, ultimul else va fi mperecheat cu al doilea if. Pentru o soluie corect, plasm cel de-al doilea if ntr-un bloc de instruciuni. if(media < 6.0) { if(media < 5.0) cout << "Respins" << endl; } else cout << "Admis" << endl; Perechea de acolade indic faptul c cea de-a doua instruciune if este complet, iar else trebuie s aparin primului if.

5.4

Testarea strii stream-urilor de intrare / ieire

n capitolul trecut am prezentat conceptul de stream de intrare i de stream de ieire n C++. Am artat c sunt situaii n care un stream poate intra in fail state: - date de intrare invalide; - tentativa de a citi un fiier dincolo de EOF; - intenia de a deschide pentru citire un fiier inexistent. C++ ofer un mecanism de a determina cnd un stream este in fail state. n expresii logice se poate folosi efectiv numele stream-ului ca i cum ar fi o variabil boolean. Exemple if(cin) ... if(!inFile) ... La testarea strii unui stream rezultatul poate fi nenul, adic ultima operaie I/O asupra stream-ului a avut succes sau nul, cnd ultima operaie I/O asupra streamului a euat.

5.5

Proiectarea orientat pe obiecte

Proiectarea este etapa care trebuie parcurs n procesul de dezvoltare a unui proiect cu scopul de a depi bariera pe care o impune complexitatea sa. O metod de proiectare ne ajut s mprim proiectul n module de dimensiuni mai mici, care pot fi rezolvare mai uor. Proiectarea orientat pe obiecte este una dintre metodele de proiectare a aplicaiilor, fiecare avnd propriile avantaje i dezavantaje. n proiectarea orientat

10

Programarea calculatoarelor i limbaje de programare I

pe obiecte problemele sunt modelate prin obiecte. Acestea se caracterizeaz prin comportament, adic realizeaz aciuni i prin stri care se modific prin aciuni. Exemplu Un autoturism poate fi tratat ca un obiect. Acesta are o stare n care prespunem c motorul este pornit i un comportament - pornirea autoturismului - care i schimb starea din motor oprit n motor pornit.

Abstractizarea
n proiectarea orientat pe obiecte, complexitatea problemelor este tratat prin abstractizare. Abstractizarea nseamn eliminarea elementelor nerelevante i amplificarea elementelor eseniale. Un exemplu de abstractizare este descrierea funcionrii unui autoturism. Dorim s nvm pe cineva s conduc autoturismul folosindu-ne de abstractizare. Amplificm elementele eseniale nvndu-l pe elevul nostru cum se pornete maina i cum se mnuiete volanul. Eliminm detaliile legate de funcionarea motorului i nu i vom spune c, pentru ca maina s funcioneze, combustibilul este pompat din rezervor ctre motor unde printr-o scnteie acesta se aprinde, are loc o mic explozie care mpinge un piston care, la rndul su, face ca motorul s se mite. Problemele au, n general, mai multe nivele de abstractizare. Putem discuta despre un autoturism din punctul de vedere al oferului, plasndu-ne la un nivel nalt de abstractizare. Atunci cnd vom discuta cu un mecanic auto, acesta va avea nevoie de informaii detaliate despre funcionarea motorului sau a instalaiei electrice i atunci ne vom afla la un nivel mai sczut de abstractizare, devenind puin mai concrei. Se poate vorbi, totui, despre abstractizare i la nivelul mecanicului auto. Mecanicul testeaz sau ncarc bateria automobilului fr s se uite n interiorul acesteia, acolo unde au loc reacii chimice complexe. Pe de alt parte, un proiectant al bateriei este interesat de aceste detalii, dar nu i de modul n care curentul generat de baterie face ca aparatul de radio s funcioneze. Observm astfel c putem analiza detalii cum ar fi proiectarea bateriei sau a aparatului de radio. Analiza se face pe module care pot fi mai uor de descris, dar prin abstractizare i ignorarea detaliilor putem s privim ntregul autoturism ca un modul.

11