Sunteți pe pagina 1din 87

C a p i t o lul IV :

I n s t r u c Ń iu n il e l i m b aj u l u i

Precizare: În secŃiunile de "Probleme rezolvate" din acest capitol, vom


relua toate problemele prezentate în cadrul capitolului "Principiile programării
structurate". Întrucât în capitolul amintit algoritmii au fost explicaŃi în detaliu,
considerăm că este suficient să reamintim pseudocodul şi să prezentăm textul
programului, punctând doar câteva comentarii suplimentare acolo unde este cazul.

I V . 1 . I n s tru c Ńi u n i de se l e c Ń i e

I V .1 .1 . I n s t r u c Ń i u n e a d e s e l e c Ń i e s i m p l ã

InstrucŃiunea de selecŃie simplă if-se este transcrierea în limbajul Pascal a


structurii de selecŃie simplă învăŃată în pseudocod.
dacă (<expresie>) atunci if (<expresie>)
<secvenŃa_1> <secvenŃa_1>
altfel else
<secvenŃa_2> <secvenŃa_2>

 Expresia logică <expresie> trebuie scrisă întotdeauna între


paranteze rotunde.
 Se testează condiŃia dată de expresia logică <expresie> :
 dacă aceasta este adevărată, se execută secvenŃa de instrucŃiuni
<secvenŃa_1> (corpul ramurii "if");
 în caz contrar, se execută <secvenŃa_2> (corpul ramurii
"else").
Exemplu: Maximul a două numere întregi a şi b citite de la tastatură.

Se citesc de la citeşte a,b; #include <iostream.h>


tastatură numerele a şi b. dacă (a>b) atunci
void main()
Apoi se compară numerele, max ← a; {
memorându-se cel mai mare altfel int a,b,m;
max ← b; cout “\n a,b=”;
dintre ele în variabila max:
scrie max; cin >> a >> b;
dacă a>b atunci maximul este
if (a>b)
a, în caz contrar maximul este
max=a;
b. În final se afişează else
maximul max. max=b;
cout << “max= << max;
end.

187
ObservaŃii:
Ramura else împreună cu secvenŃa aferentă poate să lipsească. În această
situaŃie nu se execută nimic pe "cazul contrar" (dacă condiŃia dată de <expresie>
este falsă).
Dacă secvenŃa de instrucŃiuni <secvenŃa_1> sau <secvenŃa_2> conŃine
mai mult de o instrucŃiune, ea trebuie cuprinsă între acoladă deschisă şi acoladă
închisă.
Într-o instrucŃiune if-else, corpul oricărei if <c1> then
ramuri poate fi la rândul său o altă instrucŃiune if-else, if <c2> then
caz în care se formează o aşa-numită "structură if-else <s1>
imbricată". Implicit, fiecare else se asociază ultimului else
<s2>
if anterior care nu a fost asociat, aşa cum arată şi else
schema alăturată. Dacă dorim să schimbăm această <s3>
asociere, vom folosi acoladele.
Exemplu:
{ Varianta A } { Varianta B}
x=1; x=1;
if (!(a<=b) || if (!(a<=b) ||
!(a<=c)) { (1) } !(a<=c)) { (1) }
if (b>c) { (2) } {
cout << -x { (3) } if (b>c) { (2) }
else { (4) } cout << -x { (3) }
if (b<c) { (5) } }
cout << x; { (6) } else { (4) }
if (b<c) { (5) }
cout << x; { (6) }
În varianta A :
• instrucŃiunea else din linia (4) se asociază if-ului din linia (2) (ultimul înaintea sa).
Corpul acestui else este alcătuit din liniile (5) şi (6), adică o nouă instrucŃiune if.
Toate liniile (2),...,(6) reprezintă corpul if-ului din linia (1).
În varianta B:
• prezenŃa acoladelor deschisă şi închisă schimbă lucrurile: instrucŃiunea else din linia (4) se
asociază if-ului din linia (1). Corpul acestui if este un alt if, şi anume liniile (2), (3), şi
este cuprins între acolade, pentru că altfel s-ar face asocierea implicită din varianta cealaltă.
În fine, corpul lui else din linia (4) este un alt if, în speŃă liniile (5) şi (6).

AplicaŃie R.IV.1. Aria unui triunghi


ScrieŃi un program care citeşte de la tastatură două numere reale şi strict
pozitive b şi h, reprezentând baza, respectiv înălŃimea unui triunghi, apoi
calculează şi afişează aria triunghiului. În cazul în care valorile introduse nu pot
reprezenta latura şi înălŃimea unui triunghi, se va afişa mesaj de eroare. Reamintim
formula ariei triunghiului: A=(b*h)/2.
188
Rezolvare
:
 Pseudocodul acestui algoritm a fost descris pe larg în capitolul I, lecŃia "Primul
exemplu de pseudocod". Se citesc de la tastatură valorile bazei b şi înălŃimii h ale triunghiului.
Dacă acestea sunt ambele pozitive {"(b>0) şi (h>0)"}, atunci calculează şi afişează aria
triunghiului. În caz contrar tipăreşte un mesaj de eroare. Am prezentat două variante:
a) valoarea ariei se memorează prin atribuire într-o variabilă A.

#include <iostream.h>
void main ()
{ citeşte b,h;
int b,h; float A; dacă (b>0 ŞI h>0)
cout << "Dati baza si inaltimea "; început
cin >> b >> h; ← (b*h)/2;
A←
if (b>0 && h>0) scrie A;
{ sfârşit
A=(b*h)/2.; altfel
cout << "\n Aria= " << A; scrie 'Date incorecte ';
}
else
cout << "\n Date incorecte ";
}
Întrucât dorim să se obŃină valoarea exactă a ariei triunghiului, ca număr real cu
parte zecimală, trebuie să declarăm variabila A ca fiind de tipul float (chiar dacă b şi h
sunt numere întregi, declarate de tipul int), dar acest lucru nu este suficient: instrucŃinea
de atribuire a valorii ariei trebuie scrisă sub forma “A=(b*h)/2.”, şi nu “A=(b*h)/2”.
Punctul zecimal ataşat constantei 2 determină împărŃirea lui (b*h) la numărul real 2.0,
rezultând astfel tot un număr real cu parte întreagă şi parte zecimală. Dacă am fi scris
“A=(b*h)/2”, atunci compilatorul ar fi făcut împărŃirea întreagă a numărătorului (b*h) la
2, reŃinând doar partea întreagă a rezultatului !
b) valoarea ariei este afişată direct, ca expresie.

#include <iostream.h>
citeşte b,h;
void main () dacă (b>0 ŞI h>0)
{ scrie (b*h)/2 ;
int b,h; float A; altfel
cout << "\n Dati baza si inaltimea "; scrie 'Date incorecte ';
cin >> b >> h;
if (b>0 && h>0) cout << "\n Aria= " << (b*h)/2.;
else cout << "\n Date incorecte ";
}

ÎncercaŃi singuri !
►1. ScrieŃi programe pentru algoritmii propuşi în tema T.1. din cadrul
lecŃiei "II.3.1 Structura de selecŃie simplă" (capitolul II).

189
AplicaŃie R.IV.2. FuncŃie matematică
Să se calculeze valoarea funcŃiei matematice f(x ) , pentru o valoare a lui x
introdusă de la tastatură:
x 2 + 1 , pentru x ≤ −3

f : R → R , f(x ) = x − 2 , pentru x ∈ (− 3 ,3)
x 2 − 4x + 5 , pentru x ≥ 3

Rezolvare
:
 Pseudocodul acestui algoritm a fost explicat pe larg în cadrul aplicaŃiei R.II.3.
din cadrul lecŃiei "II.3.1 Structura de selecŃie simplă" (capitolul II).

 Pseudocodul
citeşte x;
dacă (x<=-3) atunci
← x*x+1
E←
altfel
dacă (x<3) atunci
←x-2
E←
altfel
←x*x-4*x+5;
E←
scrie E;

 Programul

#include <iostream.h>
#include <conio.h>

void main ()
{
float E,x;
clrscr();
// citeste o valoarea a argumentului x
cout << "x=";
cin >> x;
// memoreaza in variabila E valoarea functiei aleasa conform valorii lui x
if (x<=-3)
E=x*x+1;
else
if (x<3)
E=x-2;
else
E=x*x-4*x+5;
// afiseaza valoarea functiei indiferent de "ramura" aleasa
cout << endl << "E=" << E;
getch();
}

190
ÎncercaŃi singuri !
►1. ScrieŃi programe pentru algoritmii propuşi în tema T.3. din cadrul
lecŃiei "II.3.1 Structura de selecŃie simplă" (capitolul II).

AplicaŃie R.IV.3. Problemă cu răspuns scurt


PrecizaŃi care dintre secvenŃele de program de mai jos sunt corecte:
a ) if (a=b) b ) if a<b && b<c
cout << ”Nr. egale”; cout << a << b << c;
c) i f ( a % 2 = = 0 ) ; d ) if (a>=b) max=a;
cout << a << ” este par”; else max=b;
Rezolvare
:
 Singura variantă corectă este d), celelalte conŃinând erori, după cum vom
explica în continuare:
a) În linia if trebuie să avem o expresie logică (condiŃie), a cărei valoare de adevăr
(1 sau 0) se testează. Deci nu putem avea instrucŃiunea de atribuire a=b. Corect ar fi fost:
if (a==b) cout << ”Nr. Egale”;

b) Expresia logică a<b && b<c este compusă din două expresii simple a<b
respectiv b<c, "legate" între ele prin operatorul ”ŞI logic”. Dar expresia logică trebuia
cuprinsă între paranteze. Corect:
if (a<b && b<c) cout << a << b << c;

c) S-a pus punct şi virgulă după expresia logică din linia if. "Punct şi virgulă"
este "văzută" în acest caz ca secvenŃa de pe ramura if. InstrucŃiunea cout este "văzută" în
afara lui if, deci se execută indiferent dacă este îndeplinită sau nu condiŃia a%2==0.
Corect:
if (a%2==0) cout << a << ” este par”;

d) Acestă secvenŃă nu conŃine erori de sintaxă şi determină în mod corect


maximul a două numere reale a şi b, memorat în variabila max: dacă a≥ ≥ b atunci maximul
max ia valoarea lui a (prin atribuire), iar în caz contrar max ia valoarea lui b.
Răspuns corect: d).

AplicaŃie R.IV.4. Problemă cu răspuns scurt


(Bacalaureat iulie 2009, varianta 95)
În secvenŃa de instrucŃiuni de mai jos, variabilele i, j, k, x şi y sunt de tip
întreg. Pentru care dintre următoarele seturi de valori ale variabilelor i, j şi k,
variabilele x şi y vor primi valori diferite în urma executării acestei secvenŃe ?
if (k>0) a) x şi y primesc aceeaşi valoare,
if (i!=j) indiferent de valorile lui i, j şi k
x=0;
b) k=0, i=5, j=6
191
else c) k=10, i=5, j=5
x=1; d) k=0, i=5, j=5
else
x=2;
if (i!=j)
if (k>0)
y=0;
else
y=2;
else
y=1;

Rezolvare
:
 SecvenŃa conŃine două instrucŃiuni "if-else" imbricate. După cum am arătat
în partea de teorie, într-o instrucŃiune "if-else" imbricată, fiecare "else" se asociază
primului "if" de dinaintea lui care nu a fost încă asociat. Din modul în care am aşezat în
pagină "ramurile" instrucŃiunilor de selecŃie, vă puteŃi da seama care sunt asocierile. Astfel,
pe prima structură "if-else" imbricată avem:
− ramura "else x=1;" se asociază primului "if" de dinaintea lui, adică lui "if
(i!=j)";
− ramura "else x=2;" se asociază lui "if (k>0)".
În mod similar au loc asocierile şi în cazul celei de-a doua structuri "if-else"
imbricate, cea care pleacă de la "if (i!=j)".

 Pentru început vom analiza variantele b) şi d), care au ambele k=0. Întrucât
condiŃia "k>0" din primul "if" nu este îndeplinită, se va intra pe ramura "else" a
acestuia, care conŃine atribuirea x=2. Mai departe, evoluŃia algoritmului pe cele două
variante este diferită, şi anume:
− În varianta b), cu i=5 şi j=6, condiŃia din linia "if (i!=j)" este adevărată
(5#6), motiv pentru care intră pe ramura "if" a acestei structuri imbricate, unde găseşte un
alt "if-else". Aici condiŃia "k>0" este falsă (noi am plecat de la k=0), deci va executa
ramura "else" a structurii interioare, unde avem atribuirea y=2. În concluzie, în varianta
b) vom avea x=2 şi y=2, adică valori egale.
− În schimb, în varianta d), cu i=5 şi j=5, condiŃia din linia "if (i!=j)" este
falsă, deci va executa ramura "else" a acestui "if-else", unde nu mai avem un alt "if-
else", ci doar atribuirea y=1. Iată aşadar că în varianta d) am obŃinut x=2 şi y=1, adică
valori diferite pentru cele două variabile de ieşire, ceea ce corespunde cerinŃei problemei.
Acum este foarte clar că varianta a) nu este corectă. Cât priveşte varianta c), vă
lăsăm ca exerciŃiu să dovediŃi faptul că, pentru k=10, i=5 şi j=5, se obŃin la ieşire
rezultatele x=1 şi y=1, adică valori egale.
Răspuns corect: d)

AplicaŃie R.IV.5. Câtul şi restul


( B a ca l au r e at iu li e 2 0 0 8 , va r i a n t a 9 6)
R e a l i z a Ń i u n a l g o r i t m c a r e c i t e ş t e d e l a t a s t a t u r ă d o u ă n u m er e n a t u r al e
d i s t i n ct e , a p o i af i ş e a z ă c â t u l ş i r e s t u l î m p ă r Ń i r i i ce l u i m a i m a r e d i n t r e c e l e
192
d o u ă n u m e r e l a c e l m a i m i c d i n t r e e l e . D a c ă n u m e r el e s u n t e g a l e , s a u d ac ă
î m p ă r Ń i r e a n u s e p o at e e f ec t u a , s e v a a f i ş a m e s a j u l "E r o a r e " .
Rezolvare
:
 Pseudocodul acestui algoritm a fost explicat pe larg în cadrul aplicaŃiei R.II.4
din cadrul lecŃiei "II.3.1 Structura de selecŃie simplă" (capitolul II).

 Pseudocodul:
citeşte a,b;
dacă (a==b) atunci
scrie ”Eroare”;
altfel
început
dacă (a>b) atunci
dacă (b#0) atunci
scrie [a/b], ” ”,a%b;
altfel
scrie ”Eroare”;
dacă (b>a) atunci
dacă (a#0) atunci
scrie [b/a], ” ”,b%a;
altfel
scrie ”Eroare”;
sfârşit

 Programul:

#include <iostream.h>
#include <conio.h>

void main ()
{
int a,b;
clrscr();
cout << "Dati numerele a si b:" << endl;
cin >> a >> b;
if (a==b)
cout << endl << "Eroare";
else
{
if (a>b)
if (b) // echivalent cu "b!=0"
cout << endl << "Catul si restul sunt " << a/b << " " << a%b;
else
cout << endl << "Eroare";
if (b>a)
if (a)
cout << endl << "Catul si restul sunt " << b/a << " " << b%a;
else
cout << endl << "Eroare";
}
getch();
}
193
ÎncercaŃi singuri !
►1. ScrieŃi programe pentru algoritmii propuşi în tema T.4. din cadrul
lecŃiei "II.3.1 Structura de selecŃie simplă" (capitolul II).

AplicaŃie R.IV.6. Laturi în triunghi


Se citesc de la tastatură trei numere reale a, b, c. Să se verifice dacă aceste
numere pot fi laturile unui triunghi şi în caz afirmativ să se determine natura
triunghiului în funcŃie de laturi (echilateral, isoscel, oarecare). Trei numere pot fi
laturile unui triunghi, dacă sunt pozitive şi suma a oricare două dintre ele este mai
mare decât al treilea.
Exemplu: Numerele a=4, b=4 şi c=7 sunt laturile unui triunghi isoscel, iar
valorile a=2, b=3 şi c=9 nu pot fi laturile unui triunghi (din cauză că 2+3<9).

Rezolvare
:
 Pseudocodul (aplicaŃia R.II.5. din capitolul "Principiile programării
structurate").

citeşte a,b,c;
dacă (a>0 ŞI b>0 ŞI c>0 ŞI a+b>c ŞI a+c>b ŞI b+c>a) atunci
început
scrie "Numerele sunt laturi";
dacă (a==b ŞI b==c)
scrie "Triunghi echilateral";
altfel
dacă (a==b SAU a==c SAU b==c)
scrie "Triunghi isoscel";
altfel
scrie "Triunghi oarecare";
sfârşit
altfel
scrie "Nu e triunghi";

 Programul:
#include <iostream.h>
void main ()
{
float a,b,c;
float p,S;
//citeste laturile in variabilele a, b, c
cout << "\n Dati laturile: ";
cin >> a >> b >> c;
//verifica daca a, b, c, citite anterior, pot fi laturile unui triunghi
if (a>0 && b>0 && c>0 && a+b>c && a+c>b && b+c>a)

194
{
cout << "\n Numerele sunt laturi";
//verifica natura triunghiului
if (a==b && b==c)
cout << "\n triunghi echilateral ";
else
if (a==b || a==c || b==c)
cout << "\n triunghi isoscel";
else
cout << "\n triunghi oarecare";
}
else
cout << "\n Numerele nu pot fi laturi in triunghi";
}

ÎncercaŃi singuri !
►1. ScrieŃi programe pentru algoritmii propuşi în tema T.5. din cadrul
lecŃiei "II.3.1 Structura de selecŃie simplă" (capitolul II).

AplicaŃie R.IV.7. Rezolvarea ecuaŃiei de gradul II


ScrieŃi un program pentru rezolvarea ecuaŃiei de gradul II de forma
a x 2 + b x + c = 0 , unde coeficienŃii a, b, c se citesc de la tastatură. Se vor trata toate
cazurile posibile.
Rezolvare
:
 Pseudocodul (aplicaŃia R.II.6. din capitolul "Principiile programării
structurate").

citeşte a,b,c;
dacă (a==0) atunci
dacă (b==0) atunci
scrie "Nu se rezolva ecuatia"
altfel
scrie -c/b
altfel
început
delta ← b*b-4*a*c;
dacă (delta<0) atunci
scrie "Nu are solutii reale"
altfel
început
x1 ← (-b+ delta )/(2*a);
x2 ← (-b- delta )/(2*a);
scrie x1,x2;
sfârşit
sfârşit

195
 Programul:
#include <iostream.h>
#include <math.h>

void main ()
{
float a,b,c; float delta,x1,x2;
cout << "\n Dati coeficientii: ";
cin >> a >> b >> c; // citeste coeficientii
if (a==0)
if (b==0) // rezolva ec. de gr.I
cout << "\n Nu se rezolva ecuatia";
else
cout << "\n Ec. de gr. I cu solutia " << (-c/b);
else
{
delta=b*b-4*a*c; // discriminantul
if (delta<0)
cout << "\n Ecuatia nu are solutii reale!";
else // cazul delta>=0
{ // rezolva ec. de gr.II
x1=(-b+sqrt(delta))/(2*a);
x2=(-b-sqrt(delta))/(2*a);
cout << "\n Solutiile sunt:";
cout << "x1=" << x1 << " x2=" << x2;
}
}
}

ÎncercaŃi singuri !
►1. ScrieŃi programe pentru algoritmii propuşi în tema T.6. din cadrul
lecŃiei "II.3.1 Structura de selecŃie simplă" (capitolul II).

ÎncercaŃi singuri !
►1. TranscrieŃi în limbajul de programare C++ toate pseudocodurile
prezentate în enunŃurile problemelor din tema T.2., din cadrul lecŃiei "II.3.1
Structura de selecŃie simplă" (capitolul II).

AŃi înŃeles ? Probleme cu răspuns scurt


Următoarele două probleme se referă la secvenŃa de program de mai jos:
if (a>0)
if (b>0) x=8;
else x=5;
else x=6;
cout << x;
196
►1. În urma execuŃiei secvenŃei, pentru care dintre perechile de valori ale
variabilelor întregi a şi b date mai jos se va afişa x=5 ?
a) a=-1 şi b=-1 b) a=1 şi b=1
d) a=0 şi b=-1 d) a=1 şi b=-1

