Jump to content

[PASCAL] Lectia 3 - Instructiuni conditionale si bucle


Leventhe
 Share

Recommended Posts

Instructiuni conditionale si bucle

 

La inceputurile informaticii, programarea se facea mai mult dupa ureche, programatorul fiind liber sa foloseasca orice structuri oferite de limbajul de programare in care lucra, fara sa tina cont de posibilitatea ca un alt programator ar avea mari dificultati daca ar incerca sa corecteze / dezvolte programul facut de el. Salturile neconditionate (GOTO) si structurile cu mai multe puncte de intrare sau iesire erau un lucru foarte obisnuit.

 

In mai 1966, Bohm si Jacopini au demonstrat ca orice algoritm poate fi compus din numai trei structuri de calcul:

structura secventiala

structura alternativa

structura repetitiva

 

In 1968, Dijkstra a publicat un articol denumit "Un caz impotriva structurii GOTO" (A Case against the GO TO Statement), care de fapt este metodologia a ceea ce astazi numim programare structurata.

 

Programarea structurata este, in conceptia celor mentionati mai sus, cel mai simplu mod de a crea un program care este usor de inteles si usor de corectat / dezvoltat.

 

Sa luam cele trei structuri de mai sus in ordine.

 

Structura secventiala

 

Este cea mai usoara structura intalnita intr-un program. In programul de mai jos (care face suma a doua numere citite de la tastatura) :

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var a, b: integer;

begin

write('Dati a: '); readln(a);

write('Dati b: '); readln(b);

write('Suma celor doua numere este ', a + b);

readln;

end.

, nu intalnim alta structura de calcul decat cea secventiala. Cu asta vreau sa spun ca toate instructiunile vor fi folosite, pe rand, in ordine, fara ca vreuna din instructiuni sa se repete. Suna ca o reteta usoara de mancare, nu ? Exact asa si este.

 

Structura alternativa

 

Este o structura de calcul care permite, in functie de anumite conditii, executarea (sau neexecutarea) unei anumite instructiuni sau secventa de instructiuni. Programul de mai jos vrea sa faca suma a doua numere, in afara de cazul in care primul numar este 0 (zero), caz in care aduna al doilea numar cu el insusi :

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var a, b: integer;

begin

write('Dati a: '); readln(a);

write('Dati b: '); readln(b);

If a <> 0 Then write('Suma celor doua numere este ', a+b)

Else write('Suma celor doua numere este ', b+b);

readln;

end.

 

Deci, am pus o conditie si in functie de ea executam o parte sau alta a codului. Parca suntem in viata. Ne ofera cineva ceva, dar noi nu acceptam decat daca pretul e mai mic sau egal cu o anumita suma, pentru ca altfel ni se pare prea mare pretul.

 

Structura repetitiva

 

Este o structura de calcul care permite, in functie de anumite conditii, executarea unei anumite instructiuni sau secventa de instructiuni de N ori (unde N poate fi 0, 1 sau mai mult). Programul de mai jos citeste doua numere de la tastatura si va aduna primul numar cu el insusi de atatea ori cat e valoarea celui de-al doilea :

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var a, b, suma: integer;

begin

write('Dati a: '); readln(a);

write('Dati b: '); readln(b);

suma := 0;

For b := 1 To b Do

suma := suma + a;

write('Suma este ', suma);

readln;

end.

 

Este simplu, doar adunam valoarea din A de B ori, altfel spus inmultim A cu B. Totusi, scopul acestui program nu e de a face inmultirea, ci de a explica structura repetitiva

 

Aceste trei structuri de calcul s-au dovedit de-a lungul timpul a fi, intr-adevar, singurele strict necesare crearii unui program, motiv pentru care nici nu o sa explic in aceste tutoriale cum se folosesc, in Pascal, salturile neconditionate (desi exista aceasta posibilitate).

 

Instructiuni conditionale

 

Avem la dispozitie doua tipuri de instructiuni conditionale in Pascal: If ... Then ... [Else ... ] si Case.

 

Sa incepem cu inceputul.

 

Structura If ... Then ... [Else ... ]

 

Are doua sintaxe, putin diferite. Cea mai obisnuita este mai jos:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

If conditie

Then instructiune1

Else instructiune2;

 

conditie este o comparatie sau orice altceva care returneaza o valoarea logica (True sau False), cum ar fi suma = 5 ("=" semnifica egalitate, nu atribuire !)

 

instructiune1 si instructiune2 pot fi orice fel de instructiuni, inclusiv instructiunea compusa.

 

Atentie:

