Structuri de control în limbajul de programare
Implementarea structurilor algoritmice fundamentale în limbajul de programare ales.
Evaluarea Națională
Instrucțiunea if-else: decizia în cod
Instrucțiunea if este traducerea în C++ a structurii alternative din pseudocod:
- if (conditie) instructiune; — instrucțiunea se execută doar dacă condiția e adevărată;
- if (conditie) instructiune1; else instructiune2; — se execută exact una dintre cele două ramuri.
Reguli care se verifică la teste:
- Condiția stă obligatoriu între paranteze rotunde: if x > 5 este eroare de sintaxă; corect este if (x > 5).
- Dacă pe o ramură vrei mai multe instrucțiuni, le grupezi între acolade { }. Fără acolade, de ramură aparține doar prima instrucțiune — restul se execută mereu, indiferent de condiție. Aceasta e una dintre cele mai frecvente erori de logică: indentarea frumoasă te păcălește vizual, dar compilatorul ține cont doar de acolade.
- Nu se pune punct și virgulă imediat după condiție: if (x > 5); { ... } face ca ramura să fie instrucțiunea vidă, iar blocul de după acolade să se execute întotdeauna.
if-urile imbricate: un if poate sta în interiorul altui if. Regula de aur: else se leagă de cel mai apropiat if care nu are deja un else. Când vrei altă asociere, folosești acolade ca să delimitezi explicit blocurile.
Lanțul if – else if – else tratează mai multe cazuri exclusive (de exemplu: notă sub 5 → corigent; între 5 și 9 → promovat; 10 → excelent), verificându-le în ordine și oprindu-se la primul caz adevărat.
Instrucțiunea switch: alegerea multiplă
Când o variabilă întreagă sau de tip caracter trebuie comparată pe rând cu mai multe valori fixe, lanțul de if-else devine greoi. C++ oferă instrucțiunea switch (case of în Pascal):
switch (x) { case 1: ...; break; case 2: ...; break; default: ...; }
Cum funcționează: valoarea lui x este comparată cu fiecare case; la prima potrivire, execuția sare acolo și continuă de la acel punct. Ramura default se execută când nicio valoare nu se potrivește — este echivalentul lui else.
Detaliul care face diferența la punctaj: break. Fără break la finalul unui case, execuția NU se oprește, ci cade în cazul următor (fenomenul fall-through) și execută și instrucțiunile acestuia. Dacă x este 1 și case 1 nu are break, se execută și instrucțiunile de la case 2. Uitarea lui break este o eroare de logică clasică — programul compilează perfect.
Limitări de reținut:
- switch funcționează doar cu valori întregi sau caractere — nu cu numere reale și nu cu intervale;
- case 1..5 nu există în C++: pentru condiția „x între 1 și 5” folosești if (x >= 1 && x <= 5);
- valorile din case trebuie să fie constante, nu variabile sau expresii cu variabile.
Când ai de ales: valori fixe și puține → switch e mai citeț; condiții cu intervale sau comparații complexe → obligatoriu if-else.
Instrucțiunea while: repetarea cu test inițial
while (conditie) { ... } este bucla cu test inițial: condiția se evaluează înaintea fiecărei iterații, iar corpul se execută doar cât timp condiția rămâne adevărată.
Consecința esențială: dacă la prima evaluare condiția este falsă, corpul nu se execută deloc — zero iterații. Un while (n < 0) cu n citit pozitiv se sare complet.
Anatomia unei bucle while corecte are trei elemente, toate obligatorii:
- inițializarea variabilelor de control, înainte de buclă (i = 1;);
- condiția de continuare (i <= n);
- actualizarea variabilei de control, în corpul buclei (i++;).
Dacă lipsește actualizarea, condiția nu se schimbă niciodată și obții o buclă infinită — programul „îngheață”. La probele practice, aceasta este cauza numărul unu pentru care un program nu afișează nimic.
while este alegerea firească atunci când nu știm dinainte de câte ori repetăm: prelucrarea cifrelor unui număr (while (n != 0) { ... n /= 10; }), citirea unor valori până la întâlnirea unui zero, înjumătățirea repetată a unui număr.
Pentru întrebările de tip „de câte ori se execută corpul buclei?”, metoda sigură rămâne tabelul de urmărire: notezi valorile variabilelor la fiecare iterație și numeri rândurile. Estimarea „din ochi” duce aproape mereu la greșeli de tip ±1 (off-by-one): bucla while (i < n) cu i pornind de la 1 face n-1 pași, nu n.
Instrucțiunea for: repetarea cu contor
Când numărul de repetări este cunoscut, folosim for, care adună la un loc cele trei elemente ale buclei:
for (i = 1; i <= n; i++) { ... }
Între parantezele rotunde stau, despărțite prin punct și virgulă: inițializarea (se execută o singură dată, la început), condiția de continuare (se verifică înaintea fiecărei iterații) și pasul (se execută după fiecare iterație). Ordinea reală de execuție: inițializare → condiție → corp → pas → condiție → corp → pas → ... până când condiția devine falsă.
De reținut:
- for este doar o scriere compactă a unui while echivalent — tot buclă cu test inițial este, deci poate face și zero iterații: for (i = 5; i < 3; i++) nu execută corpul niciodată;
- contorul poate să și scadă: for (i = n; i >= 1; i--) parcurge valorile în ordine descrescătoare;
- pasul poate fi diferit de 1: for (i = 0; i <= 100; i += 5);
- numărul de iterații pentru for (i = a; i <= b; i++) este b - a + 1 — acel +1 se uită sistematic: de la 3 la 10 sunt 8 valori, nu 7.
Capcană de sintaxă cu efect de logică: un punct și virgulă pus direct după paranteze — for (i = 1; i <= n; i++); { ... } — face ca bucla să învârtă instrucțiunea vidă, iar blocul dintre acolade să se execute o singură dată, la final. Programul compilează fără nicio eroare, dar rezultatul e complet diferit.
do-while și structurile imbricate
do { ... } while (conditie); este bucla cu test final (repeat-until în Pascal): corpul se execută mai întâi, apoi se verifică condiția. Garanția ei: corpul rulează cel puțin o dată, orice ar fi.
Atenție la sensul condiției, pentru că aici Pascal și C++ diferă și confuzia costă puncte: do-while continuă cât timp condiția e adevărată, pe când repeat-until se oprește când condiția devine adevărată. La traducerea dintr-un limbaj în celălalt, condiția se neagă: repeat ... until n = 0 devine do { ... } while (n != 0);
Utilizarea tipică: validarea datelor de intrare — ceri utilizatorului un număr până introduce unul acceptabil; citirea trebuie să se întâmple măcar o dată, deci do-while e alegerea naturală.
Structurile imbricate — o buclă în interiorul alteia — apar la afișarea tabelelor, a triunghiurilor de stele sau la parcurgerea matricelor (anul viitor). Regula de execuție: pentru fiecare iterație a buclei exterioare, bucla interioară rulează complet, de la capăt. Două bucle for imbricate, fiecare de la 1 la n, execută corpul interior de n × n ori.
Greșeala tipică la imbricare este refolosirea aceluiași contor (i) în ambele bucle — cele două se sabotează reciproc și rezultatul devine haotic; bucla interioară primește întotdeauna alt contor (j).
În sfârșit, break părăsește imediat bucla curentă (doar pe cea interioară, dacă sunt imbricate), iar continue sare la iterația următoare. Folosite cu măsură, fac unele soluții mai scurte; folosite haotic, fac programul greu de urmărit.
De reținut
- instrucțiunea if-else
- instrucțiune de decizie: execută o ramură dacă condiția din parantezele rotunde e adevărată și ramura else în caz contrar
- bloc de instrucțiuni
- grup de instrucțiuni cuprins între acolade { }, tratat ca o singură instrucțiune; fără acolade, unei ramuri îi aparține doar prima instrucțiune
- instrucțiunea switch
- instrucțiune de selecție multiplă care compară o expresie întreagă sau caracter cu valori constante (case), cu ramura default pentru restul cazurilor
- break în switch
- oprește execuția ramurii curente; fără break, execuția continuă în cazul următor (fall-through)
- instrucțiunea while
- buclă cu test inițial: condiția se verifică înaintea fiecărei iterații, deci corpul se poate executa de zero ori
- instrucțiunea for
- buclă cu contor, echivalentă unui while, cu inițializarea, condiția și pasul scrise între parantezele rotunde, separate prin punct și virgulă
- instrucțiunea do-while
- buclă cu test final: corpul se execută cel puțin o dată, iar repetarea continuă cât timp condiția este adevărată
- buclă infinită
- buclă a cărei condiție nu devine niciodată falsă, de regulă pentru că variabila de control nu este actualizată în corp
- structuri imbricate
- structură de control plasată în interiorul alteia; la bucle imbricate, bucla interioară se execută complet la fiecare iterație a celei exterioare
- else de cel mai apropiat if
- regula de asociere: în lipsa acoladelor, un else aparține celui mai apropiat if precedent care nu are deja else
Greșeli frecvente
Greșit: Punct și virgulă pus imediat după condiție: if (x > 5); sau după for (...);
Corect: Acel ; este o instrucțiune vidă care devine corpul structurii; blocul dintre acolade se execută apoi necondiționat (la if) sau o singură dată (la for)
Greșit: Ramură cu mai multe instrucțiuni scrise fără acolade, bazându-te pe indentare
Corect: Fără acolade, doar prima instrucțiune aparține ramurii; compilatorul ignoră complet indentarea — instrucțiunile multiple se grupează obligatoriu între { }
Greșit: Uitarea lui break la finalul fiecărui case din switch
Corect: Fără break, execuția cade în cazul următor și se execută și instrucțiunile acestuia; fiecare case se încheie cu break, mai puțin atunci când căderea e intenționată
Greșit: Traducerea lui repeat-until în do-while păstrând condiția neschimbată
Corect: Cele două au condiții opuse: until se oprește când condiția devine adevărată, while continuă cât e adevărată — la traducere condiția se neagă
Greșit: Numărarea iterațiilor lui for (i = a; i <= b; i++) ca b - a
Corect: Numărul de iterații este b - a + 1, pentru că ambele capete sunt incluse; de la 3 la 10 bucla face 8 pași, nu 7
Test — 6 întrebări ca la examen
1. Ce afișează secvența: int x = 4; if (x > 10) cout << 1; cout << 2;?
- nimic
- 12
- 2
- 1
Vezi răspunsul
2. Fără acolade, de if aparține doar cout << 1;, care nu se execută (4 nu e mai mare ca 10). Instrucțiunea cout << 2; este în afara if-ului și se execută mereu. Răspunsul „nimic” e ales de cei păcăliți de așezarea pe același rând, care cred că ambele afișări depind de condiție.
2. Într-un switch, valoarea expresiei se potrivește cu case 2, care NU se termină cu break. Ce se întâmplă?
- compilatorul semnalează eroare de sintaxă
- se execută doar instrucțiunile de la case 2, apoi switch se încheie
- se execută instrucțiunile de la case 2 și se continuă cu cele din cazul următor
- se execută direct ramura default
Vezi răspunsul
se execută instrucțiunile de la case 2 și se continuă cu cele din cazul următor. Lipsa lui break produce fall-through: execuția continuă în cazul următor. Nu este eroare de sintaxă — programul compilează perfect, tocmai de aceea greșeala e periculoasă; e o eroare de logică descoperită abia la testare.
3. De câte ori se execută corpul buclei: for (i = 3; i <= 10; i++)?
- de 7 ori
- de 8 ori
- de 10 ori
- de 6 ori
Vezi răspunsul
de 8 ori. Contorul ia valorile 3, 4, 5, 6, 7, 8, 9, 10 — adică 10 - 3 + 1 = 8 iterații. Răspunsul 7 vine din formula greșită b - a, care uită că ambele capete sunt incluse — cea mai comună eroare de tip ±1.
4. Ce afișează secvența: int i = 8; while (i < 5) { cout << i; i++; } cout << i;?
- 8
- 5678
- nimic
- 88
Vezi răspunsul
8. Condiția 8 < 5 este falsă de la prima verificare, deci corpul buclei nu se execută deloc — while e buclă cu test inițial. Se execută doar afișarea finală: 8. Cine alege „nimic” uită de instrucțiunea cout << i; aflată după buclă.
5. Care buclă garantează că instrucțiunile din corpul ei se execută cel puțin o dată, indiferent de condiție?
- while
- for
- do-while
- toate trei garantează acest lucru
Vezi răspunsul
do-while. La do-while corpul se execută înainte de prima verificare a condiției. while și for — distractorii — au test inițial: dacă condiția e falsă de la start, corpul nu rulează deloc; de aceea do-while e alegerea potrivită pentru validarea datelor introduse de utilizator.
6. Ce afișează secvența: s = 0; for (i = 1; i <= 3; i++) for (j = 1; j <= i; j++) s++; cout << s;?
- 9
- 6
- 3
- 12
Vezi răspunsul
6. Bucla interioară face 1 pas când i=1, 2 pași când i=2 și 3 pași când i=3, în total 1+2+3 = 6. Distractorul 9 vine din presupunerea că bucla interioară face mereu 3 pași (3×3), ignorând că limita ei este chiar i, care se schimbă la fiecare iterație exterioară.
Deschide varianta interactivă — cu AI care îți explică