►2 Este posibil să găsim două valori egale între ele pentru variabilele a şi b,
astfel încât secvenŃa să afişeze o valoare negativă ?
► 3. (Bacalaureat august 2001, varianta 2)
Ştiind că variabilele întregi x şi y au iniŃial aceeaşi valoare, stabiliŃi care este
diferenŃa absolută între valorile lor la sfârşitul execuŃiei secvenŃei următoare.
y++; x--;
if (y<=x)
{ y--; x++; }
else
{ y+=2; x--; };

► 4. Se consideră secvenŃa de mai jos, în care x este o variabilă de tipul caracter,


iar m este de tip întreg.
if (x=='a') m=0; else if ((x=='b')||(x=='c')) m=1; else
if ((x>'c')&&(x<'z')) m=0; else if (x=='z') m=1; else m=-1;
Pentru fiecare dintre secvenŃele S1, S2 şi S3 date mai jos, stabiliŃi dacă este
echivalentă cu secvenŃa de mai sus. JustificaŃi răspunsurile.

// SecvenŃa S1 // SecvenŃa S2
if (x=='a') m=0; if (x=='b' || x=='c' || x=='z' )
else m=1;
if (x=='b' || x=='c') else
m=1; if ((x=='a') || (x>'c' && x<'z'))
else m=0;
if (x>'c' && x<'z' ) else
m=0; m=-1;
else
if (x=='z') m=1;
else m=-1;

// SecvenŃa S3
if (x<'a' || x>'z') m=-1;
else
if (x=='b' || x=='c' || x=='z')
m=1;
else
m=0;

►5. PrecizaŃi ce afişează programul de mai jos:


int a=1, b=0, c=1;
if (a || b) if (b && !c) cout << "unu"; else cout << "doi";

a) Nu afişează nimic. b) Textul unu. c) Textul doi.


d) InstrucŃiunea if este greşită sintactic.

197
►6. Care dintre următoarele secvenŃe de instrucŃiuni atribuie variabilei întregi x
cea mai mică dintre valorile variabilelor întregi a şi b, sau valoarea lor comună în cazul în
care acestea sunt egale ?
a) if (a==b) x=b; b) x=a;
else if (x>b)
if (b>a) x=a; x=b;
c) if (b>=a) x==a; d) if (a<=b) x=b;
else x==b; else x=a;

►7. Fie x o variabilă de tipul float. PrecizaŃi care dintre secvenŃele Pascal de
mai jos corespunde enunŃului "dacă valoarea lui x este un număr întreg (fără parte
zecimală), atunci afişează TRUE ".
a) if (x==(int)x) cout << 1;
b) if (x==floor(x)) cout << 1;
c) if (x==ceil(x)) cout << 1;
d) if (floor(x)==ceil(x)) cout << 1;

►8. PrecizaŃi de câte ori se va afişa valoarea 1 în timpul execuŃiei programului


următor, dacă prin citire de la tastatură variabilele primesc valorile a=3, b=4 şi x=5.
#include<iostream.h>
void main()
{
int a,b,x;
cin >> a >> b >> x;
if (!((x<=a) && (x>=b))) cout << 1 << "\n";
if (!(x<=a || x>=b)) cout << 1 << "\n";
if (!(x<=a) && !(x>=b)) cout << 1 << "\n";
if (!(x<=a) || !(x>=b)) cout << 1 << "\n";
}

Următorii trei itemi se referă la secvenŃa de program de mai jos:


int x=floor(sqrt(10));
int a,b,c;
a=b=c=0;
if (x>3)
a++;
else
if (x<-3);
b++;
else
if (x<0)
else
c++;
cout << "\n" << a << b << c;

►9. SecvenŃa dată conŃine erori de sintaxă ? În caz afirmativ, câte şi care sunt acestea ?

►10. După corectarea erorilor, în urma execuŃiei secvenŃei, care dintre variabilele
întregi a, b, c va primi valoarea 1 ?
a) variabila a b) variabila b c) variabila c
d) niciuna dintre cele trei variabile

198
►11. ÎnlocuiŃi structura de selecŃie "if (x<0) else c++;" cu una echivalentă
(cu acelaşi efect), dar care să nu mai conŃină ramura "else".
►12. (Bacalaureat, iulie 2002, varianta 3)
Care dintre următoarele secvenŃe calculează în variabila întreagă min cea mai
mică dintre valorile variabilelor întregi r, s şi t ?
a) if (r<t) min=r; b) min=s;
else min=t; if (min<t) min=t;
if (min>s) min=s; if (min<r) min:=r;
c) if (r<s) if (s<t) min=r; d) if (r<s) min=r else min=s;
else min=t; else min=s; if (s<t) min=s else min=t;
if (r<t) min=r else min=t;

► 13. (Bacalaureat iulie 2009, varianta 96)


În secvenŃa dată de instrucŃiuni, variabilele i, j, k şi y sunt de tip întreg. Pentru
care dintre următoarele seturi de valori ale variabilelor i, j şi k variabila y va avea
valoarea 1 în urma executării secvenŃei ?
if (k>0)
if (i!=j) y=0;
else y=1;
else y=2;

a) k=0; i=5; j=5; b) k=10; i=5; j=6;


c) k=10; i=5; j=5; d) k=0; i=5; j=6;
► 14. (Bacalaureat iulie 2009, varianta 1)
Ştiind că variabilele a şi b sunt utilizate pentru a memora două numere reale,
stabiliŃi care dintre secvenŃele de instrucŃiuni de mai jos determină, în urma executării,
iniŃializarea variabilei m cu diferenŃa absolută a valorilor memorate în a şi b.
a) m=(a-b) || (b-a);
b) m=a; if (m<a) m=b-m;
c) m=a; if (m>b) m=a-m;
d) m=a-b; if (a<b) m:=-m;

► 15. (Bacalaureat iulie 2008, varianta 61)


DeduceŃi care este cea mai mică valoare pozitivă pe care o poate memora
variabila x, astfel încât, în urma executării secvenŃei de instrucŃiuni de mai jos, să se
afişeze valoarea lui x.
if (x>71% 2+3/x) then
cout << x;
a) 2 b) 3 c) 4 d) 5

199
Aprofundare

Probleme rezolvate

R.IV.8 Dif e re n Ńă mi ni mă
(Bacalaureat iulie 2008, varianta 93)
Pentru trei numere reale şi distincte a, b şi c citite de la tastatură, se cere
să se afişeze o valoare întreagă x care îndeplineşte proprietatea că suma distanŃelor
de la x la cele trei numere date, adică |x-a|+|x-b|+|x-c|, este minimă (prin
definiŃie, distanŃa dintre două numere u şi v, măsurată pe axa reală, este egală cu
modulul diferenŃei celor două numere, adică |u-v|). Se cere o metodă de
rezolvare eficientă din punctul de vedere al timpului de executare şi al spaŃiului de
memorie folosit.
Exemplu: pentru a=2.5, b=3.8 şi c=7.1, suma minimă este 4.8, şi se
realizează pentru x=4.
Rezolvare
:
Algoritmul a fost explicat pe larg în pseudocod în aplicaŃia R.II.7. din secŃiunea
"Aprofundare " a lecŃiei "InstrucŃiunea de selecŃie simplă ".

 Pseudocodul:

citeşte a,b,c;
min←a;
dacă (b<=min) atunci
min← b;
dacă (c<=min) atunci
min← c;
max←a;
dacă (b>=max) atunci
max← b;
dacă (c>=max) atunci
max← c;
p←(a+b+c)-(min+max);
x1← [p];
S1← |x1-min|+|x1-max|+|x1-p|;
x2← [p]+1;
S2← |x2-min|+|x2-max|+|x2-p|;
dacă (S1<S2) atunci
scrie S1,x1;
altfel
scrie S2,x2;
200
 Programul:

// Bac 2009, II.3 / var 25


#include <iostream.h>
#include <conio.h>
#include <math.h>

void main ()
{
clrscr();
float a,b,c,p,min,max,S1,S2;
int x1,x2;
cout << "Dati numerele:" << endl;
cin >> a >> b >> c;
// determina min = minimul dintre a, b si c
min=a;
if (b<=min)
min=b;
if (c<=min)
min=c;
// determina max = maximul dintre a, b si c
max=a;
if (b>=max)
max=b;
if (c>=max)
max=c;
// p = al treilea numar, care nu e nici minim nici maxim
p=(a+b+c)-(min+max);
// determinam in x1 si x2 cele doua valori pe care le-ar putea lua x, si sumele aferente
x1=floor(p);
S1=abs(x1-min)+abs(x1-max)+abs(x1-p);
x2=floor(p)+1;
S2=abs(x2-min)+abs(x2-max)+abs(x2-p);
// stabilim care dintre cele doua sume de distante este mai mica
if (S1<S2)
cout << "S=" << S1 << " x=" << x1;
else
cout << "S=" << S2 << " x=" << x2;
getch();
}

R.IV.9 Vârsta unei persoane


Se cunoaşte data naşterii unei persoane, definită prin intermediul a trei
variabile, reprezentând ziua, luna şi anul naşterii. Fiind cunoscută şi data curentă
exprimată sub aceeaşi formă, să se afişeze un mesaj din care să rezulte dacă la data
curentă persoana în cauză a împlinit x ani. În determinarea vârstei în ani împliniŃi
se va Ńine cont de cazurile expuse în exemplul următor.
Exemplu: Presupunem că data curentă este 23.09.2002.
− dacă persoana s-a născut în 25.08.1962, ea a împlinit 40 ani (cazul 1);
− dacă data naşterii este 28.09.1962 (cazul 2) sau 26.11.1962
(cazul 3), persoana are doar 39 de ani împliniŃi.
201
Rezolvare
:
Algoritmul a fost explicat pe larg în pseudocod în aplicaŃia R.II.8. din secŃiunea
"Aprofundare " a lecŃiei "InstrucŃiunea de selecŃie simplă ".

 Pseudocodul:
citeste zn,ln,an
citeste zc,ac,lc
citeste x
nr_ani←ac-an
dacă (ln>lc SAU (ln=lc SI zn>zc))
nr_ani←nr_ani-1;
dacă (nr_ani>=x)
scrie "Persoana are ',x,' ani impliniti"
altfel
scrie "Persoana nu a implinit ',x, ' ani"

 Pseudocodul:
#include <iostream.h>
#include <conio.h>
void main ()
{
int zn,ln,an,zc,lc,ac,nr_ani,x;
cout << "\n Dati ziua, luna si anul nasterii persoanei: ";
cin >> zn >> ln >> an;
cout << "\n Dati ziua, luna si anul datei curente: ";
cin >> zc >> lc >> ac;
cout << "\n Dati varsta cu care comparam ";
cin >> x;
nr_ani=ac-an;
if ( (ln>lc) || (ln==lc && zn>zc) )
nr_ani--;
if (nr_ani>=x)
cout << "\n Persoana are " << x << " ani impliniti";
else
cout << "\n Persoana nu a implinit " << x << " ani";
getch();
}

Probleme propuse

ScrieŃi programe pentru algoritmii propuşi în tema T.R.1. din lecŃia "II.3.1.
Structura de selecŃie simplă" (capitolul II), la sfârşitul secŃiunii "Aprofundare".

202
Extindere

În această secŃiune ne propunem să ilustrăm legătura dintre instrucŃiunea


de selecŃie simplă “if-else” şi expresia condiŃională. Mai exact spus, unele
secvenŃe “if-else” pot fi înlocuite cu expresii condiŃionale, ceea ce, trebuie să
recunoaştem, conduce la o condensare remarcabilă a codului sursă.
Exemplu: ScrieŃi o instrucŃiune “if-else” şi o expresie condiŃională
care să “traducă” în C++ următorul enunŃ: "dacă numărul y este pozitiv, atunci
x ia valoarea lui a, în caz contrar x ia valoarea lui b ".
SecvenŃa “if-else” este absolut banală:
if (y>0)
x=a;
else
x=b;
Reamintim sintaxa unei expresii condiŃionale pe caz general:
<expr_1> ? <expr_2> : <expr_3>;
ExecuŃia unei expresii condiŃionale se produce în felul următor:
♦ se evaluează mai întâi expresia logică <expr_1>:
− dacă valoarea acesteia este diferită de 0, atunci valoarea şi tipul
expresiei condiŃionale sunt date de expresia <expr_2>, iar în caz
contrar de <expr_3>.
Operatorii condiŃionali sunt "?" şi ":". Observăm că o expresie condiŃională are
efectul unei instrucŃiuni “if-else“: dacă <expr_1> are valoarea de adevăr 1 se execută
<expr_2>, în caz contrar se efectuează <expr_3>. Există totuşi o deosebire: într-o
instrucŃiune “if-else“ ramura “else“ poate să lipsească, pe când într-o expresie
condiŃională trebuie să fie prezente ambele expresii <expr_2> şi <expr_3>.
În cazul nostru: condiŃia testată, adică expresia <expr_1>, este “y>0”, expresia
<expr_2> care se execută pe condiŃia adevărată este “x=a”, iar expresia <expr_3>
aferentă cazului de condiŃie falsă este “x=b”. Prin urmare, transcrierea secvenŃei cu
expresie condiŃională este:
(y>0) ? (x=a) : (x=b);
În cazul în care expresiile <expr_2> şi <expr_3> aferente celor două “ramuri”
constau în atribuiri de valori pentru aceeaşi variabilă, se poate folosi o formă particulară de
expresie condiŃională. Sintaxa este:
<var> = <expr_1> ? <expr_2> : <expr_3>;
FuncŃionarea în acest caz este următoarea:
♦ se evaluează expresia logică <expr_1>:
203
 dacă aceasta are o valoare diferită de zero, atunci variabilei <var> i se
atribuie expresia <expr_2>;
 în caz contrar, variabilei <var> i se atribuie expresia <expr_3>.
Conformă cu sintaxa de mai sus este expresia:
x=(y>0) ? a : b
− variabila <var> este x, expresia logică <exp_1> este "y>0",
<expr_2> este "a", iar <expr_3> este "b".
Expresia se "traduce" astfel: dacă y>0, atunci x ia valoarea lui a, în caz contrar x
ia valoarea lui b, adică exact enunŃul cerut.
MenŃionăm că parantezele puteau să lipsească, deoarece operatorii "?" şi ":" ai
unei expresii condiŃionale au prioritate mai mică decât toŃi operatorii aritmetici, logici şi
relaŃionali. Aşadar, se putea scrie: x=y>0 ? a : b

Vom da în continuare un exemplu invers, în care se cere să se transcrie o


expresie condiŃională printr-o instrucŃiune de selecŃie simplă. Am ales un exemplu
mai complex pentru a ilustra faptul că până şi structurile “if-else” implicate pot
fi echivalate într-o manieră super-elegantă cu expresii condiŃionale.
Exemplu: Să se transcrie printr-o secvenŃă “if-else” următoarea
expresie condiŃională:
a>0 ? (b>0 ? (x=8) : (x=5)) : (x=6);
Interpretarea expresiei condiŃionale este următoarea:
− dacă a>0, se execută expresia de după operatorul “?”, care este tot o expresie
condiŃională: “b>0 ? (x=8) : (x=5)”;
− în caz contrar, se execută expresia de după operatorul “:”, respectiv atribuirea “x=6”.
Pâna acum, transcrierea printr-o instrucŃiune “if-else” este următoarea:
if (a>0)
b>0 ? (x=8) : (x=5);
else
x=6
Mai departe, “traducerea” expresiei condiŃionale de pe “ramura” if este banală:
dacă b>0 se execută atribuirea x=8, în caz contrar are loc atribuirea x=5. A rezultat astfel
varianta cu o structură “if-else” imbricată:
if (a>0)
if (b>0)
x=8;
else
x=5;
else
x=6;
Mai facem menŃiunea că acoladele nu sunt necesare, deoarece oricum în absenŃa
acestora are loc asocierea implicită: fiecare “else” se asociează primului “if” dinaintea
lui care nu a fost încă asociat.

În expresia logică din linia if pot fi înglobate alte expresii de tot felul:
atribuiri, expresii condiŃionale, expresii cu operatorul “virgulă”, etc.. Un exemplu
concret în acest sens îl constituie aplicaŃia următoare.
204
AplicaŃie R.IV.10. Afişări
DeduceŃi pas cu pas valorile pe care le afişează programul de mai jos:
#include <iostream.h>
void main()
{
int x,y,m,n,a,b;
a=b=2;
if ((m=(x=a+3,y=b-1,y++,y+x))>0 && a) cout << m;
if (x-y>a && x>y || !m) cout << 1; else cout << 0;
if (((n=x>y)==0) || (--x==4)) cout << x--;
}
Rezolvare
:
 Vom analiza pe rând liniile de program:
• a=b=2;
Este o instrucŃiune de atribuire compusă, în urma căreia variabilele b şi a
primesc, în această ordine, valoarea 2.
• if ((m=(x=a+3,y=b-1,y++,y+x))>0 && a) cout << m;
ObservaŃi că în expresia logică din linia “if” apare o atribuire, şi anume:
m=(x=a+3,y=b-1,y++,y+x);
Variabilei m i se atribuie valoarea expresiei “x=a+3,y=b-1,y++,y+x“. Aceasta
este o expresie compusă din mai multe expresii elementare cu ajutorul operatorului
"virgulă ". Expresiile elementare se evaluează de la stânga la dreapta, iar valoarea ultimei
dintre ele este atribuită lui m. Aşadar: x=a+3=2+3=5, y=b-1=2-1=1, y=y+1=1+1=2 şi
m=y+x=2+5=7.
Expresia logică ce constituie condiŃia testată în linia “if” este “m>0 && a”, adică
“m>0 ŞI a≠0”. Pentru valorile existente, evaluarea expresiei conduce la: 7>0 ŞI 2≠0 ? da
⇒ se afişează valoarea lui m, adică, 7.
• if (x-y>a && x>y || !m) cout << 1; else cout << 0;
Dacă m este diferit de 0, atunci !m va fi 0. Evaluarea expresiei din linia if înseamnă (5-
2>2) ŞI (5>2) SAU !7, adică (1 ŞI 1) SAU 0. Se va obŃine 1 SAU 0 cu rezultat 1 (se
efectuează mai întâi operaŃia "ŞI", apoi operaŃia "SAU"). Pentru că expresia " x-y>a && x>y ||
!m" are valoarea 1, se va executa "ramura" if, afişându-se 1.
• if (((n=x>y)==0) || (--x==4)) cout << x--;
În expresia "(n=x>y)==0", întâlnim o atribuire şi o testare. Mai precis, se
atribuie lui n valoarea expresiei "x>y" (0 sau 1), apoi valoarea lui n este comparată cu 0.
Deci: 5>2 ? da ⇒ n=1, 1==0 ? nu ⇒ valoarea expresiei "(n=x>y)==0" este 0 (cu sens
de fals).
În expresia "--x==4", mai întâi se decrementează x, apoi, noua valoare a lui x
este comparată cu 4. Aşadar, x=5-1=4, apoi, x==4 ? da ⇒ valoarea expresiei "--x==4"
este 1.

205
În urma operaŃiei "SAU logic" între valorile celor două expresii de mai sus, se
obŃine "0 SAU 1" cu rezultat 1.
Aşadar, toată expresia ((n=x>y)==0) || (--x==4) are valoarea 1, motiv
pentru care se execută instrucŃiunea cout << x--. Se afişează valoarea curentă a lui x,
adică, 4, şi abia apoi se decrementează x.

ÎncercaŃi singuri !
►1. Fie trei variabile întregi a, b, x. ScrieŃi în două moduri, folosind o
secvenŃă “if-else” respectiv cu ajutorul unei expresii condiŃionale, enunŃul:
"dacă x ∉ [a , b] atunci x ia valoarea lui a, în caz contrar x ia valoarea lui b".

►2. RealizaŃi un program pentru determinarea minimului a trei numere


întregi a, b şi c, folosind o structură “if-else”. RescrieŃi apoi programul,
înlocuind întreaga structură “if-else” cu o expresie condiŃională condensată într-
o singură linie.
►3. Se consideră următorul program C++:
#include <stdio.h>
void main ()
{
int x,y,z,p; char m,n;
m='C'; n='A';
x=m; y=2*m-n; z=3;
p=x<y?(y<z?z:y):(z<x?x:z);
printf("\n%d",p);
}
a) Ştiind că în standardul ASCII caracterele literă mare au codurile
succesive începând cu 65 ('A'← ←65, 'B'← ←66, 'C'← ←67, etc), deduceŃi ce valoare
va afişa programul.
b) RescrieŃi programul, înlocuind expresia condiŃională compusă din linia
(*) cu o structură “if-else” imbricată.
►4. PrecizaŃi ce valori se vor afişa, în ordine, în timpul execuŃiei
programului următor:
#include <iostream.h>
void main()
{
int x,y,m,n,a,b=5;
x=(m=b=n=3,b+4);
y=a=((b==5)? b--:--b);
if (!(y==a) && (m==n)) cout << 1; else cout << 0;
if (!a && b && !m) cout << 1; else cout << 0;
if ((n=(a+b--))==-(m-x)) cout << 1; else cout << 0;
}