In cazul folosirii acestei sintaxe, semnul " ; " (punct si virgula) nu numai ca nu este necesar dupa instructiune1, ci este interzis sa fie pus acolo.

 

 

A doua varianta a acestei structuri conditionale este cea in care nu avem ramura de else :

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

If conditie

Then instructiune1;

 

 

Atentie:

In cazul folosirii acestei sintaxe, semnul " ; " (punct si virgula) este strict necesar dupa instructiune1.

 

 

Sa exemplificam aceste structuri prin programul de mai jos:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var varsta: integer;

sex: char;

begin

write('Ce varsta aveti ? '); ReadLn(varsta);

write('Sunteti baiat sau fata ? (M / F) : '); ReadLn(sex);

 

If (sex = 'f') or (sex = 'F')

Then WriteLn('Sex feminin')

Else WriteLn('Sex masculin');

 

If varsta > 17 Then

WriteLn('Persoana majora');

 

ReadLn;

End.

 

Pentru a intelege programul, sa-l luam pas cu pas. Am definit doua variabile, una de tip integer (valoare numerica) denumita varsta si una de tip Char (un singur caracter) denumita sex.

 

Dupa citirea de la tastatura a valorilor pentru aceste doua variabile, verificam daca variabila sex e cumva litera F. De remarcat ca am folosit operatorul logic OR pentru a verifica daca variabila are valoarea f sau F, ambele insemnand faptul ca sexul este feminin, caz in care afisam acest lucru. Pe ramura de Else, stiind ca sexul nu este feminin, am pus direct afisare ca sexul este masculin, ceea ce nu este tocmai corect. Trebuia facuta o verificare si daca valoarea variabilei sex este m sau M, pentru a asigura acuratetea programului. In programul de mai sus, daca pentru variabila sex introducem litera c, progamul va afisa tot "Sex masculin", dar momentan scopul meu nu e de a crea programe fara bug-uri, ci doar de a va explica modul de functionare a structurilor conditionale.

Pentru varsta facem o singura verificare, anume daca varsta este strict mai mare decat 17 (adica minim 18), caz in care afisam "Persoana majora".

 

Sa refacem programul pentru a lua in calcul si alte cazuri (cum ar fi verificarea pentru sexul masculin, varste negative sau peste 150 de ani )

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var varsta: integer;

sex: char;

begin

write('Ce varsta aveti ? '); ReadLn(varsta);

write('Sunteti baiat sau fata ? (M / F) : '); ReadLn(sex);

 

If (sex = 'f') or (sex = 'F')

Then WriteLn ('Sex feminin')

Else

If (sex = 'm') or (sex = 'M')

Then WriteLn ('Sex masculin')

Else WriteLn ('Sex necunoscut, probabil neutru');

 

If (varsta < 0)

Then WriteLn ('Persoana care este inca in planuri de viitor')

Else

If (varsta < 18)

Then WriteLn ('Persoana minora')

Else

If (varsta < 60)

Then WriteLn ('Persoana majora')

Else

If (varsta < 150)

Then WriteLn ('Persoana in varsta')

Else WriteLn ('Personaj biblic');

 

ReadLn;

End.

 

Dupa cum vedeti, in noul program am luat in calcul ca variabila sex poate reprezenta sex feminin, sex masculin sau un caracter care nu reprezinta nici unul din acestea doua cazuri. Pentru aceasta, am folosit instructiuni conditionale imbricate (adica una in interiorul alteia). Arata urat, nu ? In plus, e si destul de greu de inteles.

Cu toate acestea, pentru variabila varsta am facut chiar si mai multe verificari, folosind multiple instructiuni conditionale imbricate. E deja mai urat si chiar si mai greu de inteles.

Nu am de facut decat sa va recomand multa atentie cand creati sau recititi programul ... si sa va prezint instructiunea conditionala multipla, ca o alternativa la instructiunea If ... Then ... [Else ... ]

 

Structura Case

 

Instructiunea Case, denumita si instructiune alternativa multipla, ofera posibilitatea verificarii unei variabile pe un set mai intins de valori, fara a da dureri de cap la crearea sau recitirea programului.

 

Sintaxa generala:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

Case variabila_simpla Of

val_posibile1 : instructiune1;

val_posibile2 : instructiune2;

...

val_posibileX : instructiuneX;

Else instructiuneY;

End;

 

Sa incercam sa intelegem aceasta sintaxa, care pare a fi ceva mai complicata decat sintaxa instructiunii dinainte.

Variabila_simpla desemneaza orice variabila de un tip simplu de date (vedeti tutorialul anterior). Nu poate fi folosit aici, de exemplu, tipul String, el nefiind un tip simplu de date.