206
I V .1 .2 . I n s t r u c Ń i u n e a de s e l e c Ń i e m u l t i p l ã

InstrucŃiunea de selecŃie multiplă case este implementarea structurii de


selecŃie multiplă descrisă în pseudocod. Ea permite alegerea unei secvenŃe de
instrucŃiuni din mai multe posibile, în funcŃie de valoarea unei expresii numită
selector. De cele mai multe ori selectorul este o variabilă.
alege (<selector>) switch (<selector>)
început {
cazul <val_1>: case <val_1>:
<secvenŃa_1> <secvenŃa_1>
ieşire break;
cazul <val_2>: case <val_2>:
<secvenŃa_2> <secvenŃa_2>
ieşire break;
.................. ..................
cazul <val_n>: case <val_n>:
<secvenŃa_n> <secvenŃa_n>
ieşire break;
altfel default
<secvenŃa_0> <secvenŃa_0>
sfârşit }

Aşadar:
 Linia "switch (<selector>)" se traduce prin "alege unul din mai multe
cazuri posibile, în funcŃie de valoarea variabilei (<selector>". În limbajul
C++, numele variabilei selector trebuie scris între paranteze rotunde.
 Fiecare dintre simbolurile <val_1>, <val_2>, ... <val_n>, reprezintă o
valoare posibilă a selectorului <selector>. Astfel, de exemplu, linia
"case <val_1>:" se traduce prin "cazul în care selectorul are valoarea
simbolizată prin <val_1>";
 Fiecărui caz îi corespunde o secvenŃă de instrucŃiuni, iar calculatorul va alege
unul dintre cazuri executând secvenŃa aferentă în funcŃie de valoarea
selectorului. Astfel, în cazul în care selectorul are valoarea <val_1> se execută
secvenŃa de instrucŃiuni <secvenŃa_1>, dacă selectorul are valoarea
<val_2> are loc execuŃia secvenŃei <secvenŃa_2>, ş.a.m.d.. ObservaŃi că pe
fiecare "ramură", după secvenŃa de instrucŃiuni aferentă, urmează cuvântul
cheie "break;". Acest fapt se datorează modului în care funcŃionează
instrucŃiunea de selecŃie multiplă în limbajul C++: în absenŃa instrucŃiunii
"break", compilatorul ar trece la analizarea următoarelor "cazuri". PrezenŃa
cuvântului-cheie "break" la sfârşitul fiecăruia dintre "cazuri", va determina
compilatorul să abandoneze complet instrucŃiunea de selecŃie multiplă după
execuŃia secvenŃei de instrucŃiuni aferentă "cazului” selectat.

207
 Pe lângă "ramurile" ce descriu cazurile, mai poate exista o ramură numită
"default". Aceasta se va executa dacă valoarea selectorului nu este
cuprinsă în nici unul dintre cazurile anterioare <val_1>, <val_2>, ...,
<val_n>. MenŃionăm însă că prezenŃa ramurii "default" nu este
obligatorie, situaŃie în care dacă nu este îndeplinit nici unul din cazurile
date, pur şi simplu nu se va executa nimic.
 Întreaga instrucŃiune de selecŃie multiplă trebuie cuprinsă între acoladă
deschisă şi închisă.

Ex e mp l u :
Prezentăm un program pur demonstrativ care, fără a avea vreun efect deosebit,
ilustrează sintaxa instrucŃiunii case. Pseudocodul acestui program a fost explicat pe larg în
capitolul "Algoritmi. Principiile programării structurate", lecŃia "Structura de selecŃie
multiplă ".
#include<iostream.h> citeşte x;
int x,y; alege (x)
void main() început
{ cazul -1:
cout << "x="; y ← x+2;
cin >> x; ieşire
switch (x) cazul 0:
{ scrie "Ati introdus 0";
case -1: y ← x;
y=x+2; ieşire
break ; cazul 1:
case 0: y ← x-1;
cout << "Ati intodus 0"; ieşire
y=x; altfel
break ; scrie "Nu e -1,0,1 ";
case 1:
y=x-1; y ← 100;
break ; sfârşit
default:
cout << "Nu e -1,0,1";
y=100;
}
cout << "\n" << y;
}

AplicaŃie R.IV.11. Grilă


Ce va afişa programul următor, dacă de la tastatură se introduc în ordine
numerele 5, 6 şi 8 ?
#include <iostream.h>
void main()
{
int x,y,z,m;
cin >> x >> y >> z;
m=(x+y+z)/3;
switch (m)

208
{
case 4:
cout << "Corigent";
break;
case 6:
cout << "Mediocru";
break;
case 8:
cout << "Bine";
break;
case 10:
cout << "Foarte bine";
break;
default:
cout << "EROARE !";
}
a) "Corigent" b ) "Mediocru" c) "Satisfacator" d) "Foarte bine"
e) "EROARE ! "
Rezolvare
:
 AcŃiunile programului sunt următoarele:
• se citesc de la tastatură valorile variabilelor întregi x, y şi z;
• se atribuie variabilei m valoarea expresiei (x+y+z) / 3. Dacă se citesc x=5, y=6,
z=8, atunci m=(5+6+8) / 3=19 / 3=6 (reamintim că atunci când deîmpărŃitul şi
împărŃitorul sunt ambii întregi, operatorul "/" furnizează câtul împărŃirii întregi);
• instrucŃiunea switch începe cu linia de program "switch (m)". Aceasta
înseamnă că alegerea uneia sau alteia dintre ramurile instrucŃiunii se va face în funcŃie de
valoarea variabilei m. Cazurile posibile sunt:
 (C1) m=4;
 (C2) m=6;
 (C3) m=8;
 (C4) m=10;
 (C5) default ⇒ m are orice altă valoare în afara celor de mai sus.
 Deoarece variabila m a primit anterior valoarea 6, rezultă că este îndeplinit
cazul (C2), deci se va executa instrucŃiunea aferentă acestuia: {cout << "Mediocru";}
Aşadar programul afişează şirul de caractere "Mediocru".
Răspuns corect: b).

AplicaŃie R.IV.12. Alegere


Să se alcătuiască un program care citeşte două numere reale a şi b, apoi
afişează media aritmetică, suma pătratelor sau suma cuburilor celor două numere,
în funcŃie de dorinŃa utilizatorului.
Rezolvare
:
 Pseudocodul (AplicaŃia R.II.6. din capitolul "Principiile programării structurate").

209
citeşte a,b;
citeşte opt;
alege (opt)
început
cazul 1:
scrie (a+b)/2;
ieşire
cazul 2:
scrie a*a+b*b;
ieşire
cazul 3:
scrie a*a*a+b*b*b;
ieşire
altfel
scrie “Eroare”;
sfârşit

 Programul:
#include <iostream.h>

void main ()
{
float a,b,ma,mg;
int opt;
// citeste numerele. a, b si selectorul opt; valorile "valide" ale lui opt vor fi 1,2,3
cout << "\n Introduceti numerele : ";
cin >> a >> b;
cout << "\n Ce doriti sa calculez ?";
cout << "\n Dati optiunea dvs, tastand o cifra:";
cout << "\n 1: media aritmetica";
cout << "\n 2: suma patratelor";
cout << "\n 3: suma cuburilor \n";
cin >> opt;
switch (opt) // alege in functie de valoarea selectorului opt
{
case 1: // daca opt=1, calculeaza media aritmetica, afisand-o direct
cout << "Media aritm=" << (a+b)/2;
break;
case 2: // daca opt=2, calculeaza suma patratelor, afisand-o direct
cout << "\n Suma patratelor=" << a*a+b*b;
break;
case 3: // daca opt=3, calculeaza suma cuburilior, afisand-o direct
cout << "\n Suma cuburilor=" << a*a*a+b*b*b;
break;
default: // pentru orice alta valoare a lui opt, in afara de 1,2,3, nu executa nimic
cout << "\n Optiune incorecta ! Abandonez !";
} // de la switch
}

ÎncercaŃi singuri !
ScrieŃi un program pentru algoritmul propus în tema T.7. din lecŃia "II.3.2.
Structura de selecŃie multiplă " (capitolul II).
210
AŃi înŃeles ? Probleme cu răspuns scurt
►1. Fie secvenŃa de #include <iostream.h>
program alăturată. Pentru care int x,y;
dintre perechile de valori ale void main()
{
variabilelor întregi x şi y date mai cin >> x >> y;
jos, secvenŃa afişează de două ori switch (x+y)
valoarea 0 ? {
case 1: y=y-1; break;
a) x=-4, y=5
case 2: x=0; y=0; break;
b) x=-1, y=3 case 0: x++; break;
c) x=0, y=0 default: break;
d) x=0, y=1 }
e) x=6, y=-2 cout << "x=" << x <<"\n y=" << y;
}
►2. În programul alăturat, ce #include <iostream.h>
atribuire poate fi scrisă în loc de "..." int a,b;
void main()
astfel încât să se afişeze 0 ?
{
b=1;
a) a=6; cout << "Introduceti a=";
b) a=7; cin >> a;
c) a=8; switch (a)
d) a=9; {
case 6: b=b && 1; break;
case 7: b=b && 0; break;
case 8: b=b || 1; break;
case 9: b=b || 0; break;
default: break;
}
cout << "b=" << b;
}

►3. Dacă în timpul execuŃiei programului de mai jos n va primi prin citire de la
tastatură valoarea 232213, care vor fi în final valorile variabilelor f1, f2 şi f3 ?
#include <iostream.h>
void main() switch (c) {
{ case 1: { f1++; break;}
long n; case 2: { f2++; break;}
unsigned int f1,f2,f3,c; case 3: { f3++; break;}
cin >> n; }
f1=f2=f3=0; } while (n!=0);
do { cout << f1 << f2 << f3;
c=n%10; }
n=n/10;
a) f1=1, f2=1, f3=1 c) f1=1, f2=3, f3=2 e) f1=3, f2=2, f3=1
b) f1=1, f2=2, f3=2 d) f1=2, f2=1, f3=3

211
Aprofundare

Probleme propuse

ScrieŃi programe pentru algoritmii propuşi în tema T.7. din lecŃia "2.3.2.
Structura de selecŃie multiplă" (capitolul II).

IV . 2. In str u c Ń i u n i r e pe ti ti v e ( c ic l u r i )

I V . 2 .1 . Ci c l u l c u t e s t i n i Ń i a l ( wh i l e - d o )

Reprezintă codificarea în limbajul C++ a structurii repetitive cu test iniŃial


pe care am descris-o în capitolul "Algoritmi. Principiile programării structurate".
cât timp (<expr>) execută while (<expr>)
<secv> <secv>
− unde <expr> este o condiŃie (expresie logică), iar <secv> este o
secvenŃă formată dintr-una sau mai multe instrucŃiuni, numită corpul ciclului.
Principiul de funcŃionare:
Atâta timp cât este îndeplinită condiŃia dată de <expr> (cât timp expresia
<expr> are valoarea 1), execută corpul ciclului <secv>:

1) se evaluează expresia logică <expr>


2) − dacă aceasta este adevărată, atunci se execută secvenŃa <secv>, apoi se
revine la pasul “1)” (între timp valoarea expresiei <expr> s-a putut
modifica);
− în caz contrar se trece la prima instrucŃiune de după ciclu.
ObservaŃii:
 Expresia logică <expr> va fi scrisă întotdeauna între paranteze rotunde;
 În cazul în care corpul ciclului conŃine cel puŃin două instrucŃiuni, acesta va fi
cuprins între acoladă deschisă şi închis;.
 Testarea condiŃiei are loc la început, deci corpul ciclului poate să nu se
execute niciodată.

Ex e mp l u :
Să se calculeze suma a n numere naturale citite pe rând de la tastatură
(unde n este cunoscut).
212
Pseudocodul acestei probleme a fost explicat pe larg în lecŃia "Structura repetitivă
cu test iniŃial" din capitolul "Principiile programării structurate". Reamintim pe scurt
algoritmul problemei. La fiecare execuŃie a corpului ciclului se citeşte un număr în
variabila x şi se adaugă la S, apoi se incrementează contorul i care ne spune la a câta
execuŃie ne aflăm. Variabila i se iniŃializează cu 1, iar ciclul se execută cât timp i<=n (se
citesc n numere).

#include <iostream.h>
void main () citeşte n;
{ S ← 0;
int i,n,x,S;
i ← 1;
cout << "\n n=";
cât timp (i<=n) execută
cin >> n;
început
S=0;
citeşte x;
i=1;
while (i<=n) S ← S+x;
{ i ← i+1;
cout << "\n x= "; cin >> x; sfârşit
S+=x; i++; scrie S;
}
cout << "\n S=" << S;
}

Algoritmi cu structuri repetitive cu test iniŃial

AplicaŃie R.IV.13. Problemă cu răspuns scurt


Ştiind că toate variabilele sunt de tip întreg, care dintre secvenŃele
următoare afişează 12 ?
a) i=1; b) i=1; S=7; c) a=1;
while (i<=2) while (i<=2) i=floor(0.2);
{ i++; S+=i; j=abs(-3);
cout << i; c o u t < < S; while (a)
i++; {
} i++; j--;

d) nici una dintre secvenŃele date. a=(i>j);


};
cout << i << j;
Rezolvare
:
Analizăm pe rând secvenŃele date.

 SecvenŃa a):
Contorul i se iniŃializează cu 1 şi cât timp i<=2 execută două instrucŃiuni:
tipăreşte valoarea lui i, apoi incrementează i cu 1. Paşii ciclului sunt următorii:
Pas 1: i<=2 ? 1< =2 ? da ⇒ scrie 1 şi i=i+1, i=1+1=2
Pas 2: i<=2 ? 2< =2 ? da ⇒ scrie 2 şi i=i+1, i=2+1=3
Pas 3: i<=2 ? 3< =2 ? nu ⇒ iese din ciclu
213
Prin urmare, s-au afişat cifrele 1 şi 2 "lipite" una de alta, simulându-se numărul
întreg 12 (enunŃul nu cere să se formeze în memorie numărul 12 !).

 SecvenŃa b):
Cât timp i<=2, se execută incrementarea i=i+1. AtenŃie, instrucŃiunea S+=i,
adică S=S+i, nu este în ciclu ! În absenŃa acoladelor deschisă şi închisă,, corpul ciclului
este considerat numai prima instrucŃiune de după linia ”while”. Valoarea iniŃială a lui i
este 1, deci după ieşirea din ciclu vom avea i=3 (ciclul are doi paşi, iar la finele celui de-al
doilea incrementarea i=i+1 va conduce la i=2+1=3). Apoi, după ciclu, atribuirea S=S+i
va avea ca rezultat S=7+3=10.

 SecvenŃa c):
Reamintim că funcŃia floor(0.2) trunchiază pe 0.2 la cel mai apropiat întreg
mai mic decât 0.2, deci returnează 0, iar funcŃia abs(-3) întoarce |-3| adică 3. Valorile
returnate de către cele două funcŃii se atribuie variabilelor i respectiv j. Prin urmare
valorile iniŃiale sunt a=1, i=0 şi j=3.
Cât timp a este diferit de 0 (condiŃie care este scrisă simplificat "while (a)" în
loc de "while (a!=0)"), execută trei atribuiri. Ultima dintre ele, "a=(i>j)", atribuie
variabilei a valoarea de adevăr a expresiei logice i>j. La primul pas al ciclului avem
i=i+1=1, j=j-1=2 şi a=0 (expresia "i>j" este falsă), apoi condiŃia "a!=0" din linia while
este deja falsă producând ieşirea din ciclu. În final, se afişează valorile variabilelor i şi j una
după alta, fără nici un separator între ele, tipărindu-se astfel 12.
Răspuns corect: a) şi c).

Sume şi produse cu n termeni

AplicaŃie R.IV.14. Produs de numere naturale impare


ScrieŃi pseudocodul unui algoritm care calculează produsul numerelor
naturale impare mai mici sau egale decât o valoare n dată.
Exemplu: pentru n=8 rezultă P=1⋅3⋅5⋅7=105, pentru n=9 se va calcula
P=1⋅3⋅5⋅7⋅9=945.

Rezolvare
:
 Algoritmul a fost explicat în aplicaŃia R.II.10. din lecŃia "II.4.1. Structura
repetitivă cu test iniŃial" (capitolul II).

 Pseudocodul:
citeşte n;
P←1; i←1;
cât timp (i<=n) execută
început
P←P*i; i←i+2;
sfârşit
scrie P;
214
 Programul:
#include <iostream.h>
void main ()
{
int P,i,n;
// citeste de la tastatura valoarea lui n
cout << "\n n=";
cin >> n;
// calculeaza produsul cerut in variabila P
P=1; i=1;
while (i<=n)
{
P*=i;
i+=2;
}
cout << "\n P=" << P;
}

ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în tema T.10. din lecŃia "II.4.1.
Structura repetitivă cu test iniŃial" (capitolul II).

Şiruri de numere citite pe rând

R.IV.15. Numărare într-un şir de numere a cărui citire


AplicaŃie
s e t e r mi n ă c u 0
Se dă un şir de numere care se citesc pe rând de la tastatură, atâta timp cât
nu s-a introdus valoarea 0 (care nu face parte din şir). Să se afişeze câte numere
pozitive sunt în şir.
Rezolvare
:
 Algoritmul a fost explicat în aplicaŃia R.II.11. din lecŃia "II.4.1. Structura
repetitivă cu test iniŃial" (capitolul II).
citeşte x;
#include <iostream.h> nr ← 0;
void main () cât timp (x ≠ 0) execută
început
{ dacă (x>0) atunci
int x,nr; nr ← nr+1;
cout << "\n x="; citeşte x;
cin >>x; sfârşit
nr=0; scrie nr;
while (x)
{
215
if (x>0)
nr++;
cout << "\n x=";
cin >>x;
}
cout << "\n nr=" << nr;
}

ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în tema T.11. din lecŃia "II.4.1.
Structura repetitivă cu test iniŃial" (capitolul II).

AplicaŃie R.IV.16. Maximul într-un şir de numere a cărui citire


se termină cu 0
Se dă un şir de numere care se citesc pe rând de la tastatură, atâta timp cât
nu s-a introdus valoarea 0 (care nu face parte din şir). Să se afişeze maximul dintre
elementele şirului.
Rezolvare
:
 Algoritmul a fost explicat în aplicaŃia R.II.10. din lecŃia "II.4.1. Structura
repetitivă cu test iniŃial" (capitolul II).
citeşte x;
max←x;
cât timp (x≠0) execută
început
dacă (x>max) atunci
max←x
citeşte x;
sfârşit
scrie max

 Programul:
#include <iostream.h>
void main ()
{
int x,max;
cout << "\n x="; cin >> x;
max=x;
while (x!=0)
{
if (x>max)
max=x;
cout << "\n x="; cin >> x;
}
cout << "\n Maximul este " << max;
}
216
ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în tema T.12. din lecŃia "II.4.1.
Structura repetitivă cu test iniŃial" (capitolul II).

Prelucrarea cifrelor unui număr natural

AplicaŃie R.IV.17. Suma cifrelor unui număr


RealizaŃi un algoritm care calculează suma cifrelor unui număr natural x
citit de la tastatură.
Rezolvare
:
 Algoritmul a fost explicat în aplicaŃia R.II.13. din lecŃia "II.4.1. Structura
repetitivă cu test iniŃial" (capitolul II).
citeşte x;
d ← x;
S ← 0;
cât timp (d≠0) execută
început
S ← S+d % 10;
d ← d / 10;
sfârşit
scrie S;

 Programul:
#include <iostream.h>
void main()
{
int S;
long d,x;
// citeste de la tastatura numarul x
cout << "\n x=";
cin >> x;
// initial deimpartitul d este chiar numarul x, iar suma cifrelor S este 0
d=x;
S=0;
// extrage cifrele lui x intr-un ciclu, adaugand la S fiecare cifra
while (d) // cat timp deimpartitul este diferit de 0
{
S+=d % 10; // adauga cifra extrasa d % 10 la suma cifrelo S
d=d/10; // catul impartirii curente, d / 10, va fi deimpartit pentru impartirea urmatoare
}
cout << "\n S=" << S;
}

217
ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în tema T.13. din lecŃia "2.4.1.
Structura repetitivă cu test iniŃial" (capitolul II).

AplicaŃie R.IV.18. Palindroame mai mici sau egale cu n


Numim "oglinditul unui număr natural x", numărul obŃinut prin citirea
cifrelor lui x în ordine inversă, de la dreapta la stânga. Exemplu: oglinditul lui
2435 este 5342. Numim palindrom un număr natural egal cu oglinditul său (citit
invers este acelaşi număr). Exemplu: numărul 232 este palindrom.
Se citeşte de la tastatură un număr natural n (n<=20000). Să se afişeze
toate palindroamele mai mici sau egale decât n. Exemplu: pentru n=135, se vor
afişa numerele:
1,2,3,4,5,6,7,8,9,11,22,33,44,55,66,77,88,99,101,111,121,131

Rezolvare
:
 Algoritmul a fost explicat în aplicaŃia R.II.14. din lecŃia "II.4.1. Structura
repetitivă cu test iniŃial" (capitolul II).

citeşte n;
i←1;
cât timp (i<=n) execută
început
d← i;
y← 0;
cât timp (d≠0) execută
început
c← d%10;
y← y*10+c;
d← d/10;
sfârşit
dacă (y==i) atunci
scrie i;
i←i+1;
sfârşit

 Programul:

#include <iostream.h>
void main ()
{
int i,c,n,d,y;
cout << "\n n="; cin >> n; // citeste n
i=1;
while (i<=n) // intr-un ciclul parcurgem numerele i=1,2,...,n
{
d=i;
218
y=0; // in y formam oglinditul lui i
while (d!=0)
{
c=d % 10;
y=y*10+c;
d/=10;
}
if (y==i) cout << i << ' '; // daca i este egal cu oglinditul sau y, il afisam
i++;
}
}

ÎncercaŃi singuri !
ScrieŃi un program pentru algoritmii propuşi în tema T.14. din lecŃia
"II.4.1. Structura repetitivă cu test iniŃial" (capitolul II).

Interpretarea unui pseudocod dat

ÎncercaŃi singuri !
ScrieŃi programe Pascal pentru toŃi algoritmii daŃi în pseudocod în
enunŃurile problemelor din temele T.15 şi T.16.

Algoritmi cu divizori şi factori primi

AplicaŃie R.IV.19. FracŃie zecimală


(Bacalaureat iulie 2009, varianta 25, enunŃ adaptat)
Se citeşte de la tastatură un număr real pozitiv x, care are cel mult două
cifre în partea întreagă şi cel mult şapte cifre după punctul zecimal. ScrieŃi un
program care, utilizând un algoritm eficient din punctul de vedere al memoriei
utilizate şi al timpului de executare, afişează pe ecran, separate printr-un spaŃiu,
două numere naturale al căror raport este egal cu x, şi a căror diferenŃă în modul
este minimă.
Exemplu: dacă se citeşte x=0.375, se vor afişa pe ecran numerele 3 şi 8
(deoarece 3/8=0.375, iar expresia |8-3| este cea mai mică dintre toate
diferenŃele în modul dintre numitorii şi numărătorii fracŃiilor prin care s-ar putea
scrie valoarea zecimală 0.375).
Rezolvare
:
Algoritmul acestei probleme a fost explicat pe larg în cadrul aplicaŃei R.II.17. din
cadrul lecŃiei "II.4.1. Structura repetitivă cu test iniŃial".

219
 Pseudocodul:

citeşte x;
q ← 1;
cât timp (x#[x]) execută
început
q ← q*10;
x ← x*10;
sfârşit
p ← x;
scrie p,q;
a ← p;
b ← q;
cât timp (a#b) execută
dacă (a>b) atunci
a ← a-b
altfel
b ← b-a;
d ← a;
p ← p/d;
q ← q/d;
scrie p,q;

 Programul:

// Bac 2008, II.4 / var 25


#include <iostream.h>
#include <conio.h>
#include <math.h>

void main ()
{
clrscr();
float x;
int a,b,d,p,q;
// citeste numarul real x
cout << "Dati numarul x: ";
cin >> x;
// p si q vor fi numaratorul si numitorul fractiei prin care poate fi scris numarul real x
// in mod repetat inmultim pe x cu 10, pana cand el nu mai contine zecimale
q=1;
// prin variabila q tinem minte cate inmultiri facem
// iar valoarea finala a lui q va fi numitorul fractiei
while (x!=floor(x))
{
q=q*10;
x=x*10;
}
p=x; // valoarea finala a lui x va fi numaratorul fractiei
cout << " numarat si numit fractiei sunt " << p << " si " << q;
// aflam c.m.m.d.c al lui p si q, fie acesta d
a=p;
b=q;
220
while (a!=b)
if (a>b)
a=a-b;
else
b=b-a;
d=a;
// simplificam la maximum posibil fractia p/q, prin c.m.m.d.c. al lui p si q
p=p/d;
q=q/d;
cout << "\n numarat si numit fractiei sunt " << p << " si " << q;
getch();
}

ÎncercaŃi singuri !
ScrieŃi un program pentru algoritmii propuşi în tema T.17. din lecŃia
"II.4.1. Structura repetitivă cu test iniŃial" (capitolul II).

AplicaŃie R.IV.20. Număr prim


ScrieŃi un algoritm care verifică dacă un număr natural x diferit de 0 şi 1,
este prim sau nu, afişând un mesaj corespunzător.
Rezolvare
:
 Algoritmul a fost explicat în aplicaŃia R.II.18. din lecŃia "II.4.1. Structura
repetitivă cu test iniŃial" (capitolul II). Am prezentat atunci doua varinate de pseudocod:
prima descrie algoritmul “clasic”, iar a doua aduce nişte îmbunătăŃiri care vizează
eliminarea unor operaŃii inutile. Prezentăm şi programele corespunzătoare pentru ambele
variante.

 Varianta A:
citeşte x;
ok ← 1;
i ← 2;
cât timp (i<= x / 2 ŞI ok==1) execută
început
dacă (x % i=0) atunci
ok ← 0;
i ← i+1;
sfârşit
dacă (ok==1) atunci
scrie "Numărul este prim";
altfel
scrie "Numărul NU este prim";

Programul:

#include <iostream.h>
void main ()

221
{
int x,i,ok;
// citeste numarul x de la tastatura
cout << "\n x=";
cin >> x;
// variabila ok va memora "starea" conditiei testate: TRUE daca x este prim,
// respectiv FALSE in caz contrar; initial, presupunem ca x este prim
ok=1;
// prin variabila i vor "trece"posibilii divizori ai lui x, 2,3,...,x div 2
i=2;
// cat timp nu am parcurs toti divizorii posibili si nu am gasit inca un divizor
while (i<=x/2 && ok)
{
// daca valoarea curenta a lui x este divizor al lui x, atunci x nu mai poate fi prim
if (x%i==0)
ok=0;
i++; // trecem la urmatorul posibil divizor i
}
// in final, testam valoarea variabilei ok, afisand un mesaj corespunzator
if (ok)
cout << "\n Numarul este prim";
else
cout << "\n Numarul nu este prim";
}

 Varianta B:
citeşte x;
dacă (x % 2==0
dacă (x==2)
ok ← 1
altfel
ok ← 0
altfel
început
i ← 2;
cât timp (i<=x/2 ŞI ok==1)
început
dacă (x % i==0)
ok ← 0;
i ← i+1;
sfârşit
sfârşit
dacă (ok==1)
scrie "Numărul este prim";
altfel
scrie "Numărul NU este prim";

Programul:

#include <iostream.h>
void main ()
{
int x,i,ok;
222
// citeste numarul x de la tastatura
cout << "\n x=";
cin >> x;
// numerele pare nu pot fi prime, cu exceptia lui 2 care este considerat prim
if (x % 2=0)
if (x==2)
ok=1;
else
ok=0;
else
{
// daca numarul x este impar, se aplica algoritmul de cautare a divizorilor din var. anterioara
ok=1;
i=2;
while (i<=x/2 && ok)
{
if (x%i==0)
ok=0;
i++;
}
}
if (ok)
cout << "\n Numarul este prim";
else
cout << "\n Numarul nu este prim";
}

ÎncercaŃi singuri !
ScrieŃi un program pentru algoritmii propuşi în tema T.18. din lecŃia
"II.4.1. Structura repetitivă cu test iniŃial" (capitolul II).

AplicaŃie R.IV.21. Descompunerea unui număr în factori primi


Să se afişeze descompunerea unui număr natural dat x în factori primi,
evidenŃiind factorii primi împreună cu puterile la care apar în descompunere.
Exemplu: pentru x=720, descompunerea este 24⋅32⋅5, iar programul va afişa:
2 4
3 2
5 1

Rezolvare
:
Algoritmul problemei a fost explicat pe larg în pseudocod în cadrul problemei
rezolvate R.II.10., din capitolul “II.4.1. Structura repetitivă cu test iniŃial ”

223
 Pseudocodul:
citeşte x;
d← x;
f← 2;
cât timp (d>1) execută
început
p← 0;
cât timp (d % f==0) execută
început
d← d / f;
p← p+1
sfârşit
dacă (p≠0) atunci
scrie f,'^',p,'*';
f← f+1;
sfârşit
sfârşit

 Programul:
#include <iostream.h>
void main ()
{
int x,d,f,p,nr;
cout << "\n x=";
cin >> x; // citeste in variabila x numarul ce trebuie descompus
d=x; // initial deimpartitul este chiar numarul x
f=2; // in f se vor memora factorii; primul factor posibil este 2
while (d>1)
{
// determina puterea p la care apare factorul f in descompunerea numarului
p=0;
while (d % f==0)
{
d=d / f;
p++;
}
// afiseaza factorul f impreuna cu puterea sa p
if (p!=0)
cout << f << "^" << p << "*";
f++;
}
}

ÎncercaŃi singuri !
ScrieŃi un program pentru algoritmii propuşi în tema T.19. din lecŃia
"II.4.1. Structura repetitivă cu test iniŃial" (capitolul II).

224
AŃi înŃeles ? Probleme cu răspuns scurt
►1. (Bacalaureat iulie 2008, varianta 6)
Pentru care dintre următoarele valori ale variabilei n, secvenŃa de program de
mai jos afişează valoarea 0 în urma executării ei ?
while (n%10>=2)
n/=10;
cout << n;

a) 1111 b) 9282 c) 3003 d) 1345


►2 . (Bacalaureat iulie 2008, varianta 9)
DeduceŃi valorile pe care le vor primi variabilele x şi y, după execuŃia secvenŃei
de program de mai jos:
x=1;
y=11;
while (x<=y)
{
x++;
y--;
}

►3. Pentru n=7, care dintre secvenŃele de program de mai jos trebuie executată
astfel încât, la finele execuŃiei, valoarea variabilei P să fie 48 ?
a) b)
P=1; i=2; P=i=1;
while (i<=n) while (i < n/2)
{ {
P*=i; i++;
i+=2; P=P*(2*i+1);
} }
c) d)
P=i=1; P=1; i=-1;
while (i<=n/2) while (i<n)
{ {
P=P*(2*i); i+=2;
i++; P*=i;
} }

►4. SecvenŃa de program următoare afişează valoarea ....


#include <iostream.h> a) 416
void main() b) 0
{ c) 36
int n=1008,m=416; d) programul este greşit, deoarece produce o
while (n!=m)
if (n<m) împărŃire la 0
m=m%n;
else
n=n%m;
cout << n;
}

225
►5. (Bacalaureat iulie 2001, varianta 2)
Ştiind că x şi y desemnează variabile y=x;
întregi, determinaŃi valoarea iniŃială a variabilei while (x<=3)
{
x astfel încât secvenŃa dată să afişeze exact un
cout << "*";
asterisc (*). y++;
a) -4 b) -2 c) 0 d) 1 x+=y;
}
e) 2 f) 4 g) 5
}

►6. (Bacalaureat august 2000, varianta 1)


Care dintre următoarele secvenŃe de instrucŃiuni atribuie variabilei întregi u
valoarea ultimei cifre a numărului natural reprezentat de variabila x ?
a) u=x / 10; b) u=x;
while (u>10) u=u % 10;
c) u=x % 10; d) while (x>=10) x=x / 10;
u=x;

►7. Care dintre secvenŃele de program de mai jos afişează toate cifrele sistemului
zecimal, în ordine descrescătoare de la 9 la 0 ?
{SecvenŃa S1} {SecvenŃa S2}
i=9; i=0;
while (i>=0) while (i<9)
{ {
j=0; j=1;
while (j<i) while (j<9-i)
j++; j++;
cout << j << " "; cout << j << " ";
i--; i++;
} }

a) Numai secvenŃa S1 b) Numai secvenŃa S2


c) Atât secvenŃa S1 cât şi S2 d) Nici una dintre cele două secvenŃe

Următoarele patru probleme se referă la secvencŃa de mai jos, descrisă în


pseudocod:
cin >> n;
q=1;
while (n>0)
{
if (n%5==0)
q=q*10;
else
q=q*10+1;
n=n/5;
}
cout << q;

►8. (Bacalaureat iulie 2009, varianta 58)


DeduceŃi valoarea afişată pentru n=53;

226
►9. (Bacalaureat iulie 2009, varianta 58)
GăsiŃi un număr de două cifre care ar putea fi citit în variabila n, astfel încât
programul să afişeze 1001.
►10. RescrieŃi instrucŃiunea de selecŃie prezentă în cadrul secvenŃei anterioare,
inversând ramurile “if” şi “else” între ele.
►11. Ştiind că toate variabilele din secvenŃa anterioară pot memora doar numere
naturale cu maxim patru cifre, scrieŃi declaraŃiile de variabile optime din punctul de vedere
al spaŃiului de memorie rezervat.
►12. (Bacalaureat iulie 2008, varianta 18)
Câte atribuiri au loc în total în timpul execuŃiei secvenŃei de program de mai jos,
în cazul în care variabila nu are valoarea 245?
S=0;
while (n)
{
S++;
n/=100;
}

►13. Ştiind că a şi b sunt numere întregi citite de la tastatură cu a> =b, precizaŃi
ce secvenŃă de instrucŃiuni trebuie scrisă în loc de "..." în secvenŃa următoare, aşa încât
valoarea variabilei r să reprezinte cel mai mare divizor comun al numerelor a şi b.
r=0;
while (a % b)
{
......
}

a) a=b; b=r; r=a % b; b) b=a; a=r; r=a % b;


c) r=a % b; b=a; a=r; d) r=a % b; a=b; b=r;

►14. (Bacalaureat, iulie 2002, varianta 3)


Care este valoarea iniŃială a while (n>0)
variabilei întregi n astfel încât la sfârşitul {
cout << (n % 10);
execuŃiei următoarei secvenŃe de
n=n / 10-1;
instrucŃiuni rezultatul afişat pe ecran să }
fie 503 ?
a) 305 b) 415 c) 425 d) 503

►15. (Bacalaureat, iulie 2002, varianta 5)


Ştiind că valoarea iniŃială a variabilei întregi i este mai mare decât 10, stabiliŃi
care este valoarea expresiei abs(3-i) la sfârşitul executării următoarei instrucŃiuni.
while (i > 4) i--;
a) -1 b) 0
c) 1 d) 2
e) o valoare nedeteminată

227
►16. Ce valoare se afişează în urma execuŃiei secvenŃei de mai jos ?
i=4; S=0;
while (i<=10)
i++; S+=i;
cout << "\n" << S;
a) 0 b) 10 c) 49 d) 11

►17. (Bacalaureat iulie 2008, varianta 20)


Care trebuie să fie valoarea iniŃială a variabilei n, astfel încât, la sfârşitul
execuŃiei secvenŃei de mai jos să se afişeze valoarea 3 ?
c=0; a) 123
while (n%10==0) b) 10020
{
n/=10; c) 5000
c++; d) 10001
}

►18. (Bacalaureat iulie 2008, varianta 67)


Pentru secvenŃa de program de mai jos în care variabilele i şi j sunt de tip
întreg, alegeŃi o valoare iniŃială pentru variabila j, astfel încât executarea secvenŃei să se
realizeze în timp finit.
i=0;
j=...;
while (i+j<=10)
{
i++;
j-=2;
}

a) 6 b) 1 c) 5 d) 17
►19. (Bacalaureat iulie 2008, varianta 39)
În secvenŃa de program de mai jos, ştiind că de la tastatură se citeşte valoarea
n=234, deduceŃi ce valoare se afişează după executarea secvenŃei.
cin >> n;
x=1;
while (n>0)
{
x*=n%10;
n/=10;
}
cout << x;

228
Aprofundare

Probleme rezolvate

R.IV.22 Cif r e î nt r eg i ş i c if re z e ci ma le
(Bacalaureat iulie 2009, varianta 77, enunŃ adaptat)
ScrieŃi un program care citeşte de la tastatură trei numere naturale n, p şi k
(0<n<100, 0<k<5, 0<p<5), precum şi un şir de n numere reale, apoi determină şi
afişează pe ecran numărul de valori citite care au exact p cifre în partea întreagă şi
mai mult de k zecimale.
Exemplu: pentru n=6, k=2, p=2 şi şirul (6.2 41.234 2 8.131
10.0012), programul va afişa numerele 41.234 şi 10.0012.
Rezolvare
:
 Pseudocodul acestui algoritm a fost explicat pe larg în cadrul aplicaŃiei R.II.20
din cadrul lecŃiei "II.4.1 Structura repetitivă cu test iniŃial" (capitolul II).

Pseudocodul:

citeste p,k,n;
nr← 0;
i←1;
cât timp (i<=n) execută
început
citeşte x;
d=[x];
nr1← 0;
cât timp (d#0) execută
început
d← [d/10];
nr1←nr1+1;
sfârşit
y←x;
nr2← 0;
cât timp (y#[y]) execută
început
y← y*10;
nr2←nr2+1;
sfârşit
dacă (nr1=p) ŞI (nr2>k) atunci
început
scrie x;

229
nr← nr+1;
sfârşit
i←i+1;
sfârşit
scrie nr;

Programul:

// Bac 2009, var 77


#include <iostream.h>
#include <conio.h>
#include <math.h>

void main ()
{
int n,p,k;
int i=1,nr=0,nr1,nr2,b,d;
float x,y;
clrscr();
cout << "Dati p si k: "; cin >> p >> k;
cout << "Dati numarul de termeni ai sirului: ";
cin >> n;
// citim cele n numere intr-un ciclu in care contorul i=1,2,...,n numara citirile
while (i<=n)
{
cout << endl << "Dati termenul cu nr de ordine " << i << " : ";
cin >> x;
// determinam nr1 = numarul de cifre din partea intreaga a valorii citite x
nr1=0;
b=floor(x);
d=b;
while(d)
{
d/=10; nr1++;
}
// determinam nr2 = numarul de zecimale ale valorii citite x
nr2=0;
y=x;
while (y!=floor(y))
{
y*=10;
nr2++;
}
// testam daca x are exact p cifre in partea intreaga si mai mult de k zecimale
// iar in caz afirmativ incrementam nr
if (nr1==p && nr2>=k)
{
nr++;
cout << endl << " x=" << x;
}
i++;
}
cout << "\nSunt " << nr << " numere cu proprietatea ceruta";
getch();
}
230
R.IV.23 Am e st ec a r ea cif r el o r
(Bacalaureat iulie 2008, varianta 17)
Pentru două numere naturale m şi n, cu maximum nouă cifre fiecare, citite
de la tastatură, numere care au cifrele în ordine crescătoare, se cere să se afişeze pe
ecran cel mai mare număr care se poate forma cu toate cifrele lui m şi n la un loc.
AlegeŃi un algoritm eficient de rezolvare.
Exemplu: pentru m=35679 şi n=123789, se va tipări 99877653321.

Rezolvare
:
 Pseudocodul acestui algoritm a fost explicat pe larg în cadrul aplicaŃiei R.II.21
din cadrul lecŃiei "II.4.1 Structura repetitivă cu test iniŃial" (capitolul II).
Mai trebuie doar să atragem atenŃia asupra necesităŃii de a declara variabilele m şi
n ca fiind de tipul long (întreg lung), deoarece acestea, conform enunŃului, pot avea până
la nouă cifre fiecare.

 Pseudocodul:
citeşte m, n;
cât timp (m>0 SI n>0) execută
dacă (m%10>=n%10) atunci
început
scrie m%10;
m ← [m/10];
sfârşit
altfel
început
scrie n%10;
n ← [n/10];
sfârşit

 Programul:

#include <iostream.h>
#include <conio.h>
void main ()
{
long m,n;
clrscr();
cout << "Dati numerele m si n: ";
cin >> m >> n;
cout << endl << "Numarul cautat este: ";
while (m>0 || n>0)
if (m%10>=n%10)
{
cout << m%10;
m=m/10;
}
else
231
{
cout << n%10;
n=n/10;
}
}

R.IV.24 P r ob le ma cr o i to r u lu i
Un croitor are o bucată de stofă de lungime L dată, şi vrea să obŃină numai
bucăŃi de stofă de lungime mai mici sau egale decât un metru. Pentru aceasta,
procedează astfel: taie bucata de stofă în jumătate, apoi taie fiecare bucată obŃinută
din nou în jumătate, ş.a.m.d. Să se determine câte tăieturi face croitorul pentru a
obŃine bucăŃi mai mici sau egale decât un metru.
Rezolvare
:
Algoritmul problemei a fost explicat pe larg în pseudocod în cadrul problemei
rezolvate R.II.22. din secŃiunea “Aprofundare ”, capitolul “II.4.1. Structura repetitivă cu
test iniŃial ”

 Pseudocodul:
citeşte L
p← 1
nr_total←0
L0← L
cât timp (L0> =1) execută
început
L0← L0/2
nr← 1
i←1
cât timp (i<=p-1) execută
început
nr← nr*2
i← i+1
sfârşit
scrie p
nr_total← nr_total+nr
p← p+1
sfârşit
scrie nr_total

 Programul:
#include <iostream.h>
void main ()
{
int i,p,nr,nr_total;
float L,L0;
cout << "\n Lungimea : ";
cin >> L;
p=1;
232
nr_total=0;
L0=L;
while (L0>1)
{
L0/=2;
nr=1;
i=1;
while (i<=p-1)
{
nr*=2;
i++;
}
cout << "\n La pasul " << p << " sunt " << nr << " taieturi";
nr_total+=nr;
p++;
}
cout << "\n In total sunt " << nr_total << " taieturi";
}

Probleme propuse
Folosind cicluri cu test iniŃial, scrieŃi programe pentru toŃi algoritmii
propuşi în tema T.R.3. de la sfârşitul capitolului II (secŃiunea ”Probleme
recapitulative pentru toate tipurile de cicluri”).

Extindere

În această secŃiune vom prezenta unele facilităŃi ale limbajului C++ în


materie de cicluri cu test iniŃial. Este vorba despre posibilitatea de a îngloba în
expresia logică din linia “while” diverse alte expresii: incrementări, atribuiri,
expresii condiŃionale, etc. Aceste “artificii” permit reducerea dimensiunilor
programului.
Începem cu exemplul care a fost prezentat în partea de teorie, la începutul
lecŃiei.
Exemplu: Să se calculeze suma a n numere naturale citite pe rând de la
tastatură (unde n este cunoscut).
Reamintim pe scurt algoritmul problemei. La fiecare execuŃie a corpului ciclului
se citeşte un număr în variabila x şi se adaugă la S, apoi se incrementează contorul i care
ne spune la a câta execuŃie ne aflăm. Variabila i se iniŃializează cu 1, iar ciclul se execută
cât timp i<=n (se citesc n numere).

233
#include <iostream.h>
void main ()
{
int i,n,x,S;
cout << "\n n=";
cin >> n;
S=0;
i=1;
while (i<=n)
{
cout << "\n x= ";
cin >> x;
S+=x; i++;
}
cout << "\n S=" << S;
}

În linia “while”, condiŃia de continuare a ciclului este expresia logică “i<=n”.


După cum ştiŃi deja, în C++ o expresie logică poate să conŃină operaŃii de incrementare /
atribuire. Urmărind programul de mai sus, vă rugăm să răspundeŃi la următoarea întrebare:
există în corpul ciclului vreo operaŃie de incrementare / atribuire care ar putea fi înglobată
în expresia logică din linia “while” ? Răspunsul este foarte simplu ! Incrementarea lui i
(i++), cu care se încheie corpul ciclului poate fi adusă în linia “while” ! Cum anume ?
Iată !
#include <iostream.h>
void main ()
{
int i,n,x,S;
cout << "\n n=";
cin >> n;
S=0;
i=1;
while (i++<=n)
{
cout << "\n x= ";
cin >> x;
S+=x;
}
cout << "\n S=" << S;
}

Cum se execută expresia logică “i++<=n” din linia “while” ? După cum aŃi
învăŃat, atunci când într-o expresie operatorul de incrementare “++” apare în formă
postfixată (este scris după identificatorul variabilei căreia i se aplică), “mecanismul” de
funcŃionare este următorul:
− mai întâi se evaluează expresia logică fără operatorul de incrementare, adică
expresia “i<=n”, folosind valoarea curentă a lui i;
− apoi se execută incrementarea lui i, respectiv operaŃia i++, echivalentă cu
i=i+1;
ObservaŃi că în esenŃă nu s-a schimbat nimic faŃă de prima variantă a
programului. Atâta doar că, la fiecare pas al ciclului, incrementarea lui i, în loc să se

234
execute în timpul “derulării” corpului ciclului, are loc în linia while, dar după testarea
condiŃiei. Cu alte cuvinte, la fiecare pas “scenariul” este următorul: se testează condiŃia din
linia while cu valoarea curentă a lui i, apoi se execută incrementarea i++, şi apoi se
execută corpul ciclului. Nu ne supără cu nimic faptul că incrementarea i++ a fost “ruptă”
de corpul ciclului, atâta vreme cât ea se execută la fiecare pas !
Pentru a fi siguri că aŃi înteles cu adevărat cum stau lucrurile, vă propunem să
modificaŃi programul astfel încât operatorul de incrementare “++” să apară în formă
prefixată în expresia logică din linia “while”. Evident, expresia logică va fi acum
“++i<=n”. În acest caz, mai întâi se incrementează i, apoi se execută testarea condiŃiei
“i<=n” cu noua valoare a lui i. Din punctul de vedere al modului în care se derulează paşii
ciclului, este acelaşi lucru, dar apare o mică problemă vis-a-vis de intrarea în ciclu:
valoarea iniŃială a lui i trebuie să fie 0 în loc de 1. Ce s-ar întâmpla dacă această valoare ar
rămâne 1 ? Prima operaŃie care s-ar executa la începutul primului pas al ciclului ar fi
incrementarea lui i, deci i ar deveni imediat 2, din care cauză primul pas al ciclului s-ar
executa mai departe pentru i=2. Altfel spus, s-a sărit peste i=1, ceea ce înseamnă că se va
citi şi se va însuma cu un număr mai puŃin.
#include <iostream.h>
void main ()
{
int i,n,x,S;
cout << "\n n=";
cin >> n;
S=0;
i=0;
while (++i<=n)
{
cout << "\n x= ";
cin >> x;
S+=x;
}
cout << "\n S=" << S;
}

În continuare vom vedea că în linia “while” putem îngloba nu numai


incrementări, ci şi diverse operaŃii de atribuire.
ScrieŃi pseudocodul unui algoritm care calculează produsul numerelor
naturale impare mai mici sau egale decât o valoare n dată.
Exemplu: pentru n=8 rezultă P=1⋅3⋅5⋅7=105, pentru n=9 se va calcula
P=1⋅3⋅5⋅7⋅9=945.
Varianta “clasică” a fost prezentată în cadrul problemei rezolvate R.IV.14.
#include <iostream.h>
void main ()
{
int P,i,n;
cout << "\n n=";
cin >> n;
P=1; i=1;
while (i<=n)
235
{
P*=i;
i+=2;
}
cout << "\n P=" << P;
}

Încercăm acum să înglobăm atribuirea “i+=2”, adică i=i+2, în linia “while”.


Iată cum arată programul astfel modificat:
#include <iostream.h>
void main ()
{
int P,i,n;
cout << "\n n="; cin >> n;
P=1; i=1;
while ((i+=2)<=n)
P*=i;
cout << "\n P=" << P;
}
Ce înseamnă expresia “(i+=2)<=n” pe care o avem acum în linia “while” ? La
fiecare pas al ciclului:
− mai întâi se execută atribuirea i=i+2;
− apoi se face testarea condiŃiei “i<n” cu noua valoare a lui i;
− în sfârşit, se execută corpul ciclului care acum conŃine doar instrucŃiunea “P*=i”.
Privind cu atenŃie, observaŃi că faŃă de versiunea “clasică” apare o deosebire
esenŃială: la fiecare pas al ciclului, atribuirea “i+=2” se execută înaintea instrucŃiunii
“P*=i”, şi nu după ! Acest lucru se observă cu uşurinŃă dacă analizăm primul pas: se intră
in ciclul cu valoare iniŃială i=1, se execută prima dată atribuirea “i+=2” în urma căreia
contorul i va primi valoarea 3, după care se testează condiŃia “i<=n” cu noua valoare i=3.
Este corect ? Nu, deoarece prima valoare a lui i, adică 1, a fost “sărită” complet, deşi, aşa
cum se vede din exemplele numerice date în enunŃ, ea trebuie înmulŃită la produs. În mod
întâmplător, lipsa înmulŃirii cu 1 nu influenŃează rezultatul, dar ... ce ne-am fi făcut dacă s-
ar fi cerut de exemplu suma numerelor naturale impare mai mici sau egale decât n ? În
acest caz, valoarea 1 trebuia şi ea adaugată la sumă, lucru pe care nu-l face versiunea
“îmbunataŃită” a programului ! Cum poate fi eliminată această mică deficienŃă ? Foarte
simplu ! Modificăm valoarea iniŃiala a lui i: înaintea ciclului, în loc de “i=1” vom scrie
“i=-1”. În felul acesta, în urma primei executări a atribuirii “i+=2” de la începutul
primului pas, rezultă i=-1+2=1, deci se “procesează” şi valoarea 1 a lui i. În rest, nu se
modifică nimic.
#include <iostream.h>
void main ()
{
int P,i,n;
cout << "\n n="; cin >> n;
P=1; i=-1;
while ((i+=2)<=n)
P*=i;
cout << "\n P=" << P;
}

236
În continuare vom vedea că în linia “while” a unui ciclu cu test iniŃial
putem avea chiar şi o expresie condiŃională.
#include <iostream.h>
void main ()
{
int i=1, P=1, n=5;
while(i<=n ? P*=i++ : 0);
cout << P;
}

În linia "while", avem o expresie condiŃională: "i<=n ? P*=i++ : 0", care


înseamnă:
♦ Dacă i<=n, atunci se execută atribuirea P*=i++;
♦ În caz contrar, nu se execută nimic, sau mai bine zis se execută expresia "0" .
Dar atribuirea "P*=i++" înseamnă:
− P=P*i; (se execută atribuirea P*=i cu valoarea curentă a lui i)
−i=i+1; (se incrementează i)
Expresia "0" de după operatorul ":" a fost introdusă, deoarece într-o instrucŃiune
condiŃională este obligatoriu să existe atât expresia de după operatorul "?", cât şi cea de
după ":".
Dar de ce "0" şi nu altceva ? Ştim că valoarea unei expresii condiŃionale de forma
"<exp_1> ? <exp_2> : <exp_3>" este egală cu valoarea aceleia dintre expresiile
<exp_2> şi <exp_3> care se execută (după cum condiŃia dată de <exp_1> este adevărată
sau nu). În cazul nostru, aşa cum spuneam, în momentul în care condiŃia dată de expresia
"i<=n" nu mai este adevărată, adică dacă i este mai mare decât n, atunci se va executa
expresia "0", iar valoarea întregii expresii condiŃionale "i<=n ? P*=i++ : 0" din linia
while, va deveni zero. ConsecinŃa ? Se va executa "while(0)", care, intuitiv, se poate citi
"cât timp este fals ". E clar că în acest moment se va produce ieşirea din ciclu !
Mai trebuie observat că linia while se încheie cu caracterul ";", adică
instrucŃiunea vidă. Aceasta reprezintă corpul ciclului. E normal să fie aşa, deoarece
atribuirile care ar fi trebuit să alcătuiască corpul ciclului, "P=P*i" şi "i=i+1", au fost
înglobate sub forma "P*=i++" în expresia condiŃională din linia while !
Acum putem scrie o formă echivalentă "clasică" pentru secvenŃa dată:
P=1; i=1; n=5;
while (i<=n)
{
P=P*i; i=i+1;
}
Întrucât secvenŃe de program de acest gen au fost prezentate în problemele
anterioare, vă lăsăm să vă daŃi singuri seama că secvenŃa anterioară calculează corect
produsul P=1*2*...*n. În cazul nostru, pentru n iniŃializat cu valoarea 5 secvenŃa
afişează numărul 120, reprezentând produsul 1*2*3*4*5.

237
ÎncercaŃi singuri !
►1. RescrieŃi programul pentru calculul celui mai mare divizor comun a şi b,
înlocuind sctructura “if-else” din corpul ciclului, cu o expresie condiŃională, plasată în
linia “while”.
►2. RescrieŃi programul care calculează suma numerelor naturale impare mai
mici sau egale decât o valoare n dată, astfel încât tot corpul ciclului să fie “condensat” în
linia “while”.
►3. Care dintre şirurile de valori date în variantele de răspuns trebuie introduse
de la tastatură în timpul execuŃiei programului următor, astfel încât să se declanşeze un
ciclu infinit ?
#include <stdio.h>
void main ()
{
int x,y;
while (scanf("%d",&x)==1 && scanf("%d",&y)==1 && (x || y))
do {
y--;
printf("*%d *%d",x,y);
} while(x!=y);
}
a) 2,7,3,8,0,0 b) 2,5,4,4,0,0 c) 1,3,6,2,0,0
d) 2,4,5,8,0,0 e) 0,0
►4. Fie secvenŃa de program următoare, în care:
• variabilele i, n şi S sunt întregi;
• <v1>, <v2>, <v3> simbolizează valori constante întregi;
• <cond> este o condiŃie (expresie logică).

AlegeŃi de mai jos valorile <v1>, <v2>, <v3>, precum şi condiŃia <cond>, astfel
încât programul să afişeze suma cifrelor naturale 1+2+...+9.
n=<v1>; i=<v2>; S=<v3>;
while ( <cond> )
S+=i++;
printf("%d",S);
a) <v1> ← 10, <v2> ← 1, <v3> ← 0, şi condiŃia "i<n";
b) <v1> ← 10, <v2> ← 1, <v3> ← 0, şi condiŃia "i<=n";
c) <v1> ← 10, <v2> ← 0, <v3> ← 0, şi condiŃia "i<n";
d) <v1> ← 9, <v2> ← 1, <v3> ← 0, şi condiŃia "i<n";
e) <v1> ← 9, <v2> ← 2, <v3> ← 1, şi condiŃia "i<=n";

238
I V.2.2 . Cicl u cu test final (do- while)

Implementează în limbajul Pascal structura repetitivă cu test final, care a


fost de asemenea explicată în capitolul "Algoritmi. Principiile programării
structurate".
do − unde <expr> este o condiŃie (expresie logică), iar
<secv>
while (<expr>); <secv> este o secvenŃă formată dintr-una sau mai
multe instrucŃiuni, numită corpul ciclului.
Principiul de funcŃionare:

Repetă execuŃia secvenŃei de instrucŃiuni <secv>, până când expresia


logică <expr> ia valoarea 1 (până când condiŃia aferentă devine adevărată).
1) se execută secvenŃa de instrucŃiuni <secv>;
2) se evaluează expresia logică <expr>;
• dacă condiŃia dată de <expr> este adevărată, adică dacă expresia <expr>
are valoarea 1, atunci se revine la pasul ”1)”;
• în caz contrar, se iese din ciclu şi se execută prima instrucŃiune de după
ciclu.
ObservaŃii:
 La fel ca şi în cazul structurii repetitive cu test iniŃial, expresia <expr> din
linia ”cât timp” se va pune între paranteze rotunde
 În cazul în care secvenŃa de instrucŃiuni <secv> ce reprezintă corpul
ciclului conŃine mai mult de o instrucŃiune, ea va fi cuprinsă între acoladă
deschisă şi închisă;
 Deoarece testarea are loc la sfârşit, corpul unui ciclu cu test final se va
executa cel puŃin o dată.

Exemplu:
Să se calculeze suma a n numere naturale citite pe rând de la tastatură
(unde n este cunoscut).
Problema a fost deja rezolvată în varianta cu ciclu cu test iniŃial, iar pseudocodul
în varianta cu ciclu cu test final vă este de asemenea deja cunoscut din capitolul
"Algoritmi. Principiile programării structurate", lecŃia "Structura repetitivă cu test final".
De aceea, considerăm inutile orice alte explicaŃii.

#include <iostream.h>
void main ()
{
int S,i,x,n;
239
cout << "\n n="; citeşte n;
cin >> n; S ← 0;
S=0;
i ← 1;
i=1;
execută
do
început
{
citeşte x;
cout << "\n x=";
cin >> x; S ← S+x;
S+=x; i ← i+1;
i++; sfârşit
} while (i<=n); cât timp (i<=n);
cout << "S=" << S; scrie S;

AplicaŃie R.IV.25. Afişarea unui şir de litere


(Bacalaureat iulie 2001, varianta 1)
Care trebuie să fie valoarea iniŃială a variabilei întregi i pentru ca
următoarea secvenŃă să afişeze şirul "AAAAAA"?
do
{
cout << "AA";
i--;
} while (i!=3);
a) 0 b) 1 c) 2 d) 3 e) 4 f) 5 g) 6 h) nu există nici o valoare

Rezolvare
:
 La un pas al ciclului do-while se afişează două caractere 'A' {cout <<
"AA";}, iar în total trebuie tipărite şase astfel de caractere. În consecinŃă, ciclul trebuie să
aibă trei paşi. Pornind de la o anumită valoare iniŃială pe care se cere să o aflăm, contorul i
se decrementează cu 1 la fiecare pas {i--, adică i=i-1}, până când ajunge la valoarea 3.
ObservaŃi că imediat după ce i a ajuns la valoarea 3, urmează testarea "i!=3" din linia
while, deci afişarea şirului 'AA' nu se face şi pentru valoarea 3 (imediat după ce i a
primit valoarea 3 prin execuŃia decrementării i--, urmează testarea condiŃiei din linia
while care înseamnă “3≠3”, cu rezultat FALS). Drept urmare, valorile lui i pentru care
are loc afişarea respectivă vor fi cele mai mari decât 3. Întrucât am stabilit că sunt necesare
trei astfel de valori, rezultă că acestea vor fi 6, 5, 4. Aşadar valoarea iniŃială a lui i va fi 6.
Răspuns corect: g)

AplicaŃie R.IV.26. Produs de numere impare


ScrieŃi un algoritm care calculează produsul numerelor naturale pare
nenule mai mici sau egale decât o valoare n dată.
Exemplu: pentru n=8 rezultă P=1⋅3⋅5⋅7=105, pentru n=9 se va calcula
P=1⋅3⋅5⋅7⋅9=945.
Precizare: Această problemă a fost rezolvată şi în varianta cu ciclu cu test iniŃial,
în cadrul aplicaŃiei R.IV.14. din lecŃia “IV.4.1. Structura repetitivă cu test iniŃial”.

240
Rezolvare
:
 Algoritmul a fost explicat în aplicaŃia R.II.23. din lecŃia "II.4.2. Structura
repetitivă cu test final" (capitolul II).

#include <iostream.h>
citeşte n;
void main () P ← 1;
{
int i,n,P; i ← 1;
cout << "\n n="; execută
cin >> n; început
P=1; P ← P*i;
i=1; i ← i+2;
do sfârşit
{ cât timp (i<=n)
P*=i; scrie P;
i+=2;
}
while (i<=n);
cout << "\n P=" << P;
}

ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în tema T.10. din lecŃia "2.4.1.
Structura repetitivă cu test iniŃial" (capitolul II).

AplicaŃie R.IV.27. Şir de numere a cărui citire se termină cu 0


Se dă un şir de numere citite pe rând de la tastatură, până la întâlnirea
valorii 0 (care nu face parte din şir). Presupunând că şirul conŃine cel puŃin un
număr nenul, să se afişeze câte numere pozitive sunt în şir.
Precizare: Această problemă a fost rezolvată şi în varianta cu ciclu cu test
iniŃial, în cadrul aplicaŃiei R.IV.15. din lecŃia “IV.4.1. Structura repetitivă cu test
iniŃial”, cu deosebirea că acolo numerele se citeau pe rând cât timp nu s-a introdus
valoarea 0.
Rezolvare
:
 Algoritmul a fost explicat în aplicaŃia R.II.10. din lecŃia "II.4.2. Structura