Val_posibile1, Val_posibile2 si Val_posibileX tin locul unei (sau a mai multor) valori posibile pentru variabila_simpla. Daca valoarea variabilei variabila_simpla e egala (sau inclusa) cu vreuna din valorile posibile, atunci va fi executat setul corespunzator de instructiuni.

Instructiune1, instructiune2 si instructiuneX pot fi orice fel de instructiuni, inclusiv cele compuse.

Pe ramura de Else avem acelasi lucru ca si la instructiunea If ... Then ... [Else ... ], adica o anumita instructiune care se executa in cazul in care valoarea variabilei variabila_simpla nu se regaseste in optiunile de mai sus (Val_posibile1, Val_posibile2, Val_posibileX). Aceasta ramura, ca si la If ... Then ... [Else ... ], poate ramane nefolosita.

 

Sa refacem programul de mai sus, folosind aceasta noua instructiune.

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var varsta: integer;

sex: char;

begin

write('Ce varsta aveti ? '); ReadLn(varsta);

write('Sunteti baiat sau fata ? (M / F) : '); ReadLn(sex);

 

Case sex Of

'f','F' : WriteLn('Sex feminin');

'm','M' : WriteLn('Sex masculin');

Else Writeln('Sex necunoscut, probabil neutru');

End;

 

Case varsta Of

0 .. 17 : WriteLn('Persoana minora');

18 .. 60 : WriteLn('Persoana majora');

61 .. 150 : WriteLn('Persoana in varsta');

151 .. maxint : WriteLn('Personaj biblic');

-maxint .. -1 : WriteLn('Persoana care este inca in planuri de viitor');

End;

 

ReadLn;

End.

 

Dupa cum vedeti, e mult mai usor de folosit si este mult mai clara. Singurul lucru care cred ca mai e necesar sa vi-l explic este ce inseamna, 'f','F' si 18 .. 60. Structura Case, dupa cum am explicat anterior, permite ca, pentru o anumita instructiune, sa verificam mai multe valori posibile. Aceste valori pot fi scrise una cate una si despartite prin virgula (cum a fost in cazul variabilei sex) sau pot fi scrise ca un sir de valori, in care se ofera valoarea minima si apoi valoarea maxima, aceste doua valori fiind despartite prin " .. " (doua puncte unul dupa celalalt).

 

Cam asta ar fi toata partea de instructiuni conditionale in Pascal. Sa trecem la ...

 

Bucle (instructiuni repetitive)

 

Buclele (instructiuni de ciclare) sunt niste instructiuni care asigura repetarea pe un anumit numar de pasi a unor anumite instructiuni.

 

Sa ne imaginam ca vrem sa facem un program care sa afiseze crescator, de la 1 la 20, toate numerele. E destul de simplu sa le afisam cu o instructiune Write (sau mai multe). Dar sa presupunem ca vrem sa facem acelasi lucru pana la 1.000 ... sau pana la 1.000.000 ... cred ca sunteti de acord ca ar fi "cam" mult de lucru.

 

Aici apare nevoia de bucla, pentru a repeta un set de instructiuni de un numar dat de ori.

 

In Pascal, sunt trei tipuri de instructiuni de ciclare:

While

Repeat

For

Bucla While

 

Sintaxa generala a acestei instructiuni este:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

While conditie Do instructiune;

 

Conditie poate fi orice comparatie sau orice altceva ce are ca rezultat True sau False. Se poate apela si

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

While True Do instructiune;

, caz in care nu se poate iesi din bucla din cauza conditiei. Daca nu exista in interiorul acestei bucle o instructiune de iesire (Break), atunci bucla va fi infinita (nu va mai iesi din ea, programul se va bloca si va trebui terminat cu Ctrl + Break, sau si mai rau, din Task Manager sau reboot).

In general, conditia va face referire la o conditie care va deveni adevarata, pe masura bucla lucreaza sau este o simpla verificare a unui contor, caz in care putem calcula dinainte exact cate ciclari va face bucla (de cate ori va repeta instructiunile aflate in interior).

 

De remarcat ca iesirea din bucla se va face doar cand conditia va returna valoarea False. E si destul de usor de inteles asta : While conditie Do instructiune care in limbaj natural ar suna Cat timp conditia_mea_e_adevarata Fa ceva.

 

Aceasta instructiune mai este denumita si "instructiune repetitiva cu test initial" (testul de iesire din bucla se face la inceput). Instructiunile din aceasta bucla nu se vor executa nici macar o data, daca testul de iesire returneaza valoarea False de la inceput.

 