repetitivă cu test final" (capitolul II).

citeşte x;
nr ← 0;
execută
început
dacă (x>0) atunci

241
nr ← nr+1;
citeşte x;
sfârşit
cât timp (x≠0);
scrie nr;

 Programul:

#include <iostream.h>
void main ()
{
int x,nr;
cout << "\n x="; cin >>x;
nr=0;
do
{
if (x>0)
nr++;
cout << "\n x="; cin >>x;
} while (x);
cout << "\n nr=" << nr;
}

ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în temele T.11. şi T.12. din lecŃia
"II.4.1. Structura repetitivă cu test iniŃial" (capitolul II).

AplicaŃie R.IV.28. Suma cifrelor unui numãr natural


ScrieŃi un algoritm care determină suma cifrelor unui număr natural x citit
de la tastatură.
Precizare: Această problemă a fost rezolvată şi în varianta cu ciclu cu test
iniŃial, în cadrul aplicaŃiei R.IV.17. din lecŃia “IV.4.1. Structura repetitivă cu test iniŃial”.
Rezolvare
:
 Algoritmul a fost explicat în aplicaŃia R.II.11. din lecŃia "II.4.2. Structura
repetitivă cu test final" (capitolul II).

citeşte x;
d ← x;
S ← 0;
execută
început
S ← S+ d % 10;
d ← d/10;
sfârşit
cât timp d≠0;
scrie S;
242
 Programul:
#include <iostream.h>
void main()
{
int S;
long d,x;
// citeste de la tastatura numarul x
cout << "\n x=";
cin >> x;
// initial deimpartitul d este chiar numarul x, iar suma cifrelor S este 0
d=x;
S=0;
// extrage cifrele lui x intr-un ciclu, adaugand la S fiecare cifra
do
{
S+=d % 10; // adauga cifra extrasa d % 10 la suma cifrelo S
d=d/10; // catul impartirii curente, d / 10, va fi deimpartit pentru impartirea urmatoare
} while (d); // cat timp deimpartitul este diferit de 0
cout << "\n S=" << S;
}

ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în tema T.13. din lecŃia "II.4.1. Structura
repetitivă cu test iniŃial" (capitolul II).

AplicaŃie R.IV.29. Palindroame mai mici sau egale cu n


Numim "oglinditul unui număr natural x", numărul obŃinut prin citirea
cifrelor lui x în ordine inversă, de la dreapta la stânga. Exemplu: oglinditul lui
2435 este 5342. Numim palindrom un număr natural egal cu oglinditul său (citit
invers este acelaşi număr). Exemplu: numărul 232 este palindrom.
Se citeşte de la tastatură un număr natural n (n<=20000). Să se afişeze
toate palindroamele mai mici sau egale decât n. Exemplu: pentru n=135, se vor
afişa numerele:
1,2,3,4,5,6,7,8,9,11,22,33,44,55,66,77,88,99,101,111,121,131
Precizare: Această problemă a fost rezolvată şi în varianta cu ciclu cu test iniŃial,
în cadrul aplicaŃiei R.IV.16. din lecŃia “IV.4.1. Structura repetitivă cu test iniŃial”.
Rezolvare
:
Algoritmul problemei a fost explicat pe larg în pseudocod în cadrul problemei
rezolvate R.II.25. din capitolul “II.4.2. Structura repetitivă cu test final ”

243
 Pseudocodul:
execută
citeşte n;
cât timp (n<0 SAU n>20000);
i←1;
execută
început
d← i;
y← 0;
execută
început
c← d % 10;
y← y*10+c;
d← d / 10;
sfârşit
cât timp (d≠0);
dacă (y==i) atunci
scrie i;
i←i+1;
sfârşit
cât timp (i<=n);

 Programul:

#include <iostream.h>
void main ()
{
int i,c,n,d,y;
do
{
cout << "\n n=";
cin >> n;
} while (n<0 || n>20000);
i=1;
do
{
d=i;
y=0;
do
{
c=d % 10;
y=y*10+c;
d/=10;
} while (d!=0);
if (y==i)
cout << i << ' ';
i++;
} while (i<=n);
}

244
ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în tema T.14. din lecŃia "II.4.1.
Structura repetitivă cu test iniŃial" (capitolul II).

AplicaŃie R.IV.30. Multiplii comuni


(Bacalaureat iulie 2008, varianta 34)
Se citesc de la tastatură trei numere naturale nenule x, y şi p, având cel
mult trei cifre fiecare. ScrieŃi un algoritm care afişează pe ecran primii p multiplii
comuni ai celor două numere x şi y.
Exemplu: pentru x=180, y=120 şi p=5, se vor afişa numerele: 360, 720,
1080, 1440, 1800.
Rezolvare
:
 Pseudocodul acestui algoritm a fost explicat pe larg în cadrul aplicaŃiei
R.II.27. din cadrul lecŃiei "II.4.2. Structura repetitivă cu test final" (capitolul II).

Pseudocodul:

citeşte x,y,p;
dacă (x>=y) atunci
început
a ← x; b ← y;
sfârşit
altfel
început
a ← y; b ← x;
sfârşit
execută
r ← a%b;
a ← b;
b ← r;
cât timp (r#0);
d ← a;
m ← (x*y)/d;
i ← 1;
execută
scrie i*m,' ';
i ← i+1;
cât timp (i<=p);

Programul:

#include <iostream.h>
#include <conio.h>
245
void main ()
{
unsigned int x,y,p,a,b,d,r,m,i;
clrscr();
cout << "Dati numerele x, y si p: " << endl;
cin >> x >> y >> p;
// aflam d = c.m.m.d.c. al lui x si y, cu algoritmul lui Euclid
if (x>=y)
{
a=x; b=y;
}
else
{
a=y; b=x;
}
do
{
r=a%b;
a=b;
b=r;
} while (r);
d=a;
// aflam m = c.m.m.m.c. al lui x si y
m=(x*y)/d;
// aflam primii p multiplii comuni ai lui x si y, care vor fi m, 2m, 3m,..., pm
cout << endl << "Primii " << p << " multiplii sunt:" << endl;
i=1;
do
{
cout << i*m << " ";
i++;
} while (i<=p);
getch();
}

ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în tema T.27. din lecŃia "II.4.2.
Structura repetitivă cu test final" (capitolul II).

AŃi înŃeles ? Probleme cu răspuns scurt


Următoarele două probleme se referă la secvenŃa de program de mai jos în care
toate variabilele memorează numere naturale nenule.
cin >> n;
x=1;
y=x-1;
do
{
y=x*(x-1)+y;
x++;
} while (x<=n);

246
►1 . (Bacalaureat iulie 2008, varianta 3)
De câte ori este evaluată expresia logică din linia "until" în timpul execuŃiei
secvenŃei ?
a) de n2 ori b) de n+1 ori c) o dată d) de n ori
►2. Dacă de la tastatură se citeşte n=5, care vor fi valorile finale ale variabilelor
x şi y, după execuŃia secvenŃei ?

►3. (Bacalaureat iulie 2008, varianta 4)


Care vor fi valorile finale ale variabilelor a şi b afişate la finele execuŃiei
secvenŃei de program urmtoare ?
a=1; b=0;
do
{
b++;
a*=b;
} while (a<125);

Următoarele două probleme se referă la secvenŃa de program de mai jos în care


toate variabilele memorează numere naturale nenule.
cin >> a;
b=0;
do
{
a--;
b+=a*a;
} while (a!=0 && b<=99);
cout >> a >> b;

►4. (Bacalaureat iulie 2008, varianta 15)


Dacă de la tastatură se citeşte numărul a=5, ce valori se vor afişa în urma
execuŃiei secvenŃei ?
►5. GăsiŃi un număr cu exact două cifre care ar putea constitui valoarea citită în
variabila a, astfel încât valoarea finală a lui b să reprezinte suma pătratelor primelor a
numere naturale (12+22+...+a2).

►6. (Bacalaureat iulie 2006, varianta 2)


Ce reprezintă rezultatul afişat în urma execuŃiei secvenŃei de program de mai jos?
cin << a;
do
{
c=floor(a);
a=(a-c)*10;
} while (floor(a)>0);
cout >> a;

a) prima zecimală nenulă a lui a


b) prima zecimală a lui a
c) ultima zecimală nenulă a lui a
d) ultima zecimală a lui a

247
Următoarele patru probleme se referă la secvenŃa de program de mai jos în care
toate variabilele memorează numere naturale nenule.
cin >> n;
m=0;
v=n;
u=n%10
do
{
c=n%10;
v=v*10+c;
if (c==u)
m++;
n=n/10;
} while(n);
cout >> v >> m;

►7. (Bacalaureat iulie 2009, varianta 65)


DeduceŃi ce valori se vor afişa pe ecran, în cazul în care de la tastatură se citeşte
numărul n=1327.
►8 . (Bacalaureat iulie 2009, varianta 65)
GăsiŃi o valoare care ar putea fi citită în variabila n, astfel încât valoarea afişată
pentru variabila m să fie 3.
►9. Ştiind că valorile variabilelor folosite în cadrul secvenŃei pot fi orice numere
naturale cu maxim trei cifre, este corectă instrucŃiunea de mai jos prin care se declară
respectivele variabile ? JustificaŃi răspunsul.
int m,n,u,v,c;

►10. Dacă de la tastatură se citeşte valoarea n=688, câte atribuiri se execută în


total în timpul rulării secvenŃei ?
►11. DaŃi un exemplu de număr care ar putea fi citit în variabila n, astfel încât
valoarea finală a variabilei m să fie 0.
►12. (Bacalaureat iulie 2001, varianta 5)
Care trebuie să fie valoarea iniŃială a do
variabilei întregi i pentru ca secvenŃa alăturată să {
cout << "XX";
afişeze şirul XXX ? i--;
a) 0 b) 1 c) 2 d) 3 e) 4 } while (i!=3);
f) 5 g) 6 h) nu există nici o valoare

►13. (Bacalaureat iulie 2000, variantele 4 şi 9)


Care este valoarea variabilei întregi a pentru int x=5;
care secvenŃa de program alăturată va afişa exact un do
{
caracter 'A' ?
cout << 'A';
a) 12 b) 5 c) 4 d) 1 x++;
} while (x>a);

►14. ScrieŃi o secvenŃă de program care repetă citirea a unei variabile întregi a
până când introducem de la tastatură o valoare pară şi divizibilă cu 5.

248
a) do b) do
cin >> a; cin >> a;
while (a % 2==0 || a % 5==0); while (a % 2!=0 && a % 5!=0);
c) do d) do
cin >> a; cin >> a;
while (a % 2!=0 || a % 5!=0); while (a % 10==0);

►15. De câte ori afişează valoarea 0 programul următor ?


int i=2; a) nici o dată
do b) o dată
{ c) de două ori
i+=2;
cout << "\n 0";
d) de trei ori
} while (i<=5);
i--;

►16. Ce valoare va afişa programul următor ?


int x=5; a) nimic
do b) 1
{ c) 11
if (x % 3==0)
d) programul va intra într-un
x+=2;
else x--; ciclu infinit
cout << '1';
} while (x<10);

►17. Programul de mai jos va tipări numărul ....


int n=10; a) 10
while (n>0) b) 2
do { c) -2
n--; d) -3
} while (n!=-2);
cout << n;
e) programul conŃine un ciclu infinit

►18. Care dintre secvenŃele de mai jos afişează corect numerele divizibile cu 7
situate în intervalul închis [a,b] ?
a) b) c)
i=a; i=b; i=a;
do while (i % 7!=0) while (i<b)
{ i--; if (i % 7==0)
i++; do cout << i << ' ';
} while (i % 7!=0); { i++;
while (i<=b) cout << i << ' ';
{ i=i / 7;
cout << i << ' '; } while (i>=a);
i+=7;
}
d) Nici una dintre variantele anterioare.

►19. Pentru programul următor, alegeŃi răspunsul corect:


#include <iostream.h>
void main ()
249
{
int a,b,k;
cin >> a;
k=1;
do
{
k++;
b=a;
while (a%k==0)
a/=k;
if (a!=b)
cout << k << ' ';
} while (a!=1);
}

a) Programul funcŃionează corect şi afişează o valoare / nişte valori pentru orice a>=1;
b) Programul nu face nimic concret, deoarece condiŃia "a<>b" din linia if nu poate fi
îndeplinită niciodată;
c) Programul afişează toŃi divizorii proprii ai numărului a;
d) Programul afişează divizorii primi ai numărului a;
e) Nici una dintre afirmaŃiile anterioare nu este adevărată.
►20. Considerând că toate variabilele sunt întregi, ce valoare se afişează după
execuŃia secvenŃei de mai jos ?
int s=0,t=0,x=3;
int i=1,y=1,z=1;
do
{
if (x>0)
if (y>1)
if (z>2) t=x;
else t=x+y;
else t=x+y+z;
s+=i+t;
i++;
} while (i>7);
cout << s;
a) 1 b) 5 c) 6 d) 51

250
Aprofundare

Probleme rezolvate

R.IV.31 Eli mi na r e a u n ei cif r e d i nt r - u n nu m ă r


(Bacalaureat iulie 2008, varianta 22)
Să se realizeze un program care citeşte de la tastatură un număr natural n
(cu cel puŃin două cifre şi cel mult nouă cifre, toate nenule), şi determină toate
numerele obŃinute din n prin eliminarea câte unei singure cifre: mai întâi cifra
unităŃilor, apoi cifra zecilor, apoi cea a sutelor, etc. Numerele astfel obŃinute vor fi
scrise pe ecran pe o singură linie, separate prin câte un spaŃiu între ele.
Exemplu: dacă de la tastatură se citeşte n=12345, pe ecran se vor afişa numerele:
1234 1235 1245 1345 2345

Rezolvare
:
 Pseudocodul acestui algoritm a fost explicat pe larg în cadrul aplicaŃiei
R.II.28. din cadrul lecŃiei "II.4.2. Structura repetitivă cu test final" (capitolul II).

 Pseudocodul:
citeşte n;
p←1;
execută
n2←n%p;
n1←[n/(10*p)];
scrie n1*p+n2;
p←p*10;
cât timp (n1#0);

 Programul:

// bac 2008, III.1 / var 22


#include <iostream.h>
#include <conio.h>

void main ()
{
long n,n1,n2,p;
clrscr();
cout << "Dati numarul n: ";
cin >> n;
251
p=1;
cout << "Numerele obtinute sunt: " << endl;
do
{
// la fiecare pas eliminam o cifra
n2=n%p; // formam numarul n2 cu cifrele de dinaintea celei eliminate
n1=n/(10*p); // formam numarul n2 cu cifrele de dupa cea eliminata
cout << n1*p+n2 << " "; // afisam numarul rezultat prin lipirea lui n1 si n2
p=p*10;
} while (n1); // cat timp n1#0
getch();
}

R.IV.32 Co nc urs cu pr emii


La un concurs de orientare turistică s-au înscris mai mulŃi concurenŃi.
Probele întrecerii se desfăşoară pe parcursul a trei zile, la finele acesteia fiecare
concurent acumulând un anumit punctaj. Organizatorii concursului doresc să
acorde nişte premii, dar valoarea totală a premiilor nu poate depăşi suma de S lei
pe care o au la dispoziŃie. Din acest motiv nu pot fi premiaŃi toŃi concurenŃii, ci
doar un număr de p sportivi, în speŃă cei clasaŃi pe primele p locuri. Algoritmul de
împărŃire a banilor este următorul: ultimul dintre cei premiaŃi primeşte X mii lei,
apoi, fiecăruia dintre ceilalŃi concurenŃi premiaŃi i se acordă suma primită de către
sportivul de pe locul imediat următor plus 15% din suma respectivă. Ocupantul
locului I mai primeşte în plus încă L lei faŃă de suma ce-i revine conform
calculului anterior. De la tastatură se citesc valorile X, L şi S. ScrieŃi un algoritm
care determină şi afişează suma de bani primită de către fiecare concurent premiat,
precum şi numărul p al concurenŃilor care au obŃinut un premiu.
Rezolvare

:
Pseudocodul acestui algoritm a fost explicat pe larg în cadrul aplicaŃiei
R.II.29. din cadrul lecŃiei "II.4.1 Structura repetitivă cu test final" (capitolul II).

 Pseudocodul:
citeşte X,L,S;
val←x;
scrie val;
vt← val;
p←1;
execută
val← val+[(15/100)*val];
scrie val;
p←p+1;
vt←vt-val;
cât timp vt+val+L<=S;
scrie val+L,vt,p;

252
 Programul:

#include <iostream.h>
#include <math.h>
void main ()
{
long X,L,S,p,val,vt;
// citeste datele de intrare
cout << "\n Suma ultimului premiat ";
cin >> X;
cout << "\n Premiul suplimentar al castigatorului ";
cin >> L;
cout << "\n Suma totala disponibila pentru premii ";
cin >> S;
val=X; // in val vom memora succesiv valorile premiilor acordate concurentilor
premiati
cout << "\n Premiile acordate concurentilor sunt, in ordine: \n";
cout << val;
vt=val; // vt =valoarea totala a premiilor
p=1; // numarul concurentilor premiati
do
{
// determina si afiseaza valoarea premiului urmatorului concurent premiat
val=val+floor((15/100.)*val);
cout << "\n" << val;
// actualizeaza valoarea totala a premiilor si numarul concurentilor premiati
p++;
vt=vt+val;
} while (vt+L+val<=S);
cout << "\n Castigatorul: " << val+L;
cout << "\n Valoarea totala a premiilor este " << vt;
cout << "\n Numarul concurentilor premiati este " << p;
}

Probleme propuse

Folosind cicluri cu test final, scrieŃi programe pentru toŃi algoritmii


propuşi în tema T.R.3. de la sfârşitul capitolului II (secŃiunea ”Probleme
recapitulative pentru toate tipurile de cicluri”).

I V .2 .3 . Ci c l u c u n u m ã r f i x de p a ş i ( f o r )

Într-un astfel de ciclu, o secvenŃă de instrucŃiuni se execută de un anumit


număr de ori bine determinat, stabilit cu ajutorul valorilor pe care le parcurge un
aşa-numit contor.
253
În lecŃia "Structura repetitivă cu număr fix de paşi" din capitolul
"Principiile programării structurate", am prezentat pentru acest ciclu o sintaxă
foarte simplistă, neconformă cu cea impusă de limbajul C++.
pentru (<contor> ← <v1>,<v2>,...,<vn>) execută
<secv>

Am prezentat atunci funcŃionarea de principiu: contorul ciclului


<contor> parcurge pe rând valorile <v1>,<v2>,...,<vn>, şi pentru fiecare
dintre aceste valori se execută secvenŃa de instrucŃiuni <secv> ce reprezintă
corpul ciclului (adică se execută un pas al ciclului).
În C++, linia “pentru” este alcătuită din trei expresii. Sintaxa unui ciclu
cu contor arată astfel:
for (<expr_1>; <expr_2>; <expr_3>)
<secv>
 <contor> este o variabilă numită contorul ciclului;
 <secv> este o secvenŃă formată dintr-una sau mai multe instrucŃiuni,
numită corpul ciclului;
 <expr_1> este aşa-numita “expresie de iniŃializare a ciclului”, din
care trebuie să rezulte valoarea iniŃială a contorului (valoarea cu care
va intra în ciclu şi va executa primul pas);
 <expr_2> reprezintă condiŃia de continuare a ciclului, mai exact
condiŃia pe care trebuie să o îndeplinească contorul pentru ca execuŃia
ciclului să continue cu un nou pas; prin această expresie ne putem
asigura că ciclul este unul finit: el se va încheia în momentul în care
condiŃia dată de <expr_2> nu mai este adevărată;
 <expr_3> asigură trecerea la pasul următor al ciclului; mai exact,
printr-o incrementare sau atribuire, această expresie stabileşte
valoarea pe care o va avea contorul la pasul următor al ciclului.

Exemplu:
Să vedem cum să transcriem în C++ un ciclu cu contor care în pseudocod este
descris astfel.
pentru (i←1,2,...,n) for (<expr_1>; <expr_2>; <expr_3>)
<secv> <secv>
Contorul i al ciclului parcurge pe rând valorile 1,2,...,n-1,n, şi, la fiecare pas, pentru
fiecare valoare a lui i, se execută corpul ciclului reprezentat de secvenŃa de instrucŃiuni
<secv> (atenŃie, valoarea variabilei n trebuie să fie cunoscută înainte de “intrarea” în
ciclu). Tot ce trebuie să facem este să stabilim care sunt expresiile <expr_1>, <expr_2>
şi <expr_3> care apar în transcrierea C++ a liniei “pentru”.

254
• Expresia <expr_1> trebuie să stabilească prima valoare a contorului i, cu care
se va executa primul pas al ciclului. Se vede clar că această valoare este 1, deci <expr_1>
este simpla atribuire i=1.
• Expresia <expr_2> trebuie să ne dea condiŃia de continuare a ciclului. Contorul
i pleacă de la valoarea 1, creşte la fiecare pas cu câte o unitate, până în momentul în care
a ajuns la valoarea n inclusiv. Altfel spus, ciclul se opreşte atunci când valoarea lui i a
depăşit n. În concluzie, ciclul se reia atâta timp cât valoarea lui i este mai mică sau egală
decât n, deci condiŃia de continuare a ciclului este “i<=n”.
• Expresia <expr_3> are rolul de modifica contorul în aşa fel încât să se asigure
trecerea la pasul următor al ciclului; ObservaŃi că la fiecare nou pas, valoarea lui i creşte
cu o unitate faŃă de pasul precedent, deci trecerea la un nou pas se face prin incrementarea
contorului i cu 1. Prin urmare, această expresie este “i++”.
Acum putem traduce in C++ ciclul nostru:
for (i=1; i<=n; i++)
<secv>
Evident că în loc de “i<=n”, puteam scrie o condiŃie echivalentă, cum ar fi
“i<n+1” !
ObservaŃii:
♦ În cazul în care corpul ciclului are cel puŃin două instrucŃiuni, acesta
trebuie cuprins între acolade.
♦ Expresiile <expr_1>, <expr_2> şi <expr_3> pot fi oricât de complexe;
ele pot conŃine şi alte operaŃii în afara celor care stabilesc rolul lor; astfel de
situaŃii mai speciale, care constituie “farmecul” C-ului, vor face obiectul secŃiunii
“Extindere” de la sfârşitul lecŃiei.
♦ Nu se va altera contorul unui ciclu for, în corpul acestuia (prin
atribuire sau citire de la tastatură).
Exemplu:
Reluăm aceeaşi problemă rezolvată până acum cu celelalte două tipuri de
cicluri:
Să se calculeze suma a n numere naturale citite pe rând de la tastatură
(unde n este cunoscut).
Notând contorul ciclului cu i, acesta va lua ca valori toate numerele naturale de la
1 la n (i=1,2,...,n). “Traducerea”în C++ a liniei de pseudocod “pentru
(i←1,2,...,n)” a fost explicată deja: “for (i=1; i<=n; i++)”. Pentru fiecare dintre
aceste valori ale lui i se execută corpul ciclului, care constă în citirea unui număr x şi
adăugarea lui la suma S (unde S s-a iniŃializat cu 0 înainte de ciclu). Observăm că
variabila-contor i nu are decât rolul de a număra execuŃiile corpului ciclului.
#include <iostream.h>
void main ()
{
int i,n,x,S;
cout << "\n n=";
255
cin >> n; citeşte n;
S=0; S ← 0;
for (i=1; i<=n; i++) pentru (i←1,2,...,n) execută
{ început
cout << "\n x= "; citeşte x;
cin >> x;
S ← S+x;
S+=x;
sfârşit
}
scrie S;
cout << "\n S= " << S;
}
Exemplu de funcŃionare:
Să urmărim funcŃionarea ciclului pas cu pas, dacă n=3 iar numerele citite succesiv
în variabila x sunt 2, 5, 8.
Înaintea ciclului avem S=0.
La “intrarea” în ciclu se execută mai întâi expresia care iniŃializează contorul:
i=1. Astfel începe primul pas al ciclului. Mai departe se testează condiŃia de continuare
“i<=n”: “1<=3 ? da” ⇒ continuă primul pas, cu corpul ciclului: citeşte x=2 şi
S=S+x=0+2=2. Urmează modificarea contorului pentru trecerea la pasul următor, prin
incrementarea i++ ⇒ i=1+1=2. Paşii următori se derulează într-o manieră absolut
similară:
Pasul 2: i<=n ? 2<=3 ? da ⇒ citeşte x=5 şi S= S+x=2+5=7; i++ ⇒ i=2+1=3
Pasul 3: i<=n ? 3<=3 ? da ⇒ citeşte x=8 şi S= S+x=7+8=15; i++ ⇒ i=3+1=4
Pasul 4: i<=n ? 4<=3 ? nu ⇒ se încheie ciclul.
ObservaŃie:
Dintre artificiile pe care le permite limbajul C++, unul este foarte des folosit de
către programatori. Este vorba despre faptul că în expresia <expr_1> de iniŃializare a
contorului pot fi incluse şi alte iniŃializări. În cazul nostru, atribuirii i=1 care iniŃializează
contorul, îi putem ataşa şi iniŃializarea lui S cu 0 (făcută înaintea ciclului). Astfel, în loc de
S=0;
for (i=1; i<=n; i++)
{
cout << "\n x= ";
cin >> x;
S+=x;
}
putem scrie:
for (S=0, i=1; i<=n; i++)
{
cout << "\n x= ";
cin >> x;
S+=x;
}

ObservaŃi că expresia <expr_1> de iniŃializare a contorului a devenit “S=0,


i=1”. VeŃi putea înŃelege cu uşurinŃă această expresie dacă aŃi parcurs lecŃia “Operatorul
<<virgulă>>” din secŃiunea “Extindere” a capitolului II, “Elemente de bază ale limbajului
C++”. Pe scurt, două expresii elementare, “S=0” respectiv “i=1”, au fost “legate” între ele
prin operatorul “virgulă”. Asta înseamnă că ele se vor executa succesiv, în ordinea în care
256
au fost scrise, adică mai întâi S=0 apoi i=1. Deosebirea faŃă de varianta precedentă constă
în faptul că, în loc să se execute înaintea ciclului, atribuirea S=0 are loc la începutul
primului pas, dar acest fapt nu influenŃează evoluŃia ulterioară a lucrurilor.

Alte exemple de cicluri for:

1) char c;
for (c='A'; c<='D'; c++)
cout << c;