Instructiune poate fi orice fel de instructiune, inclusiv instructiunea compusa.

 

Sa vedem cum am putea face in Pascal, folosind bucla While, programul de mai sus care afiseaza pana la 20.

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var cnt : integer;

begin

cnt := 1;

While cnt <= 20 Do

Begin

WriteLn(cnt);

cnt := cnt + 1;

End;

ReadLn;

end.

 

Sa analizam programul. Prima oara am declarat o variabila de tip integer (care poate lua valori intre -32768 si 32767), care va fi ceea ce denumim contorul buclei. Initializam contorul cu 1, aceasta fiind prima valoare ce va trebui afisata, apoi afisam contorul, care apoi va fi marit cu o unitate.

Pe masura ce avansam, ajungem cu Cnt = 20. Ce se va intampla atunci : va fi afisat (20), contorul va fi crescut la 21 si programul va reveni la conditia de la inceputul buclei : este Cnt mai mic sau egal cu 20 ? Evident, nu mai este cazul, motiv pentru care se trece la executarea urmatoarei instructiuni din program, anume ReadLn.

 

Sa vedem cum am putea face programul daca am initializa Cnt cu valoarea 0.

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var cnt : integer;

begin

cnt := 0;

While cnt < 20 Do

Begin

cnt := cnt + 1;

WriteLn(cnt);

End;

ReadLn;

end.

 

Ok, ar trebui sa fie evident. Tot ce am facut a fost sa:

schimb conditia de iesire din bucla, din <= in simplul <

inversez instructiunea de crestere a contorului cu cea de afisare

De ce am facut asta ? In primul rand, trebuia sa inversam instructiunile, fiindca altfel ar fi inceput afisarea cu 0, nu cu 1, cum se cerea. Cealalta modificare se refera la faptul ca in momentul care am afisat 20, trebuie iesit din bucla. Inca un ciclu (determinat de o conditie cnt <= 20 ar rezulta in afisarea lui 21, lucru pe care iar nu-l vrem.

 

Cred ca acum ati inteles cum sta treaba cu While, so ... next one

 

Bucla Repeat

 

Sintaxa general a instructiunii Repeat este:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

Repeat

instructiune;

until conditie;

 

Spre deosebire de While, iesirea din aceasta bucla se face atunci cand valoarea conditiei este True. Pentru o bucla infinita se va folosi:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

Repeat

instructiune;

until False;

 

De remarcat ca instructiune nu e necesar sa fie instructiune compusa. Cu alte cuvinte, nu este necesar sa puneti Begin ... End pentru a delimita bucla, acest lucru fiind facut de Repeat ... Until.

 

Aceasta instructiune mai este denumita si "instructiune repetitiva cu test final" (testul de iesire din bucla se face la sfarsit). Instructiunile din aceasta bucla se vor executa macar o data, daca testul de iesire returneaza valoarea True la prima testare.

 

Sa rescriem programul initial folosind aceasta instructiune.

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var cnt : integer;

begin

cnt := 1;

Repeat

WriteLn(cnt);

cnt := cnt + 1;

Until cnt > 20;

ReadLn;

end.

 

De remarcat conditia de iesire din bucla, care este exact opusul celei folosite in cazul buclei While (desi e destul de simplu de inteles, avand in vedere motivele terminarii fiecarei bucle).

 

Singurul lucru care il am de adaugat (fiindca e destul de usor de inteles, avand in vedere explicatiile anterioare) e faptul ca dupa ce cnt are valoarea 20 si este afisat, va fi crescut cu 1 (devenind 21), caz in care conditia devine adevarata (cnt > 20), motiv pentru care se iese din bucla.

 

Daca am initializa contorul cu 0, programul ar fi asa:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var cnt : integer;

begin

cnt := 0;

Repeat

cnt := cnt + 1;

WriteLn(cnt);

Until cnt >= 20;

ReadLn;

End.

 

Din nou, avem conditia de la While, dar inversata. Cam asta ar fi si Repeat-ul ... easy, nu ?

 

Atentie:

Inversa conditiei > este <=, iar a conditiei < este >=.

 

 

Bucla For

 

Sintaxa generala la For cunoaste 2 cazuri: crescator sau descrescator.

 

Cazul crescator:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

For contor = val_initiala To val_finala Do instructiune;

 

Cazul descrescator:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

For contor = val_initiala DownTo val_finala Do instructiune;

 

Motivul pentru care avem aceasta distinctie e faptul ca nu mai avem direct controlul asupra contorului buclei, acesta fiind crescut / scazut de bucla, scapandu-ne astfel de o grija. Din pacate, in felul acesta nu putem decat sa mergem cu pasi de cate o unitate (crescator sau descrescator). In cazurile While sau Repeat, puteam creste contorul cu cat vroiam noi (am ales sa-l cresc cu 1 doar pentru exemplificare).

 

Dupa cum ati observat, aici nu mai avem nici o conditie de iesire din bucla. Iesirea din aceasta bucla se face in momentul in care val_initiala devine mai mare / mai mica cu o unitate decat val_finala. De asemenea, daca se foloseste sintaxa cu To se sare peste bucla in cazul in care val_initiala este mai mare decat val_finala si invers.

 

De remarcat e faptul ca nu mai trebuie sa initializam contorul inaintea buclei (il initializam, de fapt, direct in bucla).

 

Programul de mai sus, scris cu o bucla For ar arata in felul urmator:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var cnt : integer;

begin

For cnt := 1 To 20 Do

WriteLn(cnt);

ReadLn;

End.

 

Dupa cum vedeti, contorul nu prea mai e in grija noastra (iar unele compilatoare chiar dau eroare daca veti incerca sa-i modificati valoarea in interiorul buclei).

 

Sa incercam acum sa lucram cu varianta descrescatoare pentru a face acelasi program

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var cnt : integer;

begin

For cnt := 20 DownTo 1 Do

WriteLn(20 - cnt + 1);

ReadLn;

End.

 

Ok, programul merge ... dar de ce am pus formula aceea ciudata acolo ? Trebuie sa tineti cont de faptul ca acum contorul merge de la 20, descrescator, spre 1, exact invers de cum ne-am obisnuit, asa ca prima valoare a lui cnt este 20. Pentru prima afisare, daca scadem 20 din 20 si adaugam 1 (ca in formula), ne da 1, exact ce trebuie afisat. Sa incercam pentru cazul in care cnt este 2 ... 20 - 2 + 1 = 19, deci asta e penultimul numar care va fi afisat, ultimul fiind, evident, 20.

 

Instructiuni de control pentru bucle

 

Instructiunea Continue

 

Sa presupunem ca avem o bucla care afiseaza numerele de la 1 la 20, ca si in exemplele de mai sus, dar nu vrem sa afisam numarul 9. Cum putem face acest lucru ?

 

Foarte simplu. Trebuie sa "sarim" peste o executie a buclei, cea in care indexul are valoarea 9, inainte de a afisa numarul. Pentru acest lucru folosim instructiunea Continue.

 

Sa vedem un exemplu, folosind bucla FOR:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var cnt : integer;

begin

For cnt := 1 To 20 Do

begin

if cnt = 9 then

Continue; {daca indexul este egal cu 9, nu executam instructiunea de afisare}

WriteLn(cnt);

end;

ReadLn;

End.

 

Instructiunea Continue sare la urmatorul ciclu al buclei, indiferent ca e vorba de bucla While, Repeat sau For.

 

Instructiunea Break

 

Ce facem daca avem nevoie sa scriem un program care afiseaza numerele de la 1 la 20, dar numai atat timp cat suma numerelor afisate este mai mica decat 35 ?

 

Pentru acest lucru trebuie sa facem o suma, pe care o crestem cu valoarea indexului la fiecare afisare. Aceasta suma o vom verifica inainte de urmatoarea afisare si, daca este mai mai mare sau egala cu 35, folosim instructiunea Break.

 

Sa modificam programul de mai sus pentru un mic exemplu:

LINE NUMBER ON/OFF | EXPAND/CONTRACT | SELECT ALL

var cnt, suma : integer;

begin

suma := 0;

For cnt := 1 To 20 Do

begin

suma := suma + cnt;

if suma >= 35 then

Break; {iesim din bucla}

WriteLn(cnt);

end;

ReadLn;

End.

 

Acest program va afisa numerele de la 1 la 7, inclusiv, fiindca 1 + 2 + ... + 8 = 36.

 

Instructiunea Break opreste bucla din care este apelata. dar nu poate opri decat o singura bucla. Daca aceasta instructiune este folosita in interiorul unei bucle care este imbricata in alta bucla, doar bucla interioara va fi oprita.

 

Sursa: http://www.bitcell.info/tutorial-pascal-lectia-3-instructiuni-conditionale-si-bucle-t19.html?sid=ba5880663f2c18ab18ed300345f06ba8

Edited by Cdorsu
Link to comment
Share on other sites

Guest
This topic is now closed to further replies.
 Share

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.