• Contorul ciclului este variabila c de tipul caracter. Prima valoare a sa este


caracterul ‘A’, ciclul se execută atâta timp cât caracterul memorat în variabila c este mai
mic sau egal decât ‘D’, şi la fiecare pas se incrementează contorul c. În condiŃiile în care
iniŃial c=’A’, după prima incrementare valoarea contorului c va fi caracterul ’B’. De ce?
Reamintim că în setul ASCII, fiecare caracter are un cod numeric, numit codul ASCII al
caracterului, iar limbajul C++ face o asociere între caracter şi codul său. Astfel, atunci
când trebuie să incrementeze caracterul, el va incrementa de fapt codul său ASCII. În cazul
nostru, codul lui ‘A’ pe care îl incrementează este 65, în urma incrementării ajunge la
valoarea 66 care este codul lui ‘B’, deci, în virtutea asocierii inverse cod→caracter, noua
valoare a variabilei c va fi caracterul ‘B’. În acest mod, contorul c va parcurge succesiv
caracterele ‘A’, ‘B’, ‘C’, ‘D’. Odată ajuns la ‘D’, ciclul se opreşte datorită condiŃiei de
continuare c<=’D’.
2) S=0;
int n=9, S=0, i;
for (i=n; i>=1; i-=2)
S+=i;

• Prima valoare a lui i este n adică 9, la fiecare pas contorul i scade cu două
unităŃi prin atribuirea i=i-2, iar ciclul se execută atâta timp cât i>=1. Prin urmare,
valorile lui i vor fi succesiv 9, 7, 5, 3, 1. La fiecare pas, se adaugă valoarea curentă a lui i
la o variabilă S (iniŃializată cu 0). V-aŃi dat seama desigur că, în final, în variabila S se va
calcula suma S=9+7+5+3+1=25. Am ales acest exemplu pentru a ilustra faptul că într-un
ciclu “for”, contorul se poate modifica de la un pas la altul, după orice regulă, nu neapărat
prin incrementare cu o unitate.
3) int i, n=4;
for (i=sqrt(3); i<=n; i++)
cout<< "\n " << i;

• Conform primei expresii din linia “for”, prima valoare a contorului i ar trebui
să fie “radical din 3”, adică 1.732... Această valoare va fi însă trunchiată la 1, urmare a
faptului că variabila i căreia i se atribuie este de tipul int (regula conversiilor implicite).
La fiecare pas se incrementează i cu 1, iar condiŃia de continuare este i<=n. Rezultă că
valorile lui i vor fi succesiv 1, 2, 3, 4 care se afişează în ciclu.
Oricât ar părea de ciudat, acest ciclu funcŃionează şi în cazul în care contorul i se
declară de tipul float. În această situaŃie, prima valoare a lui i nu mai este trunchiată,
afişându-se pe rând 1.732051, 2.732051, 3.732051, 4.732051 (instrucŃiunea cout
tipăreşte implicit primele şase zecimale).

257
AplicaŃie R.IV.33. SecvenŃe
Care dintre secvenŃele de program de mai jos nu afişează 123 ?
a) n=3; b) n=7;
for (i=1; i>=n; i++) for (i=1; i<=n/2; i++)
cout << i; cout << i;
c) for (a='1'; a<=’3’; a++) d) F=1; E=0;
cout << a; for (i=3; i>=1; i--)
{
E=E+i*F; F=F*10;
}
cout << E;
Rezolvare
:
 Varianta a) este eronată: ciclul “for” nu are nici un pas, deoarece condiŃia de
continuare “i>=n” este falsă încă de la început, pentru prima valoare a contorului i=1.
Toate celelate variante afişează 123 sub o formă sau alta (atenŃie, nu se cere să se
formeze neapărat numărul întreg 123 şi să se memoreze într-o variabilă !).
CondiŃia de continuare a ciclului din varianta b) este “i<=3” (rezultatul împărŃirii
7/2 va fi 3, deoarece atunci când împarte doi întregi compilatorul va furniza câtul întreg al
împărŃirii).Prin urmare, valorile contorului i vor fi pe rând 1, 2, 3, şi aceste valori se
tipăresc “lipite” una de alta, simulându-se astfel numărul 123.
Contorul a al ciclului din varianta c) parcurge pe rând caracterele '1', '2', '3'
şi la fiecare pas se afişează valoarea contorului. Efectul final va fi tipărirea caracterelor
'1', '2' şi '3', "lipite" unul de altul.
În varianta d) se formează numărul întreg 123 în variabila E, care apoi se
afişează. Să parcurgem paşii ciclului din această secvenŃă, în care i=3,2,1 şi iniŃial F=1,
E=0:
 i=3: E=E+i*F=0+3*1=3, F=F*10=1*10=10
 i=2: E=E+i*F=3+2*10=23, F=F*10=10*10=100
 i=1: E=E+i*F=23+1*100=123, F=F*10=100*10=1000
Răspuns corect: a).

AplicaŃie R.IV.34. Valori ale unor variabile


(Bacalaureat iulie 2001, varianta 3)
StabiliŃi care dintre variabilele întregi pozitive x şi y trebuie să aibă valoarea
iniŃială 1, pentru ca, la sfârşitul executării următoarei secvenŃe de instrucŃiuni, variabila z
să aibă valoarea 3 ?
z=0; a) numai x
for (i=x; i<=y; i++) b) numai y
z+=i; c) atât x, cât şi y
if (z==1) d) nici x, nici y
z=3
else
z=5;

258
Rezolvare
:
 În ciclul for, contorul i parcurge valorile întregi de la x la y, şi la fiecare pas
se adaugă i la z (unde z a fost iniŃializat cu 0). Pentru ca în final variabila z să aibă
valoarea 3, este necesar să se execute "ramura" if a instrucŃiunii de selecŃie if-else.
Prin urmare, după ciclu variabila z trebuie să aibă valoarea 1, aşa încât să fie adevărată
condiŃia din linia if şi să se execute atribuirea z=3. Întrucât la începutul secvenŃei
variabila z are valoarea 0, rezultă că în ciclu z trebuie să se mărească doar cu o unitate
pentru a ajunge la valoarea 1 la finele ciclului. Ce înseamnă aceasta ? Că atribuirea z=z+i
din corpul ciclului se execută o singură dată, pentru i=1 (în urma căreia vom avea
z=0+1=1). În traducere, ciclul va avea un singur pas, iar linia for se va traduce astfel:
"pentru i de la 1 la 1". Concluzia este clară: valorile lui x şi y trebuie să fie ambele
egale cu 1.
Răspuns corect: c).

AplicaŃie R.IV.35. Numãr prim


ScrieŃi un algoritm care verifică dacă un număr natural x diferit de 0 şi 1,
este prim sau nu, afişând un mesaj corespunzător.
Precizare: Această problemă a fost rezolvată şi în varianta cu ciclu cu test iniŃial,
în cadrul aplicaŃiei R.IV.19. din lecŃia “IV.4.1. Structura repetitivă cu test iniŃial”.
Rezolvare
:
 Algoritmul a fost explicat în aplicaŃia R.II.31. din lecŃia "II.4.1. Structura
repetitivă cu număr fix de paşi" (capitolul II).

citeşte x;
ok ← 1;
pentru (i← 2,...,x / 2) execută
dacă (x%i==0) atunci
ok ← 0;
dacă (ok==1)
scrie 'Numărul este prim'
altfel
scrie 'Numărul NU este prim';

 Programul:

#include <iostream.h>
void main ()
{
int x,i,ok;
cout << "\n x=";
cin >> x;
ok=1;
for (i=2; i<=x/2; i++)
259
if (x % i==0)
ok=0;
if (ok)
cout << "\n Numarul este prim";
else
cout << "\n Numarul NU este prim";
}

ÎncercaŃi singuri !
ScrieŃi un program pentru algoritmii propuşi în tema T.18. din lecŃia
"II.4.1. Structura repetitivă cu test iniŃial" (capitolul II).

AlŃi algoritmi care folosesc structuri repetitive cu contor

AplicaŃie R.IV.36. Numere pare şi divizibile cu 5


(Bacalaureat iulie 2008, varianta 27, enunŃ adaptat)
ScrieŃi un program care, pentru un număr natural n nenul de cel mult patru
cifre citit de la tastatură, afişează, în ordine crescătoare primele n numere naturale
pare şi divizibile cu 5, precum, şi suma acestora.
Exemplu: pentru n=6 se vor afişa numerele 10 20 30 40 50 60
Rezolvare

:
Pseudocodul acestui algoritm a fost explicat pe larg în cadrul aplicaŃiei
R.II.33. din cadrul lecŃiei "II.4.3. Structura repetitivă cu număr fix de paşi " (capitolul II).

Pseudocodul:

citeste n;
S ← 0;
pentru (k ← 1,2,...,n) execută
început
scrie 10*k;
S ← S+10*k;
sfârşit
scrie S;

Programul:

// Bac 2008, III.1 / var 27


#include <iostream.h>
#include <conio.h>

void main ()
{
clrscr();

260
int k,n,S=0; // S = suma numerelor afisate
// citeste n
cout << "Dati valoarea lui n: ";
cin >> n;
cout << "Numerele cerute sunt: " << endl;
// contorizeaza, afiseaza si insumeaza primele n numere pare si divizibile cu 5
// adica divizibile cu 10
for (k=1; k<=n; k++)
{
cout << (10*k) << " ";
S+=10*k;
}
cout << endl << "Suma numerelor este " << S;
getch();
}

ÎncercaŃi singuri !
Folosind structuri repetitive cu contor, scrieŃi programe pentru toate
problemele propuse în cadrul temei T.20., din lecŃia "II.4.1. Structura repetitivă cu
test iniŃial" (capitolul II).

AplicaŃie R.IV.37. Şirul lui Fibonacci


Să se afişeze primii n termeni ai şirului lui Fibonacci. Şirul are primii doi
termeni egali cu 1 şi fiecare din următorii termeni este egal cu suma dintre
termenul precedent şi termenul ante-precedent.
Rezolvare
 :
Algoritmul a fost explicat în aplicaŃia R.II.34. din lecŃia "II.4.3. Structura
repetitivă cu număr fix de paşi" (capitolul II).

citeşte n;
prec ← 1;
anteprec ← 1;
scrie prec,anteprec;
pentru i←3,...,n
început
fib ← prec+anteprec;
scrie fib;
anteprec ← prec;
prec ← fib;
sfârşit

 Programul:

#include <iostream.h>

void main ()
261
{
int i,n;
long fib,prec,anteprec;
// n=numarul de termeni
// fib=termenul, prec=precedentul, anteprec=anteprecedentul
cout << "\n n="; cin >> n;
prec=anteprec=1;
// primii doi termeni
cout << "\n " << anteprec << " " << prec;
for (i=3; i<=n; i++)
{
// restul termenilor
fib=prec+anteprec;
cout << "\n" << fib;
anteprec=prec;
prec=fib;
}
}

ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în tema T.34. din lecŃia "II.4.3.
Structura repetitivă cu număr fix de paşi" (capitolul II).

AplicaŃie R.IV.38. Triunghi de numere


Să se afişeze triunghiul de numere 1
alăturat, pentru o valoare dată a lui n. 1 3
1 3 5
.............
Rezolvare −1
1 3 5 ...... 2n−
:
Algoritmul problemei a fost explicat pe larg în pseudocod în cadrul problemei
rezolvate R.II.35. din secŃiunea “Aprofundare ”, capitolul “II.4.3. Structura repetitivă cu
număr finit de paşi ”

 Pseudocodul:
citeşte n;
pentru (i←1,...,n)
început
pentru (j← 1,...,i)
scrie 2*j-1:2,' ';
<salt la rând nou>;
sfârşit;
sfârşit

 Programul:
#include <iostream.h>
void main ()

262
{
int i,j,n;
cout << "\n n=";
cin >> n; // n este numarul de randuri
for (i=1;i<=n; i++) // parcurge liniile i
{
for (j=1; j<=i; j++) // afiseaza valorile fiecarei linii i
cout << (2*j-1) << ' ';
cout << "\n";
}
}

ÎncercaŃi singuri !
ScrieŃi programe pentru algoritmii propuşi în tema T.35. din lecŃia "II.4.3.
Structura repetitivă cu număr fix de paşi" (capitolul II).

AŃi înŃeles ? Probleme cu răspuns scurt


►1. Fie următoarele declaraŃii de variabile:
int i,a=5, d=10;
b:char;

Să se precizeze care din următoarele instrucŃiuni for sunt corecte:


a) for (i=1; i<=a; i++) cout << 1;
b) for (b='m'; b<=’v’; b--) cout << 1;
c) for (i=a/2; i<=floor(d); i=2) cout << 1;
d) for (d==0; d<=7; d++) cout << 1;

►2. Câte valori distincte va afişa instrucŃiunea:


for (i=1; i<=22; i++) cout << "\n" << floor(sqrt(i));
a) 22 b) 21 c) 5 d) 4

►3. (Bacalaureat iulie 2000, varianta 7)


Care va fi valoarea afişată de către programul următor dacă a=b=3 ?
#include <iostream.h> a) 8
void main() b) 32
{ c) 27
long a,b,c,z,i; d) 13
cout << "Dati a si b: ";
cin >> a >> b;
c=0; z=1;
for(i=1;i<=a;i++)
{
c+=z; z*=b;
}
cout << "c=" << c;
}

263
►4. Câte numere afişează programul următor ?
int i,j,nr=0; a) două
for (i=1; i<=5; i++) b) trei
for (j=5; j>=1; j--) c) patru
{ d) cinci
nr+=1;
if (i==j-i) cout << "\n" << nr;
}

►5. (Bacalaureat august 2000, varianta 1)


Care dintre următoarele secvenŃe de instrucŃiuni atribuie variabilei întregi x
valoarea 10n, cu n număr natural, variabila auxiliară i fiind de tip întreg ?
a) x=1; i=1; b) x=1;
do { for(i=n;i>0;i--)
x*=10; x*=10;
i++;
} while (i<n);
c) x=10; d) x=1; i=0;
for(i=1;i<=n;i++) while (i<=n) {
x*=i; i++;
x*=i;
}

►6. (Bacalaureat august 2000, varianta 3)


Ştiind că x şi i reprezintă două variabile întregi, stabiliŃi care dintre următoarele
secvenŃe de instrucŃiuni afişează numărul 11.
a) x=7; b) x=1;
for (i=1; i<=5; i++) x++; while (x<10) x++;
cout << x; cout << x;
c) x=1; d) x=1; i=2;
for (i=1; i<=2; i++) cout << x; while (i>=0) {
cout << “\n”; cout << x; i--;
}

►7. (Bacalaureat iulie 2001, varianta 4)


Ştiind că x şi y reprezintă două variabile întregi şi că x are valoarea 11, precizaŃi
care dintre următoarele secvenŃe afişează exact zece caractere 'A'.
a) b)
if (x>8) cout << ('A'*10); y=20
while (y>=x) cout << 'A';

c) d)
for (y=2; y<=x; y++) cout << 'A'; for (y=x; y<=21; y++) cout << 'A';

►8. DeduceŃi şirul de numere care se va afişa în urma execuŃiei secvenŃei de


program de mai jos, în care toate variabilele sunt întregi:
for(i=1;i<5;i++)
for(j=1;j<i+1;j++)
cout << j << " ";

264
a) 1 2 2 3 3 3 4 4 4 4
b) 1 1 1 1 2 2 2 2 3 3 3 3 4 4 4 4
c) 1 1 2 1 2 3 1 2 3 4
d) 1 2 3 4 1 2 3 4 1 2 3 4 1 2 3 4

►9. (Bacalaureat august 2000, varianta 2)


Care dintre următoarele secvenŃe de instrucŃiuni atribuie variabilei întregi x
valoarea n2, cu n număr natural, variabila auxiliară i fiind de tip întreg ?
a) x=1; b) x=1;
for (i=1; i<=2; i++) x*=n; for (i=1; i<=n; i++) x*=2;
c) x==n*n; d) x=1; i=0;
while (i<2) x*=n; i++;

►10. Câte valori distincte afişează secvenŃa de program de mai jos ?


int j=1, n, i; a) n div 2
cin >> n; b) n-1
for (i=0; i<=n; i++) c) n
{ d) n+2
cout << i << j;
j++;
}

►11. Fie secvenŃa următoare,în care toate variabilele sunt întregi. ScrieŃi valarea
<v1> şi instrucŃiunea < I2>, astfel încât valoarea afişată la finele execuŃiei secvenŃei să
reprezinte produsul numerelor a şi b.
Cin >> a >> b; a) 0, respectiv E:=E+b;
E=<v1> b) 0, respectiv E:=E+a;
for (k=1; k<=b; k++) c) 1, respectiv E:=E*a;
<I2> d) 1, respectiv E:=E*b;
cout << “\n” << E;

►12. Care dintre secvenŃele de program P=1;


date mai jos, este echivalentă cu secvenŃa alăturată for (i=1; i<=n; i++)
? (două secvenŃe de program se consideră {
S=0;
echivalente dacă produc acelaşi efect în orice for (j=1; j<=i; j++)
situaŃie). Toate variabilele folosite sunt întregi. S=S+j;
P=P*S;
}
a) b) c)
P=1; S=0; P=1; S=0; P=1; S=0;
for (i=1;i<=n;i++) for (i=1;i<=n;i++) For (i=1;i<=n;i++)
{ { {
P=P*i; S=S+P; S=S+i; P=P*S; P=P*S; S=S+i;
} } }
d) nici una

►13. Fie secvenŃa de program următoare:


S=0;
for (i=3; i<=n; i+=3)
S+=i;
265
Se dau mai jos cinci triplete de numere, fiecare astfel de triplet reprezentând un
set de valori pentru variabila de intrare n. Care din aceste triplete au proprietatea că pentru
toate cele trei valori ale lui n din triplet se obŃine aceeaşi valoare a lui S ?
a) (3,5,6) b) (6,7,8)
c) (10,11,12) d) (6,9,12)

►14. Fie o variabilă x de tip întreg, diferită de 0 şi 1. În urma execuŃiei


secvenŃelor de program de mai jos, valoarea variabilei ok ar trebui să fie: 1, dacă numărul
x este prim, respectiv, 0, în caz contrar (variabilele ok şi x sunt de tip întreg, iar valoarea
lui x se presupune citită anterior).
Care dintre ele funcŃionează corect în sensul realizării efectului dorit ?

a) b) c)
ok=1; ok=1; ok=0;
for (i=2;i<x;i++) for (i=2;i<x;i++) for (i=2;i<x;i++)
if (x % i==0) if (x % i==0) if (x % i==0)
ok=0; ok=0; ok=1;
printf("%d",ok); else
ok=1;

d) nici una

Aprofundare

Probleme rezolvate

R.IV.39 Co nst r ui re a unui ş ir


(Bacalaureat iulie 2008, varianta 23)
Se consideră şirul crescător format din toate numerele naturale
{1,2,3,....}, luate în această ordine, în care fiecare număr se repetă de exact k
ori. De exemplu, pentru k=4, şirul astfel definit este:
1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,...
ScrieŃi un program care citeşte de la tastatură două numere naturale n şi k
(1 ≤ k ≤ 1 0 0 , 1 ≤ n ≤ 1 0 0 0 0 0 0 0 0 ), apoi, utilizând un algoritm eficient din punctul
de vedere al spaŃiului de memorie şi al timpului de executare, scrie primii n
termeni ai şirului, în ordine descrescătoare, separaŃi prin câte un spaŃiu.
Exemplu: pentru n=17 şi k=3, primii 17 termeni ai şirului format cu
numerele din mulŃimea {1,2,3,...}, luate succesiv, în care fiecare număr se
repetă de 4 ori este: (1,1,1,2,2,2,3,3,3,4,4,4,5,5,5,6,6) iar pe ecran
se va afişa: 6 6 5 5 5 4 4 4 3 3 3 2 2 2 1 1 1
266
Rezolvare
:
 Pseudocodul acestui algoritm a fost explicat pe larg în cadrul aplicaŃiei
R.II.36. din cadrul lecŃiei "II.4.3. Structura repetitivă cu număr fix de paşi" (capitolul II).

citeşte n,k;
pentru (i ← 1,2,...n%k) execută
scrie n div k+1, ' ';
pentru (v ← [n/k],...,2,1) execută
pentru i ← 1,2,...,k execută
scrie v, ' ';

 Programul:

// III. 2, var 23, Bac 2008


#include <iostream.h>
#include <conio.h>

void main ()
{
clrscr();
int i,v,n,k;
// citeste n si k
cout << "Dati valorile n si k: ";
cin >> n >> k;
// afiseaza cel mai mare termen, care se repeta de un numar incomplet de ori
for (i=1; i<=n%k; i++)
cout << n/k + 1 << " ";
// afiseaza in ordine descrescatoare ceilalti termeni, care se repeta de exact k ori fiecare
for (v=n/k; v>=1; v--)
for (i=1; i<=k; i++)
cout << v << " ";
getch();
}

R.IV.40 D escompunere
Fiind dat un număr natural n, să se găsească toate posibilităŃile de a
descompune pe n în sumă de numere naturale consecutive.
Exemplu: pentru n=15, descompunerile posibile sunt: 15=1+2+3+4+5,
15=4+5+6 şi 15=7+8.
Rezolvare
:
Algoritmul problemei a fost explicat pe larg în pseudocod în cadrul problemei
rezolvate R.II.37. din secŃiunea “Aprofundare ”, capitolul “II.4.3. Structura repetitivă cu
număr finit de paşi ”

267
 Pseudocodul:
citeşte n;
pentru (i← 1,...,[n/2]) execută
început
S←0;
k←0;
cât timp (S<=n ŞI k<=[n/2]+1) execută
început
S← S+(i+k);
scrie i+k, '+';
sfârşit
dacă (S==n) atunci
scrie "Este"
altfel
scrie "Nu este";
sfârşit

 Programul:
#include <iostream.h>
void main ()
{
int S,i,n,k;
cout << "\n n="; cin >> n;
for (i=1; i<=n/2; i++)
{
S=0;
k=0;
// pentru i-ul curent, calculeaza sumele de forma i+(i+1)+(i+2)+..+(i+k), incercand sa
// gaseasca descompunerea care pleaca de la i
cout << "\n";
while (S+i+k<=n && k<=n/2+1)
{
S=S+(i+k);
cout << (i+k) << '+';
k++;
}
if (S==n) cout << " este";
else cout << " nu este";
}
}

R.IV.41 “T a b la în mu lŃ ir ii”
(Bacalaureat, iulie 2002, varianta 5)
Se citesc de la tastatură trei numere naturale f, a şi b,
fiecare număr având cel mult trei cifre. Să se afişeze o "tablă" cu 2*5=10
3*5=15
toate înmulŃirile de doi factori naturali dintre care unul este 4*5=20
obligatoriu f şi care dau ca rezultate numai numere cuprinse între a 5*5=25
şi b inclusiv. ÎnmulŃirile vor fi afişate câte una pe linie, în ordinea
crescătoare a rezultatelor.

268
Exemplu: pentru f=5, a=8 şi b=25 se va afişa "tabla înmulŃirilor cu 5" ca în
desen.
Rezolvare
:
Algoritmul problemei a fost explicat pe larg în pseudocod în cadrul problemei
rezolvate R.II.38. din secŃiunea “Aprofundare ”, capitolul “II.4.3. Structura repetitivă cu
număr finit de paşi ”

 Pseudocodul:
// citirea datelor cu validare
execută
citeşte f,a,b;
cât timp (f<0 SAU f>=999 SAU a<0 SAU a>999
SAU b<0 SAU b>999);
// parcurgem intr-un ciclu numerele de la a la b si pentru fiecare astfel de numar i,
// daca se imparte exact la f atunci am obtinut o impartire, catul fiind primul factor
pentru (i←a,...,b)
dacă (i % f==0)
început
c← i / f;
scrie c,'*',f,'=',i;
sfârşit

 Programul:
#include <iostream.h>
void main ()
{
int a,b,f,i,c;
// citirea datelor cu validare
do
{
cout << "\n Datele de intrare"; cin >> f >> a >> b;
} while (f<0 || f>999 || a<0 || a>999 || b<0 || b>999);
// parcurgem intr-un ciclu numerele de la a la b si pentru fiecare astfel de numar i, daca
// se imparte exact la f atunci am obtinut o impartire, catul fiind primul factor
for (i=a; i<=b; i++)
if (i%f==0)
{
c=i/f;
cout << c << '*' << f << '=' << i << "\n";
}
}

Probleme propuse

Folosind cicluri cu contor, scrieŃi programe pentru toŃi algoritmii propuşi


în tema T.11. de la sfârşitul capitolului II (secŃiunea ”Probleme recapitulative
pentru toate tipurile de cicluri”).
269
Extindere

Aşa cum v-am obişnuit, în secŃiunea “Extindere” aveŃi ocazia să


descoperiŃi câteva “subtilităŃi” ale C-ului în materie de cicluri cu contori. VeŃi
vedea cum o întreagă secvenŃă de program poate fi redusă la o singură linie !
Exemplu: ScrieŃi o secvenŃă de program care, pentru un număr natural n
citit de la tastatură, calculează şi afişează produsul primelor n numere naturale,
P=1*2*...*n (factorialul numărului natural n, notat în matematică n!)

Algoritmul este foarte simplu. Mai întâi citim de la tastatură valoarea lui n şi
iniŃializăm cu 1 variabila P în care vom calcula produsul cerut.Apoi, într-un ciclu, contorul
i va parcurge pe rând valorile 1,2,...,n ce fac obiectul produsului, şi la fiecare pas
înmulŃim cu P valoarea curentă a lui i (P*=i).
cin >> n;
P=1;
for(i=1; i<=n; i++)
P*=i;
cout << P;

Vom vedea în continuare cum linia “for” va “înghiŃi” toate celelalte linii ale
secvenŃei.
Începem cu o operaŃie pe care am explicat-o deja. IniŃializarea “P=1” poate fi
adusă în prima dintre cele trei expresii din linia “for”. Cum anume ? “Lipind-o” de
iniŃializarea “i=1”. Motivul pentru care este posibil acest “artificiu” a fost explicat în
partea teoretică. Este vorba despre două expresii elementare legate între ele prin operatorul
“virgulă”, care se vor executa succesiv, în ordinea în care sunt scrise, de la stânga la
dreapta. Mutarea iniŃializării “P=1” nu schimbă cu nimic situaŃia: ori că se execută înaintea
ciclului (ca în varianta anterioară), ori că are loc la începutul primului pas imediat înainte
de “i=1”, este acelaşi lucru.
cin >> n;
for(P=1, i=1; i<=n; i++)
P*=i;
cout << P;
Dar o expresie compusă cu operatorul “virgulă”, poate să conŃină şi citiri şi
afişări. Prin urmare, din punct de vedere sintactic, şi instrucŃiunea de citire a lui n, “cin
>> n”, poate fi ataşată expresiei compuse “P=1, i=1”. Acest fapt ar avea vreun efect
asupra execuŃiei programului ? Nu ! Şi despre citirea lui n putem spune acelaşi lucru pe
care l-am spus în legătură cu iniŃializarea “P=1”: este tot una dacă se execută înaintea
ciclului sau la începutul primului pas !
for(P=1, i=1, cin >> n; i<=n; i++)
P*=i;
cout << P;
270
Dacă tot ne-am propus să mutăm totul în linia “for”, oare nu putem “birui” şi
atribuirea “P*=i” ce constituie corpul ciclului ? Ba da ! Numai că această atribuire se va
ataşa la a treia expresie din linia “for”. Pentru a vă da seama cum anume, gândiŃi-vă că la
fiecare pas al ciclului se execută mai întâi atribuirea “P*=i” din corpul ciclului, şi apoi
incrementarea lui i din linia “for” (pentru a se asigura trecerea la pasul următor). În
aceste condiŃii este clar că cele două expresii în discuŃie, “P*=i” şi “i++”, pot fi
“comasate” într-una singură: “P*=i++”. Dacă încercăm să interpretăm expresia “P*=i++”,
ajungem exact la ce am spus înainte: se execută mai întâi atribuirea “P*=i” cu valoarea
curentă a lui i, apoi are loc incrementarea “i++”. În concluzie, a treia expresie din linia
“for” devine “P*=i++”.
for(P=1, i=1, cin >> n; i<=n; P*=i++);
cout << P;

În noua formă, linia “for” trebuie să se încheie cu caracterul “punct şi virgulă”.


ExplicaŃia este foarte simplă: acum corpul ciclului a devenit “vid”, adică nu mai conŃine
nici o instrucŃiune. În absenŃa caracterului “;”, în mod implicit C-ul ar considera drept
corp al ciclului următoarea instrucŃiune de după linia “for”, adică afişarea lui P (ceea ce
este eronat, deoarece valoarea lui P se tipăreşte o singură dată după ciclu). Punând
caracterul “;” la sfârşitul liniei “for”, compilatorul va interpreta respectivul caracter ca
fiind instrucŃiunea vidă şi va considera această instrucŃiune vidă drept corpul ciclului,
lăsând afişarea lui P în afara ciclului.
În următorul exemplu vom arăta că, într-un ciclu “for”, una dintre cele
trei expresii ale liniei “for” poate să lipsească, dacă rolul său este suplinit în alt
mod. Vom analiza un program în care lipseşte a doua expresie, cea care ne dă
condiŃia de continuare a ciclului, dar în corpul ciclului este prevăzută o posibilitate
de ieşire “forŃată” din ciclu (la îndeplinirea unei condiŃii).

AplicaŃie
Dacă de la tastatură se introduce numărul 22, câte valori distincte va afişa
programul următor ?
#include<iostream.h>
#include<math.h>
void main ()
{
int x,n,i;
for(cin >> n, i=1 ; ; x=sqrt(i), cout << x, i++)
if (i>n) break;
}

Rezolvare
:
Într-un ciclu for de forma for(<exp_1>;<exp_2>;<exp_3>), una dintre
expresii poate să lipsească, dacă rolul său este suplinit într-un alt mod.
În cazul nostru:
− <exp_1> este "cin >> n, i=1";
− <exp_3> este "x=sqrt(i), cout << x, i++";

271
Lipseşte expresia <exp_2>, care dă condiŃia de continuare a ciclului. Totuşi
ciclul nu se va executa la infinit, pentru că în corpul său întâlnim instrucŃiunea break, care
la un moment dat va asigura ieşirea "forŃată" din ciclu. Mai exact, dacă i este mai mare
decât n, atunci se va ieşi din ciclul for, ceea ce este echivalent cu formularea "ciclul se
execută cât timp i<=n ". Prin urmare, în loc să scriem "if (i>n) break" în corpul
ciclului, putem scrie condiŃia de continuare "i<=n" în linia for. Prin această transformare,
ciclul devine: for(cin >> n, i=1 ; i<=n ; x=sqrt(i), cout << x, i++)
Momentan, corpul ciclului for nu conŃine nici o instrucŃiune, motiv pentru care,
la finele liniei for trebuie să punem ";" (adică, de fapt, corpul este instrucŃiunea vidă).
Dar... urmează alte transformări.
Expresia de iniŃializare a ciclului <exp_1> este "cin >> n, i=1". Avem de-a
face cu o expresie care conŃine două instrucŃiuni separate prin operatorul "virgulă ". Cele
două instrucŃiuni, "cin >> n", respectiv, "i=1", se vor executa succesiv în această ordine.
Dar numai atribuirea "i=1" îşi justifică locul în expresia de iniŃializare a ciclului,
deoarece ne dă valoarea iniŃială a contorului i. InstrucŃiunea "cin >> n", care citeşte
valoarea variabilei n, poate fi scrisă înaintea ciclului.
Analog, expresia <exp_3> este alcătuită din expresiile "x=sqrt(i)", "cout <<
x " şi "i++", separate prin operatorul "virgulă ". Dar numai "i++" trebuie, obligatoriu, să
apară în <exp_3>, deoarece asigură trecerea la pasul următor, prin incrementarea contorului i.
Celelalte două instrucŃiuni pot constitui corpul ciclului (care în forma dată nu există), pentru că
oricum se execută la fiecare pas.
În concluzie, ciclul se mai poate scrie şi astfel:
cin >> n;
for (i=1; i<=n; i++)
{
x=sqrt(i);
cout << x;
}

Atribuirea x=sqrt(i) trebuie privită cu atenŃie: funcŃia sqrt(i) returnează


"radical din i" care este un număr real, dar această valoare returnată se atribuie variabilei x
de tipul int ! În consecinŃă, x va reŃine numai "partea întreagă a lui radical din i " !

Acum, sperăm că e clar ce face programul: dacă de la tastatură se introduce


valoarea 22, atunci aceasta este citită în variabila n, iar programul afişează "partea
întreagă a lui radical din i " pentru i=1,2,...,22.
Ştim că: 1 = 1 , 2 = 1.414..., 3 = 1.732.. , 4 = 2 . Partea
întreagă a lui 1, 2 şi 3 este 1, deci pentru i=1,2,3 secvenŃa dată afişează valori de
1. Analog, celelalte valori distincte care se vor afişa sunt:
− 2, pentru i=4,5,...,8, deoarece parte întreagă din 4, 5,..., 8 este 2;
− 3, pentru i=9,10,...,15, deoarece parte întreagă din
9, 10,..., 15 este 3;
− 4, pentru i=16,17,...22, deoarece parte întreagă din
16, 17,..., 22 este 4.
În concluzie, sunt patru valori distincte afişate, şi anume, 1, 2, 3, 4.
Răspuns corect: e).

272
ÎncercaŃi singuri !
►1. RescrieŃi programul care testează dacă un număr natural x este prim
sau nu, înlocuind structura “if-else” de verificare a divizorilor cu o expresie
condiŃională plasată în linia “for”.
►2. ScrieŃi un program care calculează valoarea expresiei:
E=1*3+2*5+3*7+...+n*(2n+1), condensând tot algoritmul într-o singură linie
“for”.
►3. Ce valoare va afişa programul următor pentru n=12 ?
#include <iostream.h>
void main ()
{
int i,n,S;
cin >> n;
for (S=0,i=2; i<n/2; !(n%i) ? S+=i++ : i++);
cout << S;
}

►4. Pentru programul următor, care dintre afirmaŃiile de mai jos sunt
adevărate ?
#include <iostream.h>
void main ()
{
int S,x;
for(S=0,x=1;0;S+=x, cin >> x)
if (!x) break;
cout << S;
}
a) Dacă de la tastatură se introduc, în ordine, numerele 2, 3, 4 şi 5, atunci
programul va afişa suma numerelor citite, adică 14.
b) Dacă prima valoare introdusă de la tastatură este 0, atunci ciclul se încheie şi
se afişează valoarea 1.
c) Ciclul este eronat: nu se poate face o citire în linia for.
d) InstrucŃiunea if este eronată.
e) Din cauză că lipseşte expresia care dă condiŃia de continuare, ciclul for se va
executa la infinit.

273

S-ar putea să vă placă și