Sunteți pe pagina 1din 325

P

PR
RE
EFFA
A

Programarea calculatoarelor este una dintre disciplinele


din domeniul informaticii care are un loc bine definit n planurile
de nvmnt ale universitilor cu profil tehnic, cu impact real n
formarea viitorilor ingineri. Limbajul de programare C este folosit
pe scar larg att de programatorii de sistem pentru scrierea i
dezvoltarea sistemelor de operare (Windows, Unix, Linux), ct i
de programatorii de aplicaii din diverse domenii. Datorit
caracteristicilor sale (portabilitate, controlul modern al fluxurilor,
setul bogat de operatori, multitudinea funciilor de bibliotec)
limbajul poate fi utilizat pe orice platform i asigur accesul
programatorului la toate resursele calculatorului.

Cui se adreseaz cartea?


Cartea se adreseaz studenilor din universitile cu profil
tehnic care parcurg programa cursului de programarea
calculatoarelor i limbaje de programare, celor care doresc s
programeze n limbajul C, dar i celor care au deja experien n
programare.
Coninutul
crii
urmeaz
programa
cursului
Programarea calculatoarelor i limbaje de programare predat de
autori studenilor din anul I la Academia Naval Mircea cel
Btrn din Constana.

Notaii folosite n carte


Carte conine urmtoarele notaii pentru a nlesni
urmrirea explicaiilor i secvenelor de program:
secvenele de program sunt scrise cu font proporional
simplu: printf("Bine ai venit!").
dac secvena de program este mai mare, atunci va fi
scris ntr-un paragraf separat, cu o linie n partea stng:
puts("Programarea");
puts("Calculatoarelor in");
puts("Limbajul C");

rezultatele execuiei programelor sunt scrise cu font


proporional ngroat: Bine ai venit!
dac rezultatele sunt mai multe, atunci vor fi scrise ntr-un
paragraf separat, ntr-o caset cu chenar ntrerupt:

Programarea
Calculatoarelor in
Limbajul C

observaiile i informaiile suplimentare legate de diverse


noiuni vor fi marcate printr-un paragraf special, astfel:
Aceste paragrafe v ofer informaii suplimentare.

Mulumiri
Mulumim familiilor noastre care ne-au susinut n
realizarea acestei cri i au ndurat orele trzii de munc.
Mulumim colegilor care au fcut observaii pertinente
privind coninutul acestei cri i personalului Editurii Europolis
pentru sfaturile privind tehnoredactarea.
De asemenea, mulumim anticipat celor care vor aduce
sugestii pentru mbuntirea acestei cri.
Cu toii ne-au ajutat n ncercarea noastr de a scrie o
carte fr greeli. Erorile pe care cititorul le va gsi ne aparin n
totalitate.

Autorii.
Decembrie 2006

Bazele programrii calculatoarelor

C
CU
UP
PR
RIIN
NS
S
1. Algoritmi i limbaje algoritmice ................................................. 9
1.1. De la problem la program ................................................ 9
1.2. Noiunea de algoritm ....................................................... 11
1.3. Reprezentarea algoritmilor .............................................. 12
1.4. Exemple .......................................................................... 17
1.5. Exerciii ............................................................................ 24
2. Uniti lexicale ........................................................................ 25
2.1. Mulimea caracterelor ...................................................... 25
2.2. Comentarii ....................................................................... 26
2.3. Tipuri de date primare ..................................................... 27
2.4. Constante ........................................................................ 28
2.5. Cuvinte cheie ................................................................... 31
2.6. Identificatori ..................................................................... 31
2.7. Exemple .......................................................................... 33
2.8. Exerciii ............................................................................ 34
3. Expresii. Operanzi. Operatori. ................................................ 36
3.1. Expresii ............................................................................ 36
3.2. Operanzi .......................................................................... 37
3.3. Conversii implicite de tip .................................................. 37
3.4. Operatori ......................................................................... 37
3.5. Exemple .......................................................................... 48
3.6. Exerciii ............................................................................ 54
4. Instruciuni.............................................................................. 56
4.1. Instruciuni expresie......................................................... 56
4.2. Instruciuni de decizie ...................................................... 56
4.3. Instruciuni de ciclare ....................................................... 59
4.4. Instruciuni de salt............................................................ 61
4.5. Exemple .......................................................................... 63
4.6. Exerciii ............................................................................ 77
5. Funcii standard de intrare/ieire ............................................ 78
5.1. Funcii pentru caractere ................................................... 78
5.2. Funcii pentru iruri de caractere ..................................... 79
3

Algoritmi i limbaje algoritmice

5.3. Funcii cu formatare ......................................................... 79


5.4. Funcii cu formatare pentru iruri de caractere ................ 86
5.5. Exemple ........................................................................... 86
5.6. Exerciii ............................................................................ 89
6. Tipuri de date compuse .......................................................... 91
6.1. Masive ............................................................................. 91
6.2. Structuri ........................................................................... 92
6.3. Uniuni .............................................................................. 95
6.4. Cmpuri ........................................................................... 96
6.5. Exemple ........................................................................... 96
6.6. Exerciii .......................................................................... 111
7. Funcii................................................................................... 113
7.1. Declararea i definirea funciilor..................................... 113
7.2. Apelul funciilor .............................................................. 115
7.3. Transmiterea parametrilor ............................................. 117
7.4. Recursivitate .................................................................. 123
7.5. Exemple ......................................................................... 124
7.6. Exerciii .......................................................................... 158
8. Pointeri i gestiunea dinamic a memoriei ........................... 160
8.1. Pointeri .......................................................................... 160
8.2. Operatorii &, * i -> ........................................................ 160
8.3. Aritmetica pointerilor ...................................................... 161
8.4. Legtura ntre tablouri i pointeri ................................... 162
8.5. Gestiunea dinamic a memoriei .................................... 163
8.6. Funcii pentru operaii cu blocuri de memorie ................ 165
8.7. Exemple ......................................................................... 166
8.8. Exerciii .......................................................................... 173
9. Funcii pentru iruri de caractere .......................................... 175
9.1. iruri de caractere ......................................................... 175
9.2. Funcii pentru iruri de caractere ................................... 175
9.3. Funcii pentru clasificarea caracterelor .......................... 179
9.4. Exemple ......................................................................... 181
9.5. Exerciii .......................................................................... 194
10. Funcii matematice ............................................................. 195
10.1. Exemple ....................................................................... 199
10.2. Exerciii ........................................................................ 208
4

Bazele programrii calculatoarelor

11. Funcii pentru gestiunea fiierelor ...................................... 210


11.1. Structura FILE ............................................................. 210
11.2. Fiiere standard de intrare/ieire ................................. 210
11.3. Deschiderea i nchiderea fiierelor............................. 211
11.4. Funcii pentru caractere ............................................... 211
11.5. Funcii pentru iruri de caractere ................................. 212
11.6. Funcii cu formatare ..................................................... 213
11.7. Funcii pentru blocuri de date ...................................... 214
11.8. Funcii pentru acces aleator n fiiere .......................... 216
11.9. Alte funcii pentru fiiere i directoare .......................... 216
11.10. Exemple .................................................................... 217
11.11. Exerciii ...................................................................... 229
12. Metode de programare....................................................... 232
12.1. Metoda Divide et Impera ........................................... 232
12.2. Exemple ...................................................................... 232
12.3. Metoda Backtracking ................................................... 238
12.4. Backtracking nerecursiv .............................................. 241
12.5. Exemple ...................................................................... 243
12.6. Backtracking recursiv .................................................. 254
12.7. Exemple ...................................................................... 256
12.8. Metoda Greedy ............................................................ 269
12.9. Exemple ...................................................................... 272
12.10. Metoda programrii dinamice .................................... 281
12.11. Exemple .................................................................... 282
13. ntrebri de autoevaluare ................................................... 294
13.1. Uniti lexicale ............................................................. 294
13.2. Expresii. Operanzi. Operatori ...................................... 294
13.3. Instruciuni ................................................................... 297
13.4. Funcii standard de intrare/ieire ................................. 298
13.5. Tipuri de date compuse ............................................... 299
13.6. Funcii .......................................................................... 299
13.7. Pointeri i gestiunea dinamic a memoriei .................. 301
13.8. Funcii pentru iruri de caractere ................................. 302
13.9. Funcii matematice ...................................................... 303
13.10. Funcii pentru gestiunea fiierelor .............................. 304
14. Anexa 1 Mediul de programare Dev-C++........................ 307
5

Algoritmi i limbaje algoritmice

14.1. Instalare ....................................................................... 307


14.2. Configurare .................................................................. 309
14.3. Utilizare ........................................................................ 312
15. Anexa 2 Setul de caractere ASCII ................................... 315

Bazele programrii calculatoarelor

Algoritmi i limbaje algoritmice

Bazele programrii calculatoarelor

11.. A
ALLG
GO
OR
RIITTM
MII
II LLIIM
MB
BA
AJJE
EA
ALLG
GO
OR
RIITTM
MIIC
CE
E
1.1. De la problem la program
Rezolvarea unei probleme ncepe cu specificarea
acesteia i se ncheie cu obinerea unui program concret i
corect. Programele sunt scrise pentru a instrui mainile s
lucreze cu sarcini specifice sau s rezolve probleme specifice. O
procedur (descris pas cu pas) asociat unei sarcini se numete
algoritm. Programarea este activitatea de codificare a algoritmilor
n calculatoare. Procesul de programare are (n general) patru
pai:
1. Specificarea problemei;
2. Proiectarea unui algoritm pentru rezolvarea sa;
3. Codificarea algoritmului ntr-un limbaj de programare;
4. Testarea programului.

1.1.1. Specificarea problemei


n prima faz, procesul de rezolvare const n analiza
problemei care are drept scop elaborarea unui enun complet i
precis al problemei, innd n acelai timp seam de condiiile de
realizare i execuie ale problemei.
Din enunul problemei trebuie s rezulte clar funciile
programului. Pentru aceasta, trebuie s se delimiteze clar
informaiile de intrare (care trebuie prelucrate de program) i
rezultatele ateptate de la program.
Pentru referirea la datele de intrare i cele de ieire se
folosete noiunea de variabile de intrare, respectiv variabile de
ieire. Trebuie s privim variabilele ca notaii simbolice pentru
valorile concrete pe care le prelucreaz algoritmul. Tot acum, n
aceast etap, trebuie precizat maniera de reprezentare i
organizare a datelor de intrare i de ieire. Rezultatul acestei
etape este specificaia (sau cerina) programului.
De exemplu, ne propunem s scriem un program care s
primeasc de la tastatur coeficienii reali a, b, c ai unei ecuaii de
9

Algoritmi i limbaje algoritmice

grad 2 i s calculeze soluiile reale ale acesteia, dac exist. Din


enun, obinem urmtoarele informaii despre problema noastr:
Date de intrare: a, b, c numere reale
Date de ieire: x1, x2 numere reale
Funcionalitate: dac exist, atunci calculeaz rdcinile
reale (x1 i x2) ale ecuaiei de grad 2 (specific prin a, b,
c), altfel afieaz mesajul Ecuaia nu are rdcini reale.
Organizarea i reprezentarea datelor de intrare i de ieire:
datele de intrare se citesc de la tastatur i rezultatele se
afieaz pe monitor.

1.1.2. Proiectarea algoritmului de rezolvare a


problemei
n aceast etap, programatorul trebuie s specifice o
list de comenzi care s descrie secvena de operaii executate
de calculator pentru a rezolva problema. n sens general, un
program reprezint scrierea unui algoritm ntr-un limbaj de
programare.
Aceast etap este evident cea mai dificil etap din
procesul de programare. n general, procesul de scriere al unui
algoritm este unul iterativ, descrierea algoritmului realizndu-se la
diferite nivele de detaliere. Acest mod de specificare pas cu pas a
rezolvrii se mai numete proiectare descendent.
De asemenea, pentru problemele mai complicate este
posibil descompunerea lor n subprobleme care s se rezolve
separat mai uor. Acest proces se numete modularizare i
uureaz modificarea programelor, deschiznd calea ctre
programe mai uor de reutilizat.

1.1.3. Codificarea algoritmului


Dup elaborare, algoritmul trebuie codificat cu ajutorul
unui limbaj de programare astfel nct s poat fi neles de
ctre calculator (altfel spus s poat fi tradus mai departe ntr-un
limbaj executabil pe calculator). Codificarea algoritmului este
facilitat de utilizarea unor simboluri i reguli speciale cum sunt
schemele logice sau limbajul pseudocod.
10

Bazele programrii calculatoarelor

1.1.4. Testarea i validarea programului


Programul obinut prin implementarea algoritmului trebuie
verificat n scopul eliminrii erorilor de sintax, dar mai ales al
eliminrii erorilor de logic. Este posibil ca n urma execuiei
programului s se obin rezultate incorecte, adic sunt eliminate
erorile de sintaxa i programul poate fi executat pe calculator, dar
acesta nu rezolv corect problema de la care s-a plecat (datorit
unei greeli de proiectare sau implementare a algoritmului). De
aceea, testarea programului trebuie s se fac cu seturi de date
de intrare care s acopere ct mai multe dintre cazurile posibile.
Aceast etap poart numele de validarea programului.
Activitatea de scriere a unui program nu se ncheie o dat
cu validarea acestuia, ci urmeaz etap de ntreinere. n aceast
etap este posibil s fie efectuate modificri ale programului,
datorate fie unor corecturi, fie schimbrii unor cerinelor. De
asemenea, o etap important o constituie realizarea
documentaiei programului explicaii despre cum trebuie utilizat
programul (e.g. Help) care s permit att modificri ulterioare
ale acestuia, dar i utilizarea programului de ctre alte persoane
dect cele care l-au creat.

1.2. Noiunea de algoritm


Noiunea de algoritm ocup un loc central n informatic.
Calculul algoritmic foreaz precizia gndirii, algoritmizarea unei
metode matematice presupune detalierea tuturor etapelor ei,
urmrirea pas cu pas a fiecreia dintre aceste etape, deci o
nelegere profund a ntregii metode.
Ca i alte noiuni matematice, noiunea de algoritm se
caracterizeaz printr-o mare generalitate. nelesul mai larg al
noiunii de algoritm este acela de procedeu, metod, reet.
Astfel, prin algoritm se nelege o mulime ordonat i finit de
reguli care descriu o succesiune finit de operaii necesare
rezolvrii unei probleme, care pornind de la date (intrri) produce
rezultate (ieiri).
Fiecare propoziie din descrierea unui algoritm este de
fapt o comand care trebuie executat de calculator. Comanda
11

Algoritmi i limbaje algoritmice

specific o aciune care se aplic unor date determinnd


modificarea acestora.
Principalele proprieti pe care ar trebui s le posede un
algoritm sunt urmtoarele:
s fie bine definit adic operaiile cerute s fie specificate
riguros i fr ambiguitate, astfel nct s poat fi executat
pe o main programabil;
s fie efectiv adic s se termine ntotdeauna dup un
numr finit de operaii;
s fie universal adic s permit rezolvarea unei clase
de probleme (nu o instan a unei probleme).
Un algoritm trebuie s fie determinist, adic executat de
mai multe ori pentru acelai set de date de intrare, s produc
aceleai rezultate.

1.3. Reprezentarea algoritmilor


Odat cu elaborarea unui algoritm, acesta trebuie
prezentat ntr-o form ct mai precis i mai clar, pentru a putea
fi transpus, n continuare, sub forma unui program neles de
calculator. Pentru reprezentarea algoritmilor se folosesc diverse
forme de descriere caracteristice (denumite limbaje algoritmice),
deoarece limbajul natural nu permite o descriere suficient de
riguroas a algoritmilor. n plus, pe msur ce complexitatea
problemelor crete, crete i complexitatea descrierii acestora n
limbaj natural.
n general, notaia folosit pentru reprezentarea
algoritmilor trebuie s satisfac urmtoarele cerine:
s fie uor de nvat i de folosit;
s permit exprimarea ct mai natural a raionamentelor
umane;
s reflecte caracteristicile limbajelor de programare pentru
a uura codificarea algoritmilor.
Avnd n vedere scopurile propuse, se dovedesc potrivite
dou forme de reprezentare a algoritmilor: scheme logice i
limbajul pseudocod.
12

Bazele programrii calculatoarelor

1.3.1. Scheme logice


O schem logic poate fi interpretat ca o reprezentare
grafic a algoritmului, format din blocuri i sgei. Blocurile
marcheaz operaii care trebuie efectuate, iar sgeile indic
ordinea acestora. n scheme logice se folosesc urmtoarele tipuri
de blocuri:
bloc de stare: marcheaz o etap n timpul execuiei
algoritmului a crui nume este specificat ntr-o elips.
Dou stri speciale sunt Start (care marcheaz nceputul
algoritmului) i Stop (care marcheaz sfritul
algoritmului).
Start

Stop

bloc de intrare: marcheaz operaia de citire a datelor de


intrare (lista de variabile a cror valori trebuie citite fiind
scris ntr-un trapez cu baza mare n sus).
lista de variabile

bloc de ieire: marcheaz operaia de generare a


rezultatelor (lista de variabile sau mesajele ce trebuie
afiate fiind scrise ntr-un trapez cu baza mare n jos).
lista de variabile

bloc de calcul: marcheaz operaia de prelucrare a


informaiilor (prin intermediul variabilelor n care sunt
stocate).
13

Algoritmi i limbaje algoritmice

variabila=expresie

bloc de decizie: marcheaz alegerea unei ci de execuie


n funcie de context: se verific o condiie; n cazul n care
condiia este adevrat, se urmeaz ramura marcat cu
DA, iar n caz contrar se urmeaz ramura marcata cu NU.
conditie
da

nu

1.3.2. Limbajul pseudocod


Limbajul pseudocod permite specificarea algoritmilor cu
ajutorul a dou tipuri de enunuri: standard i nestandard.
Enunurile standard exprim operaii cu corespondent direct n
limbajele de programare. Enunurile nestandard sunt fraze n
limbaj natural care pot fi utilizate de programator n schiarea
formelor iniiale ale algoritmilor. n general, dezvoltarea unui
algoritm se realizeaz iterativ, trecndu-l prin mai multe nivele de
detaliu, enunurile nestandard fiind nlocuite treptat cu enunuri
standard. De exemplu, pentru precizarea datelor iniiale se scrie:
Citeste a,b,c, iar pentru precizarea rezultatelor: Scrie x1, x2 sau
Scrie Ecuaia nu are soluii reale.
Att enunurile standard, ct i cele nestandard pot fi
ataate unor structuri de control. Cele mai utilizate structuri de
control sunt:
secvena reprezint o succesiune de comenzi pentru
prelucrarea datelor. De exemplu:
citete a, b
x = b + a
scrie x

14

decizia alegerea unei operaii sau a unei secvene dintre


dou alternative posibile:

Bazele programrii calculatoarelor


dac test atunci
secvena A
altfel
secvena B
sfrit

n limbaj natural, execuia poate fi descris astfel: se


evalueaz condiia test; dac rezultatul este valoarea logic
adevrat, atunci se execut secvena A, altfel (daca rezultatul
este fals), se execut secvena B. Exprimat cu o schem logic,
decizia arat astfel:
conditie
da

nu

secventa A

secventa B

De asemenea, exist i decizia cu o cale vid, exprimat


n pseudocod astfel (lsm exprimarea n schem logic ca
exerciiu pentru cititor):
dac test atunci
secvena A
sfrit

ciclul (sau iteraia) cu test iniial asigur executarea unei


secvene n mod repetat, n funcie de o anumit condiie
testat apriori.

ct timp test repet


secvena
sfrit

Execuia parcurge urmtoarele etape: se evalueaz


expresia test; dac rezultatul este adevrat, se execut
secvena i se repet secvena de ciclare, altfel se termin
secvena de ciclare i se trece la urmtoarea secven. Exprimat
cu o schem logic, ciclul cu test iniial arat astfel:
15

Algoritmi i limbaje algoritmice

conditie
da
nu

secventa

Dac valoarea testului e fals de la nceput, ciclul nu se


execut niciodat.

ciclul (sau iteraia) cu test final asigur executarea unei


secvene n mod repetat, n funcie de o anumit condiie
testat aposteriori.

repet
secvena
ct timp test

Execuia parcurge urmtoarele etape: se execut


secvena, se evalueaz expresia test; dac rezultatul este
adevrat, se repet secvena de ciclare, altfel se termin
secvena de ciclare i se trece la urmtoarea secven. Exprimat
cu o schem logic, ciclul cu test final arat astfel:
secventa
da

conditie
nu

Ciclul se execut mcar o dat, deoarece testarea se


realizeaz la sfrit.

Ciclul cu contor asigur executarea unei secvene n


mod repetat, pentru fiecare element al unei mulimi.

pentru contor=start la sfarsit pas pas repet


secvena
sfrit

16

Bazele programrii calculatoarelor


Execuia parcurge urmtoarele etape: variabila contor
primete pe rnd valorile start, start+pas, start+2*pas, ,
sfarsit, i pentru fiecare din aceste valori se execut se

secvena specificat. Ciclul cu contor este un caz particular al


ciclului cu test iniial (lsm cititorului ca exerciiu exprimarea unui
ciclu cu contor folosind un ciclu cu test iniial i structuri
secveniale). Ciclul cu contor poate fi exprimat n schem logic
astfel:

contor=start

contor<=sfarsit
da

secventa

nu

contor = contor + pas

1.4. Exemple
1.
Scriei un algoritm care s primeasc la intrare o
temperatur n grade Celsius i s calculeze temperatura
corespunztoare n grade Farenheit i Kelvin.
Din enunul problemei extragem urmtoarele cerine:
date de intrare: c numr real
date de ieire: f, k numere reale
funcionalitate: calculeaz f = 32 + 9*c/5 i k=c-273,15.
Soluia, n pseudocod i schem logic este urmtoarea:
citete c
f = 32 + 9*5/c
k = c + 273,15
scrie f,k

17

Algoritmi i limbaje algoritmice

Start
c
f=32+9*c/5
k=c-273,15

f, k

Stop

2.
Scriei un algoritm pentru rezolvarea ecuaiei ax+b=0, unde
a i b sunt numere reale citite de la tastatur.
Din enunul problemei extragem urmtoarele cerine:
date de intrare: a, b numere reale
date de ieire: x numr real
funcionalitate: dac a=0 i b=0, atunci afieaz mesajul
Orice numr real este soluie; dac a=0 i b0 atunci
afieaz mesajul Nu exist soluii reale; altfel afieaz
soluia ecuaiei de grad 1 (x=-b/a).
Soluia, n pseudocod i schem logic este urmtoarea:
citete a,b
dac a=0 atunci
dac b=0 atunci
scrie "Orice numr real este soluie"
altfel
scrie "Nu exist soluii reale"
sfrit
altfel
x = -b/a
scrie x
sfrit

18

Bazele programrii calculatoarelor

Start
a,b
a=0
da
nu

b=0
da

"Orice
numar real
este solutie"

nu

x=-b/a

"Nu exista
solutii
reale"

x
Stop

3.
Scriei un algoritm pentru rezolvarea ecuaiei ax2+bx+c=0,
unde a, b i c sunt numere reale citite de la tastatur.
Din enunul problemei extragem urmtoarele cerine:
date de intrare: a, b, c numere reale
date de ieire: x1, x2 numere reale
funcionalitate: dac a=0, atunci (pentru simplitate)
afieaz mesajul "Ecuaia nu este de gradul 2", altfel
calculeaz d=b2-4ac; dac d<0, atunci afieaz mesajul
"Ecuaia are soluii complexe", altfel afieaz soluiile
ecuaiei de grad 2 (x1=(-b-sqrt(d))/(2a) i x2=(b+sqrt(d))/(2a), unde sqrt reprezint funcia radical).
Soluia, n pseudocod i schem logic este urmtoarea:
citete a,b,c
dac a=0 atunci
scrie "Ecuaia nu este de gradul 2"
altfel
d = b*b-4*a*c
dac d<0 atunci
scrie "Ecuaia are soluii complexe"
altfel
x1=(-b-sqrt(d))/(2a)
x2=(-b+sqrt(d))/(2a)

19

Algoritmi i limbaje algoritmice


scrie x1, x2
sfrit
sfrit

Start
a,b,c
a=0

da

d=b*b-4*a*c

nu

x1=(-b-sqrt(d))/(2a)
x2=(-b+sqrt(d))/(2a)

nu

d<0
da

"Ecuatia
nu este de
gradul 2"

x1,x2

"Ecuatia are
solutii complexe"

Stop

4.
Scriei un algoritm care determin cel mai mare divizor
comun a dou numere naturale.
Din enunul problemei extragem urmtoarele cerine:
date de intrare: a, b numere naturale
date de ieire: c numr natural
funcionalitate: folosind algoritmul lui Euclid, se determin
r, restul mpririi lui a la b (notat cu r=a%b), i dac r este
nenul se repet operaia pentru a=b i b=r.
Soluia, n pseudocod i schem logic este urmtoarea:
citete a,b
repet
r = a % b
a = b
b = r
ct timp r0
c = a
scrie c

20

Bazele programrii calculatoarelor

Start
a,b
r=a%b
a=b
b=r
da

r!=0
nu

c=a
c

Stop

5.
Scriei un algoritm care determin dac un numr este prim
sau nu.
Din enunul problemei extragem urmtoarele cerine:
date de intrare: a numr natural
date de ieire: mesajul "prim" sau "compus"
funcionalitate: Fie d numrul de divizori ai lui a (adic
numere naturale din intervalul [2, a/2] pentru la care a se
mparte fr rest). Dac d este 0, atunci numrul este prim,
altfel este compus.
Soluia, n pseudocod i schem logic este urmtoarea:
citete a
d = 0
pentru i=2 la a/2 pas 1 repet
dac a % i = 0 atunci
d = d + 1
sfrit
sfrit

21

Algoritmi i limbaje algoritmice


dac d = 0 atunci
scrie "prim"
altfel
scrie "compus"
sfrit

Start
a
d=0

a%i=0
da
nu
da

d=d+1

i=i+1
i<=a/2
nu

"compus"

nu

d=0

da

"prim"

Stop

6.
Fie n un numr natural i a1,,an, respectiv, b1,,bn, doi
vectori de n numere reale. Scriei un algoritm care determin
produsul scalar al vectorilor a i b.
Din enunul problemei extragem urmtoarele cerine:
date de intrare: n numr natural, a1,,an, b1,,bn
numere reale
date de ieire: p numr real

22

Bazele programrii calculatoarelor

funcionalitate: determin valoarea produsului scalar


p=<a,b>= a1* b1+a2*b2++ an*bn.
Soluia, n pseudocod i schem logic este urmtoarea:

citete n
pentru i = 1 la n repet
citete a[i], b[i]
sfrit
p = 0
pentru i = 1 la n repet
p = p + a[i]*b[i]
sfrit
scrie p

Start
n

p
p=0
i=1

i=1

nu

nu

i<=n

i<=n
i=i+1

i=i+1
da

a[i], b[i]

da

p=p+a[i]*b[i]

Stop

Desigur c valoarea produsului scalar putea fi calculat n


acelai timp cu citirea elementelor vectorului, pseudocodul n
acest caz fiind urmtorul:
citete n
p = 0
pentru i = 1 la n repet
citete a[i], b[i]
p = p + a[i]*b[i]
sfrit
scrie p

23

Algoritmi i limbaje algoritmice

1.5. Exerciii
1.
Scriei un algoritm care determin perimetrul i aria unui
dreptunghi cunoscnd lungimile laturilor.
2.
Scriei un algoritm care determin consumul de combustibil
la o sut de kilometri al unui vehicul tiind consumul total pe
parcursul unei anumite distane.
3.
Scriei un algoritm care determin maximul a trei numere
reale citite de la tastatur.
4.
Scriei un algoritm care, cunoscnd trei valori naturale,
determin dac acestea pot reprezenta laturile unui triunghi. n
caz afirmativ, s se afieze dac triunghiul este oarecare, isoscel
sau echilateral.
5.
Scriei un algoritm pentru rezolvarea sistemului:
a*x + b*y = c
d*x + e*y = f
unde a, b, c, d, e, f sunt numere reale date.
6.
Scriei un algoritm care determin divizorii unui numr
natural nenul.
7.
Scriei un algoritm care determin factorialul unui numr
natural.
8.
Scriei un algoritm care transform un numr din baza 10 n
baza 2.
9.
Scriei un algoritm care transform un numr din baza 2 n
baza 10.
10. Fie n un numr natural i a1,,an numere reale. Scriei un
algoritm care determin media aritmetic a numerelor a1,, an.
11. Fie n un numr natural i a1,,an numere reale. Scriei un
algoritm care determin suma valorilor pozitive din mulimea
a1,,an.
12. Fie n un numr natural i a1,,an numere reale. Scriei un
algoritm care determin valoarea minim din mulimea a1,,an.
13. Fie n un numr natural i m, a1,,an numere reale. Scriei
un algoritm care afieaz toate valorile i pentru care ai=m.
14. Fie n un numr natural i a1,, an numere reale. Scriei un
algoritm care ordoneaz cresctor numerele a1,, an.
24

Bazele programrii calculatoarelor

22.. U
UNNIITTII LLEEXXIICCAALLEE
Unitile lexicale sunt atomii unui program C, aa cum un
roman este format din fraze, iar acestea din cuvinte. Scopul
acestui capitol este s v prezinte aceste noiuni fundamentale.
Orice program C este alctuit din cel puin o funcie (funcia
main). Orice funcie conine zero, una sau mai multe expresii. O
expresie este construit din operanzi conectai prin operatori
conform anumitor reguli sintactice. n plus, textul programelor
poate conine comentarii care s ajute la nelegerea acestuia.

2.1. Mulimea caracterelor


Unitile lexicale ale unui program C sunt alctuite din
caractere, fiecare caracter avnd un anume neles pentru
compilatorul C, folosirea incorect a acestora fiind semnalat prin
mesaje de eroare. Mulimea caracterelor ce pot fi folosite n
programe C este mprit n urmtoarele submulimi:
caractere alfanumerice: literele mici i mari din alfabetul
englez, i cifrele;
caractere speciale: caracterele prezentate n Tabel 2.1
caractere de spaiere: caracterele prezentate n Tabel 2.2
alte caractere: celelalte caractere tipribile din setul de
caractere ASCII (vezi Anexa 2 Setul de caractere ASCII)
Tabel 2.1 Caractere speciale

C
aracter
,
:

Denumire
virgul
dou

C
aracter
.
;

'
(

semnul
ntrebrii
apostrof
parantez
rotund stnga

punct
punct

virgul

puncte
?

Denumire

!
"
)

semnul
exclamrii
ghilimele
parantez
rotund dreapta
25

Uniti lexicale

[
{
<
^
+
*
%
|
_
&

parantez
dreapt stnga
acolad
stnga
mai mic
sgeat sus
plus
asterisc
procent
bar
vertical
underscore
ampersand

parantez
dreapt dreapta
}
acolad
dreapta
>
mai mare
=
egal
minus
/
slash
\
backslash
~
tild
]

diez

Tabel 2.2 Caractere de spaiere

Co
d ASCII
32
9
10
13

11
12

De
numire
sp
aiu
tab

Semnificaie
un spaiu

grup de spaii (tabulator


orizontal)
lin
trecere la linia urmtoare (new
e feed
line)
car
revenire la nceputul liniei
riage
curente
(folosit
n
special
la
return
imprimante)
tab
tabulator vertical (folosit n
vertical
special la imprimante)
for
trecere la pagina urmtoare
m feed
(folosit n special la imprimante)

2.2. Comentarii
Un comentariu este o poriune de text care este ignorat
de ctre compilatorul C. Un comentariu pe o singur linie ncepe
dup o secven slash-slash // i se termin la sfritul liniei
curente. Un comentariu pe una sau mai multe linii ncepe dup o
secven slash-star /* i se termin la prima secven star-slash
26

Bazele programrii calculatoarelor


*/. Pentru a uura nelegerea programelor se recomand

folosirea comentariilor ct mai detaliate.


De exemplu, o secven de program care calculeaz
suma a dou numere poate fi comentat astfel:
suma = a + b; // calculam suma lui a si b

sau
suma = a + b; /* calculam suma lui a si b */

Comentariile nu pot fi imbricate (i.e. nu putem introduce un


comentariu n alt comentariu) i nu pot fi scrise n interiorul
constantelor caracter sau ir de caractere.

2.3. Tipuri de date primare


Un tip de date este o informaie asociat unei expresii pe
baza creia compilatorul limbajului C determin n ce context
poate fi folosit expresia respectiv. De exemplu, cu un numr
ntreg se pot efectua operaii aritmetice. Orice expresie valid n
limbajul C are asociat un tip de date. Limbajul C definete patru
tipuri de date fundamentale: caracter (char), ntreg (int), flotant
(sau real) simplu (float) i flotant dublu (double), unele dintre
acestea avnd mai multe variante (denumite subtipuri).
n funcie de compilator, tipurile char i int reprezint
valori cu sau fr semn, dar programatorul poate s foloseasc
modificatorii signed i unsigned pentru a selecta un anume
subtip. De asemenea, implicit tipul int poate fi scurt sau lung, dar
programatorul poate s foloseasc modificatorii short i long
pentru a selecta subtipul dorit. n anumite situaii (foarte rare),
tipul flotant dublu (double) este echivalent cu flotant simplu
(float). Caracteristicile tipurilor i subtipurilor de baz sunt
prezentate n tabelul urmtor.
Tabel 2.3 Tipuri i subtipuri fundamentale de date

Tip/subti
p
unsigned

Mri
me (octei)
1

Domeniu de valori
0255

char
27

Uniti lexicale

signed

char

-128127

char
depinde (cu sau fr
semn)
short
signed int
short
unsigned int
short int

-3276832767

065535
depinde (cu sau fr

2
semn)

long
signed int
long
unsigned int
long int

4
4

21474836482147483647
0 4294967296
depinde (cu sau fr

4
semn)

signed int

2 sau

depinde (cu semn)

2 sau

depinde (fr semn)

4
unsigned
int

4
int
float
double

depinde (cu sau fr

2 sau
4

semn)
4
8

-3,401038...3,41038
1,7910308...1,7910308

2.4. Constante
Constantele reprezint cel mai simplu tip de operanzi,
mai exact o valoare care nu poate fi modificat i care are asociat
un tip (stabilit n funcie de modul de scriere al valorii constantei).

2.4.1. Constante de tip caracter


O constant de tip caracter se scrie n program ntre
apostrofi (e.g. C, 0, ., !). Tipul constantelor caracter
este ntotdeauna char. Pentru a scrie constantele caracter
apostrof, backslash (\) sau un caracter care nu apare pe tastatur
28

Bazele programrii calculatoarelor

se folosesc secvene escape. O secven escape este compus


din caracterul backslash (\) urmat de un caracter normal sau un
numr (n baza 8 sau 16). n acest context, semnificaia
caracterului sau a numrului de dup backslash devine una
special. Cele mai utile secvene escape sunt prezentate n Tabel
2.4. De exemplu, dac vrem s scriem constanta caracter
apostrof, atunci vom scrie \.
Tabel 2.4 Secvene escape valide n limbajul C

S
ecven
escape
\a
\n
\r
\t
\v
\f
\b
\\
\
\
\o
oo
\x
hh

Semnificaie
alert produce un sunt n difuzorul
calculatorului
new line trecerea la rndul urmtor
carriage return revenirea la captul rndului
horizontal tab deplasarea pe orizontal cu
un tab
vertical tab deplasarea pe vertical cu un
tab (la imprimant)
form feed trecerea la pagina urmtoare (la
imprimant)
backspace deplasarea napoi a cursorului
cu un caracter
backslash caracterul backslash
single quote caracterul apostrof
double quote caracterul ghilimele
octal caracterul cu codul ASCII ooo (unde
ooo este un numr n baza 8, vezi Anexa 2 Setul de
caractere ASCII)
hexazecimal caracterul cu codul ASCII hh
(unde hh este un numr n baza 16, vezi Anexa 2
Setul de caractere ASCII)

2.4.2. Constante de tip ir de caractere


O constant de tip ir de caractere este un grup de
caractere i secvene escape scrise ntre ghilimele (e.g. acesta
29

Uniti lexicale
este un sir). Daca o constant de tip ir de caractere este

prea lung, ea poate fi scris pe mai multe linii n program fie prin
terminarea fiecrui rnd (cu excepia ultimului) cu caracterul
backslash, fie prin scrierea fiecrui rnd ntre ghilimele. De
exemplu, urmtoarele trei iruri sunt identice:
Acesta este un sir
Acesta este \
un sir
Acesta este
un sir

Tipul constantelor ir de caractere este char[], adic un


vector de caractere. La sfritul fiecrui ir de caractere
compilatorul adaug automat caracterul NUL (caracterul cu codul
ASCII 0), ca marcator pentru sfritul irului.
Pentru a include caractere ghilimele ntr-un ir de
caractere se folosete secvena escape \. Funciile pentru
operaii cu caractere i iruri de caractere vor fi discutate n
detaliu n capitolul 8.

2.4.3. Constante de tip ntreg


O constant de tip ntreg este un numr ntreg scris n
baza 8, 10 sau 16. Dac numrul este scris n baza 8, atunci
trebuie s fie prefixat de cifra zero. Dac numrul este scris n
baza 16, atunci trebuie s fie prefixat de zero urmat de litera x.
Subtipul constantei este ales astfel nct domeniu
acestuia s conin valoarea constantei. Programatorul poate
scrie sufixele u (de la unsigned) i/sau l (de la long) pentru a
specifica un subtip anume (vezi seciunea 2.3). Dac valoarea
constantei nu poate fi memorat ca subtip long signed int sau
long unsigned int, atunci constanta se consider constant
de tip flotant.
De exemplu, constanta de tip ntreg 12 poate fi scris:
014 (n baza 8), 12 (n baza 10) sau 0xC (n baza 16). Dac
scriem 12l, constanta are tot valoarea 12, dar tipul este ntreg
lung, iar dac scriem 12ul, tipul ei este ntreg lung fr semn.

30

Bazele programrii calculatoarelor

n limbajul C, codificarea valorilor de tip ntreg cu semn se


face folosind codul complementar fa de 2. n acest caz,
bitul cel mai din stnga al numrului codific semnul, iar
restul biilor valoarea. Bitul de semn este 0 pentru numere
pozitive i 1 pentru numere negative. n plus, valoarea n
baza 10 a numerelor negative se calculeaz negnd bii de
valoare i adunnd 1 la rezultat.

2.4.4. Constante de tip flotant


O constant de tip flotant este un numr real scris n baza
10, cu sau fr zecimale, cu sau fr exponent. Exponentul este
alctuit din litera e urmat de un numr ntreg n, cu semnificaia
c valoarea constantei este numrul dinaintea exponentului
nmulit cu 10n. Separator pentru zecimale este punctul. Dac
numrul nu are zecimale sau exponent, atunci trebuie urmat de
un punct pentru a fi considerat real.
Tipul implicit al constantei este tipul double, dar dac
aceasta este urmat de litera f (de la float), tipul implicit va fi
float (vezi seciunea 2.3).
De exemplu, constanta cu valoarea -12,5 i tip double se
poate scrie: -12.5 sau -1.25e1. Dac scriem -12.5f, atunci tipul
este float.

2.5. Cuvinte cheie


Un cuvnt cheie este o secven caractere alfanumerice,
care are o semantic predefinit n limbajul C. Cuvintele cheie ale
limbajului C (standardul ANSI) sunt: auto, break, case, char,
const, continue, default, do, double, else, enum, extern,
float, for, goto, if, int, long, register, return, short,
signed, sizeof, static, struct, switch, typedef, union,
unsigned, void, volatile i while.

2.6. Identificatori
Un identificator este un nume pe care programatorul l d
unei entiti (aceasta poate fi o variabil vezi seciunea
urmtoare, funcie vezi capitolul 7, sau tip de date vezi
31

Uniti lexicale

capitolul 6) pentru a putea lucra mai uor cu aceasta. Un


identificator este o secven de caractere alfanumerice i
underscore (_), care ncepe cu o liter sau underscore.
Identificatorii trebuie s fie diferii de cuvintele cheie. De exemplu,
identificatorii varsta, greutate, total1980, _secret sunt
identificatori coreci, dar 1980total, 1_secret nu sunt.

2.6.1. Variabile
O variabil este un identificator care are asociat un tip, o
adres de memorie i o valoare (i.e. informaia din memorie de la
adresa asociat variabilei). nainte de a fi folosit n program,
orice variabil trebuie declarat, adic se specific numele i tipul
variabilei. Tipul variabilei determin ce operaii se pot efectua cu
valoarea variabilei. Adresa de memorie unde va fi stocat
valoarea variabilei se stabilete automat. Valoarea variabilei
poate fi specificat n faza de declarare (operaie denumit
iniializare) sau ulterior (operaie denumit atribuire).
De exemplu, pentru a defini o variabil de tip flotant dublu
cu numele PI i valoarea 3,1415926, i dou variabile de tip
ntreg fr semn cu numele varsta i greutate, din care varsta
este iniializat cu valoarea 26 vom scrie:
double PI = 3.1415926;
unsigned int varsta = 26, greutate;

2.6.2. Masive
Masivele (sau tablourile de date) sunt blocuri de variabile
de acelai tip, grupate n memorie, accesibile printr-un nume
comun i coordonatele lor n interiorul grupului. Declararea unui
masiv i accesarea elementelor acestuia se realizeaz cu ajutorul
caracterelor paranteze ptrate (denumite n acest context
operator de indexare). Indexarea masivelor se face n limbajul C,
pornind de la 0. Masivele i proprietile acestora sunt prezentate
n capitolul 6. Deocamdat vom prezenta doar cteva exemple:
float v[10];
reale
char c[65];

32

// v este un masiv de 10 valori


// c este un masiv de 65 caractere

Bazele programrii calculatoarelor


int mat[5][5];
// mat este un masiv de 5x5 valori
intregi
v[3]=0; // al 4-a valoare din v devine 0

n limbajul C, o variabil de tip ir de caractere cu maxim n


caractere se declar ca un vector de tip char cu dimensiune
n+1. irurile de caractere sunt discutate n capitolul 9.

2.7. Exemple
7.
Programul urmtor exemplific noiunile discutate n acest
capitol. Instruciunea de preprocesare din prima linie cere
folosirea bibliotecii de funcii stdio.h, care conine funcii standard
de intrare/ieire (vezi capitolul 4) precum printf. Urmeaz
definiia funciei main, punctul de pornire al oricrui program C. n
corpul funciei main (ntre cele dou acolade), se declar
variabilele PI, raza i aria, prima fiind i iniializat. Funcia
printf afieaz pe ecran mesajul "Introducei raza", iar valoarea
introdus de utilizator este memorat n variabila raza cu ajutorul
funciei scanf. Instruciunea urmtoare calculeaz aria unui cerc
i atribuie rezultatul variabilei aria. n final, funcia printf
afieaz rezultatul calculelor. Codurile %g din mesajul funciei vor
fi nlocuite cu valorile corespunztoare parametrilor raza i aria.
Instruciunea return din final este opional, dar scrierea ei este
o practic bun, valoarea 0 simboliznd terminarea fr erori a
programului.
#include <stdio.h>
#include <conio.h>
int main()
{
float PI = 3.1415926, raza, aria;
printf("Introduceti raza:");
scanf("%f", &raza);
aria = PI * raza * raza;
printf("Aria unui cerc cu raza %g este %g.\n",
raza, aria);
getch();
return 0;
}

33

Uniti lexicale

Cnd este pornit din interfaa grafic din Windows, fereastra


programului dispare de pe ecran dup rulare. Pentru a
suspenda execuia programului pn cnd utilizatorul apas
o tast am folosit instruciunea getch() din biblioteca
conio.h conform indicaiilor din seciunea 14.3.1.
Pentru a compila i rula acest program, consultai Anexa 1
Mediul de programare Dev-C++.
Rezultatul rulrii programului este urmtorul:

Introduceti raza:3.1
Aria unui cerc cu raza 3.1 este 30.1907.

8.

Programul urmtor afieaz suma a dou numere ntregi.

#include <stdio.h>
#include <conio.h>
int main()
{
int a, b;
printf("Introduceti a si b");
scanf("%i %i", &a, &b);
printf("%i + %i = %i", a, b, a+b);
getch();
}

2.8. Exerciii
15. Determinai tipul unitilor lexicale din exemplele anterioare.
16. Care dintre urmtoarele secvene sunt constante de tip
caracter: 'a', a, "a", \a i 'aa'?
17. Care dintre urmtoarele secvene sunt constante de tip ir
de caractere: 'a', a, "a", "a"a", "a\"a", "a\\"a" i "aa"?
18. Care dintre urmtoarele secvene sunt constante de tip
ntreg: a, 0xa, 0a, 10, 10.1, 10ul i 10.?
19. Care dintre urmtoarele secvene sunt constante de tip
flotant (simplu sau dublu): 10, 10.1, 10ul, 10.f i 10.?
20. Care dintre urmtoarele secvene pot fi folosite ca
identificator: test, test10, _test10, test_10, 10test, _10test i _10?
21. Determinai tipul, numele i valoarea urmtoarelor variabile:
int test=10, real=010, fictiv=0x10;
float greutate=1.3e2, densitate=3.2;

34

Bazele programrii calculatoarelor


char cod='a', adresa[30]="Constanta";

22. Modificai exemplul 7 astfel nct s calculeze volumul unui


cilindru.
23. Scriei un program C care afieaz pe ecran urmtorul
desen folosind funcia printf:
,-.
_.---._
| `\.__.-''
".
\ _
_ ,.
\
,+++=._________________)_||______|_|_||
|
(_.ooo.===================||======|=|=||
|
~~'
| ~'
"~' o o /
\
/~'\
o o /
`~'
`-.____.-'

24. Scriei un program C care afieaz pe ecran urmtorul


desen folosind funcia printf:
|
.
|
.
.
.
.
/-\
:
|"""| .
*
|>~
/"""""\
.
/\| _
__
___|# # # #| ___
___/<>\ |:
_|~~| |'''|# # # #||"""| __|"""|^^| |:
:|''|~~~~,|# # # #||"""|-|::|"""|''|_|
:|''|""""||# # # #||"""|t|::|"""|''|"""
|''|""""||# # # #||"""|||::|"""|''""""
*

35

Expresii. Operanzi. Operatori.

33.. E
EXXPPRREESSIIII.. O
OPPEERRAANNZZII.. O
OPPEERRAATTO
OR
RII..
3.1. Expresii
O expresie este o secven de operanzi i operatori. Un
operand poate fi o constant, o variabil sau o alt expresie. O
expresie este caracterizat de o valoare i un tip. Valoarea i tipul
expresiei sunt determinate de operatorii i operanzii care
formeaz expresia.
Regulile de asociativitate i preceden a operatorilor
sunt n general aceleai ca cele din matematic cu unele excepii,
dar o expresie poate conine paranteze rotunde pentru
schimbarea prioritii de evaluare subexpresiilor sale. De
exemplu, fie expresia:
a = (a*b-c/d)*(a-b);

n aceast expresie a este primul operand al operatorului


de atribuire =, iar (a*b-c/d)*(a-b) este al doilea operand. Al
doilea operand (a*b-c/d)*(a-b), este o expresie n care
expresia (a*b-c/d) este primul operand al operatorului de
nmulire *, iar expresia (a-b) este al doilea operand. Similar,
expresia a*b este primul operand al operatorului de scdere -, iar
expresia c/d este al doilea operand, .a.m.d.
Dac variabilele a, b, c, d au valorile respectiv 2, 3, 6, 3,
atunci expresia (a*b-c/d)*(a-b) are valoarea -4. Astfel
variabilei a i se atribuie valoarea -4. n plus, n limbajul C, valoare
unei expresii de atribuire este valoarea variabilei destinaie dup
atribuire, deci valoarea ntregii expresii va fi -4.
Valoarea logic de adevr a expresiei a=(a*b-c/d)*(ab) este adevrat, deoarece expresia are valoare nenul.

36

n limbajul C, o expresie are valoarea logic de adevr


adevrat dac are valoare nenul i are valoarea logic de
adevr fals dac are valoare nul.

Bazele programrii calculatoarelor

3.2. Operanzi
Un operand poate fi: o constant, o constant simbolic,
un identificator de variabil simpl, un identificator de tablou, un
element de tablou, un identificator de structur, un membru al
unei structuri, numele unei funcii, un apel de funcie sau o
expresie.

3.3. Conversii implicite de tip


n unele situaii, n timpul evalurii unei expresii, tipul unei
subexpresii poate s fie schimbat automat n alt tip cu domeniul
de valori mai mari. Aceast operaie se numete conversie
implicit de tip i realizeaz astfel:
orice operand de tipul char se convertete la tipul int;
orice operand de tipul short se convertete la tipul int.
n plus, unii operatori prelucreaz informaiile stocate n
doi operanzi. Dac operanzii au acelai tip, atunci rezultatul
operatorului are acelai tip cu al operanzilor. Altfel, unul dintre
operanzi se convertete la tipul celuilalt, conform urmtoarelor
reguli:
dac un operand este de tipul double atunci i cellalt
operand se convertete la tipul double;
dac un operand este de tipul float atunci i cellalt
operand se convertete la tipul float;
dac un operand este de tipul unsigned long atunci i
cellalt operand se convertete la tipul unsigned long;
dac un operand este de tipul long atunci i cellalt
operand se convertete la tipul long.

3.4. Operatori
Limbajul C dispune de un set puternic de operatori.
Operatorii se pot clasifica dup aritate, dup asociere sau dup
prioritatea la evaluare ntr-o expresie. Din punct de vedere al
aritii (adic numrul de operanzi), operatorii sunt unari, binari i
ternari. Operatorii unari se scriu n general naintea operandului
lor (de exemplu: -5, !a, ~x, etc.). Excepie de la aceast regul fac
37

Expresii. Operanzi. Operatori.

operatorii de incrementare i decrementare postfixai i operatorul


sizeof, a cror sintax este x++, x-- i sizeof(expresie).
Operatorii binari se scriu ntre operanzii lor (de exemplu: a+b,
x<<3, etc.). Singurul operator ternar al limbajului C este
operatorul condiional.
Din punct de vedere al asociativitii, operatorii pot fi
asociativi de la stnga la dreapta sau de la dreapta la stnga. Cu
excepia operatorilor de atribuire, operatorului condiional i
operatorilor unari, restul operatorilor au asociativitate de la stnga
la dreapta.
n limbajul C, sunt definite 15 niveluri de preceden;
nivelul 1 este cel mai prioritar, iar nivelul 15 este cel mai puin
prioritar. Operatorii aflai pe un anumit nivel de prioritate au
aceeai prioritate. Prezentm n ordine descresctoare a
precedenei toi operatorii limbajului C.
Tabel 3.1 Operatorii limbajului C

Nivel

Cate
gorie
Oper
atori
de
adresare

Operator
()

Aritate
(asociativitate)

[]
.
->
2

Oper
atori unari

!
~
+ ++ -SD)
&

38

Semnifica

Apel
funcie
s
schimbare prioritat
2 (SD)
Operator
indexare
2 (SD)
Operator
selecie direct
2 (SD)
Operator
selecie indirect
1 (DS)
Negare log
1 (DS)
Negare
nivel de bit
1 (DS)
Operator
semn
1 (DS,
Incrementa
decrementare
1 (DS)
Operator

Bazele programrii calculatoarelor

adres
*

1 (DS)

sizeo

1 (DS)

(tip)

1 (DS)

*
/
%
+
<<

2 (SD)
2 (SD)
2 (SD)
2 (SD)
2 (SD)
2 (SD)

>>

2 (SD)

<
<=

2 (SD)
2 (SD)

>
>=

2 (SD)
2 (SD)

==
!=

2 (SD)
2 (SD)

Operato
adresare indirec
Dimensi
n
octei
operandului
Convers
explicit de tip (c
nmulire
mprire
Modulo
Adunare
Scdere
Deplasa
stnga
Deplasa
dreapta
Mai mic
Mai mic
egal
Mai mar
Mai mar
egal
Egal
Diferit

&
^

2 (SD)
2 (SD)

I pe bi
SAU ex

4
5

Oper
atori
multiplicativi
Oper
atori aditivi
Oper
atori
de
deplasare
Oper
atori
relaionali

8
9

Oper
atori
de
egalitate
Oper
atori pe bii

pe bii
10
11
12
13
14

Oper
atori logici
Oper
ator ternar
Oper
atori
de

|
&&
||
?:

2 (SD)
2 (SD)
2 (SD)
3 (DS)

2 (DS)

SAU pe
I logic
SAU log
Operato
condiional
Atribuire
simpl
39

Expresii. Operanzi. Operatori.

atribuire

15

Oper
ator
secvenial

*=

2 (DS)

/=

2 (DS)

%=

2 (DS)

+=

2 (DS)

-=

2 (DS)

&=

2 (DS)

^=

2 (DS)

|=

2 (DS)

<<=

2 (DS)

>>=

2 (DS)

2 (SD)

nmulire
atribuire
mprire
atribuire
Modulo
atribuire
Adunare
atribuire
Scdere
atribuire
I pe bii
atribuire
SAU exclu
pe bii i atribuire
SAU pe bi
atribuire
Deplasare
stnga i atribuire
Deplasare
dreapta i atribuire
Evaluare li
expresii

3.4.1. Operatori de adresare


Operatorul de apelare ( ) este folosit ca separator al
listei de parametri a funciilor sau ca modificator de prioritate n
evaluarea expresiilor. Operatorul de indexare [ ] este folosit
pentru accesarea valorilor din tablouri de date i va fi discutat n
capitolul dedicat tablourilor. Operatorii de selecie direct . i de
selecie indirect -> se folosesc n gestiunea structurilor i
uniunilor i vor fi discutai n capitolul 6.
De exemplu, instruciunea
printf("Elementul 4 din vectorul v este %d", v[3]);

40

Bazele programrii calculatoarelor

folosete funcia printf pentru a afia un mesaj. Parametrii funciei


sunt scrii n operatorul de apelare, unul dintre acetia fiind al
patrulea element din vectorul v.

3.4.2. Operatori unari


Operatorul de negare logic are rezultatul 1 dac
valoarea operandului este nul i 0 dac valoarea operandului
este nenul. Ca exemplu, fie secvena:
int a = 21,b;
b=!a; // b este 0 deoarece a e diferit de 0
b=!b; // b devine 1 deoarece b este 0

Operatorul de negare la nivel de bit schimb toi biii


operandului din 0 n 1 i din 1 n 0. Ca exemplu, fie secvena:
short int a = 33,b;
b=~a;

S determinm valoarea lui b. Reprezentarea n baza 2,


pe 16 de bii a numrului 33 este: 0000.0000.0010.0001. Dac se
schimb toi biii 0 n 1 i toi biii 1 n 0 i se obine numrul:
1111.1111.1101.1110. Deoarece aceast valoare este scris n
cod complementar fa de 2, valoarea n baza 10 a lui b este -34.
Operatorul de semn plus are ca rezultat valoarea
operandului, iar operatorul de semn minus are ca rezultat
valoarea cu semn schimbat a operandului. De exemplu,
int a = 33, b, c;
b = -a;
c = +b;

Operatorii de adres i de adresare indirect, avnd


sintaxa &operand, respectiv, *operand, sunt folosii pentru
operaii cu adrese de memorie i vor fi detaliai n capitolul 8.
Operatorii de incrementare i decrementare au fiecare
dou forme: prefixat ++operand i postfixat operand++,
respectiv, operand i operand--. n forma prefixat valoarea
operandului se mrete cu 1 (adic se incrementeaz), respectiv
se micoreaz cu 1 (adic se decrementeaz), iar rezultatul
expresiei este noua valoare. n forma postfixat, valoarea
41

Expresii. Operanzi. Operatori.

operandului se incrementeaz, respectiv decrementeaz, iar


rezultatul expresiei este vechea valoare.
Operatorul sizeof are ca rezultat dimensiunea n octei a
operandului (adic numrul de octei necesari pentru memorarea
unei informaii de acest tip). Operandul poate s fie o expresie
sau un tip de dat. Dac operandul este o expresie, atunci se
evalueaz expresia i sizeof calculeaz dimensiunea n octei
pentru tipul rezultatului. De exemplu,
long b;
char c;
b=sizeof(c); // b = 1 (un caracter ocupa 1 octet)
b=sizeof(-b);// b = 4 (un long int ocupa 4 octeti)

Operatorul de conversie explicit (denumit operator cast)


este folosit atunci cnd este necesar conversia unei valori la un
anumit tip. Sintaxa operatorului este: (tip)expresie, unde tip
este tipul spre care se convertete valoarea expresiei. De
exemplu, operatorul de mprire aplicat la doi operanzi ntregi
efectueaz mprirea ntreag (fr zecimale); pentru a calcula
valoarea real unul dintre operanzi trebuie transformat n tipul
float sau double:
int a = 6, b = 10;
float f;
f=a/b;
// f=6/10 = 0 (impartire intreaga)
f=(float)a/b;// f=6.0/10 = 0.6 (impartire reala)

3.4.3. Operatori multiplicativi


Operatorul de nmulire are sintaxa operand1*operand2
i rezultatul este produsul valorilor celor doi operanzi, cu
eventuale conversii de tip.
Operatorul de mprire are sintaxa operand1/operand2
i rezultatul este ctul mpririi primului operand la cel de-al
doilea operand, cu eventuale conversii de tip. Dac ambii
operanzi sunt ntregi, atunci operandul 2 trebuie s fie nenul.
Operatorul modulo are sintaxa operand1%operand2, se
aplic numai operanzilor de tip ntreg i rezultatul este restul
mpririi primului operand la cel de-al doilea operand. Operandul
2 trebuie s fie nenul.
42

Bazele programrii calculatoarelor

Pentru exemplificare considerm secvena urmtoare:


int a = 3, b = 6;
double c = 8.1, d = 1.1;
printf("%d\n", a * b);//
printf("%f\n", a * d);//
printf("%f\n", c * d);//
printf("%d\n", b / a);//
printf("%d\n", a / b);//
printf("%f\n", c / a);//
printf("%f\n", c / d);//
printf("%d\n", a % b);//
printf("%d\n", b % a);//

Valoarea
Valoarea
Valoarea
Valoarea
Valoarea
Valoarea
Valoarea
Valoarea
Valoarea

18 de tip intreg
6.6 de tip real
8.91 de tip real
2 de tip intreg
0 de tip intreg
2.7 de tip real
7.36 de tip real
3 de tip intreg
0 de tip intreg

3.4.4. Operatori aditivi


Operatorul de adunare are sintaxa operand1+operand2
i rezultatul este suma valorilor celor doi operanzi, cu eventuale
conversii de tip. Operatorul de scdere are sintaxa operand1
operand2 i rezultatul este diferena dintre valoarea primului i a
celui de-al doilea operand, cu eventuale conversii de tip.
Pentru exemplificare considerm secvena urmtoare:
int a = 3, b = 5;
double c = 8.12, d
printf("%d\n", a +
printf("%d\n", a
printf("%f\n", c
printf("%f\n", a +
printf("%f\n", c +
printf("%f\n", c

= 1.1;
b);// Valoarea
b);// Valoarea
b);// Valoarea
c);// Valoarea
d);// Valoarea
d);// Valoarea

8 de tip intreg
-2 de tip intreg
3.12 de tip real
11.12 de tip real
9.21 de tip real
7.02 de tip real

3.4.5. Operatori pentru deplasare


Operatorii de deplasare se aplic operanzilor de tip
ntreg, rezultatul fiind de tip ntreg. Operatorul de deplasare
stnga are sintaxa: operand1<<operand2 i rezultatul se obine
prin deplasarea la stnga a configuraiei binare a primului
operand, cu numrul de bii dat de valoarea celui de-al doilea
operand. Poziiile binare rmase libere n dreapta se completeaz
cu zerouri.
Operatorul de deplasare dreapta are sintaxa:
operand1>>operand2 i rezultatul se obine prin deplasarea la
43

Expresii. Operanzi. Operatori.

dreapta a configuraiei binare a primului operand, cu numrul de


bii dat de valoarea celui de-al doilea operand. Poziiile binare
rmase libere n stnga se completeaz cu bitul de semn pentru
subtipurile cu semn (e.g. int, short, etc.), sau cu 0 pentru
subtipurile fr semn (e.g. unsigned int, unsigned short, etc.).

Deplasarea la stnga cu n poziii binare este echivalent cu


nmulirea cu 2n. Deplasarea la dreapta cu n poziii binare
este echivalent cu mprirea cu 2n. n ambele cazuri,
valoarea final nu poate depi domeniul de valori al tipului
rezultatului.
De exemplu, fie secvena:

short int a = 20, b = 2, c;


c = a << b; // c este 80
d = a >> b; // d este 5

Pentru a calcula valoarea lui c, se reprezint valoarea lui


a n baza 2 (0000.0000.0001.0100), se deplaseaz cu 2 poziii la

stnga (0000.0000.0101.0000) i se interpreteaz rezultatul n


baza 10. Deci 20<<2 este 80.
Pentru a calcula valoarea lui d, se reprezint valoarea lui
a n baza 2 (0000.0000.0001.0100), se deplaseaz cu 2 poziii la
dreapta (0000.0000.0000.0101) i se interpreteaz rezultatul n
baza 10. Deci 20>>2 este 5.

3.4.6. Operatori relaionali


Operatorii relaionali sunt folosii pentru tipurile aritmetice
de date i pentru datele de tip pointer, avnd sintaxa operand1
operator operand2. Valoarea expresiei se obine astfel: se
evalueaz cei doi operanzi; dac valoarea primului operand este
n relaia dat de operator, cu al doilea operand, rezultatul
expresiei este 1; altfel rezultatul expresiei este 0. De exemplu:
int
c =
c =
c =
c =

44

a = 20, b =
a<b;
//
a<=b;
//
a>b;
//
a>=b;
//

13, c;
c este
c este
c este
c este

0
0
1
1

Bazele programrii calculatoarelor

3.4.7. Operatori de egalitate


Operatorii relaionali sunt folosii pentru tipurile aritmetice
de date i pentru datele de tip pointer, avnd sintaxa operand1
operator operand2. Valoarea expresiei se obine astfel: se
evalueaz cei doi operanzi; dac valoarea primului operand este
n relaia dat de operator, cu al doilea operand, rezultatul
expresiei este 1; altfel rezultatul expresiei este 0.
De exemplu, fie secvena:
int a = 20, b = 13, c;
c = a==b;
// c este 0
c = a!=b;
// c este 1

3.4.8. Operatori pe bii


Operatori pe bii binari folosesc operanzi de tip ntreg, iar
rezultatul este de tip ntreg, sintaxa general fiind operand1
operator operand2. Funcia operatorului se aplic fiecrei
perechi de bii de acelai rang din reprezentarea binar a
operanzilor conform tabelului urmtor, iar rezultatul este dat de
configuraia de bii care se obine.
Tabel 3.2 Tabelul de adevr al funciilor I, SAU exclusiv i SAU

a b
&b
0 0
0 1
1 0
1 1
De exemplu, fie secvena:
short
c = a
d = a
e = a

int a = 20,
& b;
// c
^ b;
// d
| b;
// e

a
^b
0
0
0
1

a
|b
0
1
1
0

a
0
1
1
1

b = 13, c, d, e;
este 4
este 25
este 29

Pentru a calcula valoarea lui c, se reprezint n baza 2


valoarea lui a i b (adic 0000.0000.0001.0100, respectiv
0000.0000.0000.1101); se aplic operatorul I pentru fiecare
45

Expresii. Operanzi. Operatori.

pereche de bii i se obine: 0000.0000.0000.0100. Deci, 20 & 13


este 4.
Pentru a calcula valoarea lui d, se reprezint valoarea lui
a i b n baza 2 i se aplic operatorul SAU exclusiv pentru
fiecare pereche de bii i se obine: 0000.0000.0001.1001. Deci,
20 ^ 13 este 25.
Pentru a calcula valoarea lui e, se reprezint valoarea lui
a i b n baza 2 i se aplic operatorul SAU pentru fiecare
pereche de bii i se obine: 0000.0000.0001.1001. Deci, 20 | 13
este 29.

3.4.9. Operatori logici


Operatori logici binari se aplic valorilor operanzilor
conform funciei descrise n Tabel 3.2. Evaluarea se realizeaz
prin scurt-circuit, adic evaluarea operanzilor se oprete atunci
cnd valoarea expresiei a fost stabilit i nu mai poate fi
schimbat de restul expresiei. De exemplu:
short int a = 20, b = 0, c, d;
c = a && b; // c este 0 (deoarece c este 0)
d = a || b; // d este 1 (deoarece a este 20)

3.4.10. Operatorul condiional


Operatorul condiional este singurul operator ternar al
limbajului C. Sintaxa sa este: operand1?operand2:operand3.
Valoarea expresiei se obine astfel: se evalueaz expresia
operand1; dac valoarea acesteia este nenul rezultatul
expresiei este valoarea lui operand2, iar operand3 nu se mai
evalueaz; altfel, rezultatul expresiei este valoarea lui operand3,
iar operand2 nu se mai evalueaz.

3.4.11. Operatori de atribuire


Operatorii de atribuire sunt de dou tipuri: simplu i
compui. Operatorul de atribuire simpl are sintaxa var=expr
unde var este o variabil sau un element dintr-un tablou, iar expr
este o expresie. Valoarea expresiei de atribuire se calculeaz
astfel: se evalueaz expresia expr. Valoarea obinut se atribuie
46

Bazele programrii calculatoarelor

variabilei var, cu eventuale conversii de tip, iar valoarea operaiei


este valoarea lui var. De exemplu, considerm secvena:
int a, b;
char c;
double d;
a = 5;
d = 12.21;
b = a + 3.5;
b = b+d;
c = 'x';

//
//
//
//
//

a
c
b
b
d

este
este
este
este
este

5
12.21
8 (se face conversie la int)
20 (se face conversie la int)
caracterul x

Pentru atribuirea simpl de forma:


variabila = variabila operator expresie;

unde operator poate fi oricare dintre operatorii binari, se poate


folosi operatorul compus operator=, astfel:
variabila operator=expresie;

De exemplu:
int a = 3, b = 5;
a += b; // Echivalent cu a = a+b, deci a = 8

Operatorii de atribuire se evalueaz de la dreapta ctre


stnga. n cazul unor atribuiri multiple, evaluarea expresiei se
face ncepnd din partea dreapt i la fiecare pas se aplic
conversiile de tip necesare. De exemplu,
int a = 5, b = 8;
double d = 12.21;
a = b = b+d; // b este 20 (datorita conversiei)
// deci a este 20

n acest caz, nti se evalueaz expresia b+d, rezultatul


fiind 20.21. Ulterior se atribuie valoarea variabilei b, nu nainte de
a se realiza conversia de la tipul double (tipul expresiei) la tipul int
(tipul variabilei b), deci b devine 20 i valoarea expresiei b = b+d
este tot 20. n continuare, a capt valoarea 20 i valoarea
ntregii expresii este 20.

47

Expresii. Operanzi. Operatori.

3.4.12. Operatorul virgul


Operatorul virgul este folosit pentru scrierea unei
expresii format dintr-o list de expresii, avnd sintaxa:
operand1, operand2, ..., operandn. Valoarea expresiei se
calculeaz astfel: se evalueaz succesiv valorile lui operand1,
operand2, ..., operandn. Tipul i valoarea ntregii expresii este
tipul i valoarea expresiei operandn. De exemplu,
int a, b, c;
a=2, b=5, c=b%2;

nti se atribuie variabilei a valoarea 2, apoi se atribuie


variabilei b valoarea 5 i n final variabilei c restul mpririi valorii
lui b la 2, adic se atribuie variabilei c valoarea 1. Valoarea
expresiei a=2,b=5,c=b%a este 1 (valoarea expresiei c=b%a), iar
tipul ei este int (tipul expresiei c=b%a).

3.5. Exemple
9.
Programul urmtor exemplific funcionarea operatorilor
unari !, ~, ++, , &, *.
#include <stdio.h>
#include <conio.h>
int main()
{
int val, temp, rez, *pint;
char oper;
printf("Testarea operatorilor unari.\n");
printf("Introduceti operandul:");
scanf("%d",&val);
printf("Introduceti operatorul:");
scanf(" %c",&oper);
switch(oper) {
case '!':
// Operatorul !
rez=!val;
printf("!%d = %d", val, rez);
break;
case '~':
// Operatorul ~
rez=~val;
printf("~%d = %d", val, rez);
break;
case '+':
// Operatorul ++

48

Bazele programrii calculatoarelor


temp=val; // pastram valoarea initiala
rez=++val;
printf("++%d = %d\n", temp, rez);
val=temp; // refacem valoarea initiala
rez=val++;
printf("%d++ = %d", temp, rez);
break;
case '-':
// Operatorul -temp=val; // pastram valoarea initiala
rez=--val;
printf("--%d = %d\n", temp, rez);
val=temp; // refacem valoarea initiala
rez=val--;
printf("%d-- = %d", temp, rez);
break;
case '&':
// Operatorul &
case '*':
// Operatorul *
pint=&val;
rez=*pint;
printf("Adresa variabilei este %p\n", pint);
printf("Valoarea de la adresa %p este %d",
pint, *pint);
break;
default:
printf("Operator necunoscut");
}
getch();
}

Cteva dintre rezultatele produse de acest program sunt:


Testarea operatorilor unari
Introduceti operandul: 21
Introduceti operatorul: !
!21 = 0
Testarea operatorilor unari
Introduceti operandul: 33
Introduceti operatorul: ~
~33 = -34
Testarea operatorilor unari
Introduceti operandul: 12
Introduceti operatorul: ++
++12 = 13
12++ = 13

49

Expresii. Operanzi. Operatori.


Testarea operatorilor unari
Introduceti operatorul: &
Introduceti operandul: 3
Adresa variabilei este FFF4
Continutul de la adresa FFF4 este 3

10. Programul urmtor exemplific funcionarea operatorilor


binari pe bii.
#include <stdio.h>
#include <conio.h>
int main()
{
int op1,op2,rez;
char oper;
printf("Testarea operatorilor pe biti.\n");
printf("Introduceti operandul 1:");
scanf("%d",&op1);
printf("Introduceti operandul 2:");
scanf("%d",&op2);
printf("Introduceti operatorul:");
scanf(" %c",&oper);
switch(oper)
{
case '<':
rez = op1<<op2;
printf("%d<<%d = %d", op1, op2, rez);
break;
case '>':
rez = op1>>op2;
printf("%d>>%d = %d", op1, op2, rez);
break;
case '&':
rez = op1&op2;
printf("%d&%d = %d", op1, op2, rez);
break;
case '|':
rez = op1|op2;
printf("%d|%d = %d", op1, op2, rez);
break;
case '^':
rez = op1^op2;
printf("%d^%d = %d", op1, op2, rez);
break;
default:

50

}
getch();

Bazele programrii calculatoarelor


printf("Operator necunoscut");

Cteva dintre rezultatele produse de acest program sunt:


Testarea operatorilor pe bii.
Introduceti operandul 1: 20
Introduceti operandul 2: 2
Introduceti operatorul: <<
20<<2 = 80
Introduceti operandul 1: 21
Introduceti operandul 2: 7
Introduceti operatorul: &
21&7 = 5

11. Programul urmtor prezint funcionarea operatorului ternar.


#include <stdio.h>
#include <conio.h>
int main()
{
int a, b;
printf("Testarea operatorului conditional.\n");
printf("Introduceti valoarea lui a:");
scanf("%d",&a);
printf("Introduceti valoarea lui b:");
scanf("%d",&b);
printf( a<b ? "%d e mai mic ca %d" : "%d e mai
mare ca %d", a, b);
getch();
}

Pentru a=3 i b=5, deoarece expresia a<b este adevrat


(deci nenul), formatul de afiare al funciei printf este "%d e
mai mic ca %d". n acest caz, rezultatul programului este:
Testarea operatorului conditional.
Introduceti valoarea lui a: 3
Introduceti valoarea lui b: 5
3 e mai mic ca 5

12. Programul urmtor exemplific funcionarea operatorilor de


atribuire compui.
51

Expresii. Operanzi. Operatori.


#include <stdio.h>
#include <conio.h>
int main()
{
int x = 5;
int n1 = 3, n2 = 2, n3 = 1, n4 = 4, n5 = 5;
printf("Initial, x = %d.\n", x);
printf("x+=%d este %d.\n", n1, x += n1);
printf("x-=%d este %d.\n", n2, x -= n2);
printf("x*=%d este %d.\n", n3, x *= n3);
printf("x /= %d este %d.\n", n4, x/=n4);
printf("x %%= %d este %d.\n", n5, x%=n5);
printf("In final, x este %d.\n", x);
getch();
}

Rezultatul execuiei acestui program este:


Valoarea
valoarea
Valoarea
Valoarea
Valoarea
Valoarea
Valoarea

initiala
lui x +=
lui x -=
lui x *=
lui x /=
lui x %=
finala a

a lui x este 5.
3 este 8.
2 este 6.
1 este 6.
4 este 1.
5 este 1.
lui x este 1.

13. Programul urmtor determin maximul a patru numere


folosind operatorul condiional. Dup citirea datelor, primul numr
este ales ca maxim. n continuare, valoarea variabilei max este
actualizat dac se gsete un numr mai mare dect ea.
#include <conio.h>
#include <stdio.h>
int main()
{
float x, y, z, t, max;
printf("Introduceti numerele:");
scanf("%f%f%f%f", &x, &y, &z, &t);
max = x;
max = max > y ? max : y;
max = max > z ? max : z;
max = max > t ? max : t;
printf("Maximul este %f", max);
getch();
}

52

Bazele programrii calculatoarelor

Rezultatul execuiei acestui program este:


Introduceti numerele:2 3 5 1
Maximul este 5.000000

14. Program urmtor calculeaz numrul total de secunde care


sunt egale cu h ore, m minute i s secunde (citite de la tastatur).
#include <conio.h>
#include <stdio.h>
int main()
{
int h, m, s, t;
printf("Introduceti timpul in format h:m:s: ");
scanf("%i:%i:%i", &h, &m, &s);
t = h * 3600 + m * 60 + s;
printf("Total secunde: %i", t);
getch();
}

Formatul "%i:%i:%i" determin funcia scanf s citeasc de


la tastatur valori ntregi separate prin dou puncte. Valorile
vor sunt memorate n variabilele h, m i s, iar caracterele
dou puncte sunt ignorate.
Rezultatul execuiei acestui program este:

Introduceti timpul in format h:m:s: 1:3:10


Total secunde: 3790

15. Sistemul RGB permite codificarea fiecrei culori printr-un


triplet de numere naturale care reprezint intensitile culorilor de
baz rou (Red), verde (Green) i albastru (Blue). Fiecare
component a tripletului poate avea valori din mulimea
0,1,,255 . Tripletul poate fi codificat ntr-un ntreg n baza 16,
cu valori din mulimea 0,1,, FFFFFF, primele dou cifre
hexazecimale reprezentnd intensitatea culorii rou, urmtoarele
dou cifre hexazecimale reprezentnd intensitatea culorii verde,
iar ultimele dou pentru albastru. Programul urmtor citete de la
tastatur un ntreg n format hexazecimal din mulimea
0,1,, FFFFFF i calculeaz i afieaz intensitile culorilor de
baz.
53

Expresii. Operanzi. Operatori.


// Codificare culori
#include "stdio.h"
#include "conio.h"
int main()
{
int cod,R,G,B;
printf(" Tastati codul de culoare in baza 16 ");
scanf("%x",&cod);
if(cod>=0 && cod<=0xffffff)
{
printf(" Ati tastat codul %x \n",cod);
B=cod%256;
G=(cod>>8)%256;
R=(cod>>16);
printf(" R = %d \n",R);
printf(" G = %d \n",G);
printf(" B = %d \n",B);
}
else
printf(" Cod invalid \n");
getch();
}

Rezultatul execuiei este:


Tastati codul de culoare in baza 16 ABCDEF
Ati tastat codul abcdef
R = 171
G = 205
B = 239

3.6. Exerciii
25. Scriei un program C care citete de la tastatur o
temperatur n grade Celsius i afieaz pe ecran temperatura n
grade Farenheit i Kelvin.
26. Scriei un program C care citete de la tastatur un numr
ntreg i determin dac acesta este divizibil cu 2, 3, 5, 10 i 100.
27. Scriei un program C care determin perimetrul i aria unui
dreptunghi cunoscnd lungimile laturilor.
28. Scriei un program C care determin consumul de
combustibil la o sut de kilometri al unui vehicul tiind consumul
total pe parcursul unei anumite distane.
54

Bazele programrii calculatoarelor

29. Scriei un program C care citete de la tastatur un numr


natural i afieaz cei mai puin semnificativi trei bii din
reprezentarea binar a numrului respectiv.
30. Scriei un program C care determin minimul a opt numere
reale citite de la tastatur (folosii ct mai puine comparaii).
31. Scriei un program C care funcioneaz ca un minicalculator:
utilizatorul introduce o valoarea, un operator aritmetic i apoi o
alt valoare, iar programul afieaz rezultatul operaiei aritmetice.
32. Scriei un program C care calculeaz numrul maxim de
ore, minute i secunde care sunt egale cu un numr n de
secunde (citit de la tastatur).
33. Scriei un program C care adun dou intervale de timp
exprimate n ore, minute i secunde. Rezultatul trebuie exprimat
tot n ore, minute i secunde. n plus, numrul de secunde i cel
de minute trebuie s fie cuprinse ntre 0 i 59.
34. Scriei un program C care afieaz valoarea funciei
f(x,y)=2,5x2 + 3xy + 1,2y2, pentru valori x i y citite de la tastatur
cu ajutorul funciei scanf.
35. Scriei un program C care calculeaz media ponderat a trei
numere naturale. Primul are pondere 20%, al doilea 30%, iar
ultimul 50%.

55

Instruciuni

44.. IINNSSTTRRUUCCIIUUNNII
Instruciunile unui program C determin operaiile pe care
acesta le efectueaz. O instruciune este format din cuvinte
cheie, expresii i/sau alte instruciuni. O instruciune care apare n
interiorul altei instruciuni formeaz corpul acesteia din urm.
O instruciune compus este un grup de zero sau mai
multe instruciuni incluse ntr-o pereche de acolade. Efectul
execuiei acesteia este acela al execuiei rnd pe rnd a
instruciunilor care o compun.
Cu excepia instruciunilor compuse, toate instruciunile
se termin prin punct i virgul. Instruciunea vid este o
instruciune care nu face nimic, fiind reprezentat de un singur
caracter punct i virgul. Ea se folosete n locurile unde este
necesar o instruciune, dar nu vrem s se efectueze nici o
operaie.

4.1. Instruciuni expresie


O instruciune expresie este o expresie compus din
operanzi i operatorii limbajului C (vezi capitolul 3). Efectul
execuiei acesteia este acela al evalurii expresiei care o
compune. Sintaxa instruciunii este urmtoare:
expresie;

4.2. Instruciuni de decizie


4.2.1. Instruciunea if
Instruciunea if permite condiionarea execuiei unei
instruciuni de valoarea de adevr a unei expresii. Sintaxa
instruciunii este urmtoare:
if (conditie)
instructiune1;
else
instructiune2;

56

Bazele programrii calculatoarelor

Ramura else i instruciune2 pot fi omise, obinndu-se


varianta scurt a instruciunii. Efectul instruciunii este urmtorul:
se evalueaz expresia conditie; dac valoarea acesteia este
diferit de zero, atunci se execut instruciune1, altfel se
execut instruciune2 (dac exist ramura else).
Instruciunile instruciune1 i instruciune2 pot fi la
rndul lor instruciuni if. n aceast situaie, compilatorul C
asociaz fiecare else cu cel mai recent if care nu are asociat un
else. Programatorul poate modifica acest comportament prin
folosirea acoladelor (instruciunea if fr else devine astfel o
instruciune compus). De exemplu, n secvena:
if(i>=0)
if(i<=10)
j = 1;
else
j = 2;

dac i este ntre 0 i 10, atunci valoarea variabilei j devine 1;


dac i este mai mare ca 10, atunci j devine 2; dac i este mai mic
dect 0, j nu se modific. n exemplul urmtor:
if(i>=0) {
if(i<=10)
j = 1;
} else
j = 2;

dac i este ntre 0 i 10, atunci valoarea variabilei j devine 1;


dac i este mai mare dect 10, valoarea variabilei j nu se
modific; dac i este mai mic dect 0, j devine 2.

4.2.2. Instruciunea switch


La fel ca if, Instruciunea switch permite condiionarea
execuiei unei instruciuni de valoarea unei expresii, executnd
automat testele de egalitate. Sintaxa instruciunii este urmtoare:
switch(expresie) {
case constanta1:
instructiune;
...
case constanta2:

57

Instruciuni
instructiune;
...

...
default:
instructiune;
...
...
case constantan:
instructiune;
...

Oricare variant case poate s nu conin instruciuni.


Varianta implicit (default) i instruciunile aferente acesteia pot
fi omise. Efectul instruciunii este urmtorul: se evalueaz
instruciunea expresie o singur dat. Valoarea acesteia se
compar pe rnd cu valorile constanta1, constanta2, ...,
constantan. Dac exist o valoare egal cu cea a expresiei, atunci
se execut instruciunile ncepnd de la acel caz pn la sfritul
instruciunii switch sau pn la prima instruciune break. Dac nu
exist nici o valoare egal, i exist cazul implicit se execut
instruciunile ncepnd de la acesta pn la sfritul instruciunii
switch sau pn la prima instruciune break. Dac nu exist nici o
valoare egal i nu exist cazul implicit, atunci nu se mai
ntmpl nimic.
De exemplu, n secvena urmtoare:
switch(i) {
case 0: j=1; break;
case 1:
case 2: j=2;
case 3: j=3; break;
default: j = 0;
}

dac i are valoarea 0, atunci valoarea lui j devine 1; dac i are


valoarea 1 sau 2, atunci valoarea lui j devine 2; dac i are
valoarea 3, atunci valoarea lui j devine 3, iar pentru alte valori ale
lui i, valoarea lui j devine 0.

58

Bazele programrii calculatoarelor

4.3. Instruciuni de ciclare


4.3.1. Instruciunea do-while
Instruciunea do-while permite execuia repetat a unei
instruciuni ct timp o expresie are valoare nenul (adic
adevrat). Sintaxa instruciunii este:
do
instructiune;
while(conditie);

Efectul instruciunii este urmtorul: se execut corpul lui


do-while (instruciunea instructiune) i apoi se evalueaz
expresia condiie. Dac valoarea acesteia este 0, atunci se
trece la urmtoarea instruciune, altfel se repet instruciunea dowhile curent. De remarcat c testul se execut la sfrit, deci
instructiune se execut mcar o dat.
n exemplul urmtor:
int i=3, j=1;
do
j=j+1;
while (i>j);

se executa instruciunea j=j+1 (deci j devine 2) i deoarece 3>2


(adic i>j) este adevrat se repet instruciunea do-while; se
executa instruciunea j=j+1 (deci j devine 3) i deoarece 3>3 este
fals, se termin instruciunea do-while.

4.3.2. Instruciunea while


Instruciunea while permite execuia repetat a unei
instruciuni ct timp o expresie are valoarea nenul (adic
adevrat). Sintaxa instruciunii este:
while(conditie)
instructiune;

Efectul instruciunii este urmtorul: se evalueaz expresia


condiie. Dac valoarea acesteia este 0, atunci se trece la
urmtoarea instruciune de dup while (nu se execut
instruciunea din corpul lui while), altfel se execut corpul lui
59

Instruciuni

while (instruciunea instructiune) i se repet instruciunea


while curent. De remarcat c testul se execut la nceput, deci
e posibil ca instructiune s nu se execute nici o dat.
n exemplul urmtor:
int i=3, j=1;
while (i>j)
j=j+1;

deoarece 3>1 (adic i>j) este adevrat, se executa instruciunea


j=j+1 (deci j devine 2) i se repet instruciunea while; deoarece
3>2 (adic i>j) este adevrat, se execut instruciunea j=j+1
(deci j devine 3) i se repet instruciunea while; deoarece 3>3
este fals, se termin instruciunea while.

4.3.3. Instruciunea for


Instruciunea for permite execuia repetat a unei
instruciuni ct timp o expresie are valoarea nenul (adic
adevrat). Sintaxa instruciunii este urmtoare:
for(initializare; conditie; actualizare)
instructiune;

Efectul instruciunii este urmtorul: se evalueaz expresia


initializare o singur dat. Se evalueaz expresia condiie.

Dac valoarea acesteia este 0, atunci se trece la urmtoarea


instruciune de dup for (nu se execut instruciunea din corpul
lui for), altfel se execut corpul lui for (instruciunea
instructiune), se evalueaz expresia actualizare i se
repet instruciunea for curent, dar fr expresia de iniializare.
De remarcat c expresia de iniializare se execut o
singur dat, iar apoi testul de repetare se execut la nceput,
deci e posibil ca instructiune i actualizare s nu se
execute nici o dat. Expresiile de iniializare, condiie i
actualizare sunt opionale, dar caracterele punct i virgul
trebuie scrise. Dac lipsete expresia conditie atunci valoarea
ei se consider nenul. O instruciune for poate fi rescris
folosind instruciunea while astfel:
initializare;
while(conditie) {

60

Bazele programrii calculatoarelor


instructiune;
actualizare;
}

n exemplul urmtor:
int i, j;
for(i = 1, j = 0; i <= 5; ++i)
j = j+i;

instruciunea for produce execuia instruciunii j=j+i de cinci ori,


cu valori diferite pentru i. Astfel, in final valoare lui j este 15 (adic
1+2+3+4+5).

4.4. Instruciuni de salt


4.4.1. Instruciunea break
Aa cum s-a vzut n seciunea 4.2.2, instruciunea break
poate fi folosit pentru a fora terminarea unei instruciuni switch.
De asemenea, instruciunea break poate fi folosit pentru a fora
terminarea instruciunilor de ciclare for, while i do-while. n acest
caz, execuia instruciunii break determin ntreruperea
instruciunii de ciclare curente i continuarea execuiei cu prima
instruciune dup aceasta.
n exemplul urmtor:
int i, j=0;
for(i = 1; i <= 5; ++i) {
if (i == 4)
break;
j = j+i;
}

instruciunea for produce (n mod normal) execuia instruciunii


j=j+i de cinci ori, cu valori diferite pentru i. Totui, cnd i ajunge
la valoarea 4, instruciunea if determin execuia instruciunii
break, terminndu-se astfel instruciunea for. Astfel, n final
valoare lui j este 6 (adic 1+2+3).

61

Instruciuni

4.4.2. Instruciunea continue


Instruciunea continue poate fi folosit pentru a fora
terminarea execuiei corpului instruciunii de ciclare. Cu toate
aceste, instruciunea de ciclare i continu execuia prin
evaluarea expresiei de actualizare (n cazul lui for) i a expresiei
condiie. n exemplul urmtor:
int i, j=0;
for(i = 1; i <= 5; ++i) {
if (i == 4)
continue;
j = j+i;
}

instruciunea for produce (n mod normal) execuia instruciunii


j=j+i de cinci ori, cu valori diferite pentru i. Totui, cnd i ajunge
la valoarea 4, instruciunea if determin execuia instruciunii
continue, terminndu-se astfel corpul instruciunii for.
Instruciunea for continu cu expresia de actualizare i cu iteraia
urmtoare. Astfel, in final valoare lui j este 11 (adic 1+2+3+5).

4.4.3. Instruciunea goto


Instruciunea goto determin transferul execuiei
programului la o anumit instruciune. Sintaxa instruciunii este
urmtoarea:
goto eticheta;

Efectul instruciunii este urmtorul: execuia programului


continu cu prima instruciune dup eticheta eticheta. n
general, se recomand a se evita folosirea instruciunii goto.
O etichet este un identificator unic (n interiorul funciei
n care este declarat) asociat unei instruciuni i care are
semnificaie doar pentru instruciunea goto. O etichet se scrie
naintea instruciunii pe care o denumete i este urmat de
caracterul dou puncte. De exemplu, n secvena urmtoare:
int i=3, j=2;
if (i < j)
goto maimic;
j = i;

62

Bazele programrii calculatoarelor


goto gata;
maimic: i = j;
gata:;

// aici este o eticheta


// aici este alta eticheta

dac i este mai mic dect j, atunci execuia continu de la


instruciunea cu eticheta maimic (adic cu i=j), altfel se execut
instruciunea j=i i se sare la instruciunea (vid) cu eticheta
gata.

4.5. Exemple
16. Urmtorul program determin soluia unei ecuaii de gradul
1 cu coeficieni reali, de forma ax+b = 0.
#include <stdio.h>
#include <conio.h>
int main()
{
float a, b;
printf("Introduceti a: ");
scanf("%f", &a);
printf("Introduceti b: ");
scanf("%f", &b);
if(a == 0)
if(b == 0)
printf("Orice numar real e solutie");
else
printf("Nu exista solutii reale");
else {
float x = -b/a;
printf("Solutie: %f", x);
}
getch();
}

Rezultatul rulrii pentru ecuaia 3x+8=0 este:


Introduceti a: 3
Introduceti b: 8
Solutie: -2.666667

17. Urmtorul program determin soluiile reale ale unei ecuaii


de gradul 2 cu coeficieni reali, de forma ax2+bx+c=0. Dac a
este nul, rezolvarea ecuaiei se reduce la rezolvarea unei ecuaii
63

Instruciuni

de gradul 1. Pentru a calcula rdcina ptrata a lui d vom folosi


funcia sqrt din biblioteca math.h.
#include <stdio.h>
#include <math.h>
#include <conio.h>
int main()
{
float a, b, c;
printf("Introduceti a: ");
scanf("%f", &a);
printf("Introduceti b: ");
scanf("%f", &b);
printf("Introduceti c: ");
scanf("%f", &c);
if(a == 0) {
if(b == 0)
if(c == 0)
printf("Orice numar real e solutie");
else
printf("Nu exista solutii reale");
else {
float x = -c/b;
printf("Solutie: %f", x);
}
} else {
float d = b*b-4*a*c;
if(d < 0)
printf("Ecuatia nu are solutii reale");
else {
float x1 = (-b-sqrt(d))/(2*a);
float x2 = (-b+sqrt(d))/(2*a);
printf("Solutii: %f si %f", x1, x2);
}
}
getch();
}

Rezultatul rulrii pentru ecuaia x2+3x+2=0 este:


Introduceti a: 1
Introduceti b: 3
Introduceti c: 2
Solutii: -2.000000 si -1.000000

64

Bazele programrii calculatoarelor

18. Urmtorul program calculeaz valoarea n! pentru n numr


natural dup formula n!=12...n.
#include <stdio.h>
#include <conio.h>
int main()
{
int i, n, nf;
printf("Valoarea lui n este : ");
scanf("%d",&n);
nf=1;
for(int i=1; i<=n; ++i)
nf *= i;
printf("%d! = %d\n",n, nf);
getch();
}

Rezultatul rulrii pentru n=6 este:


Valoarea lui n este : 6
6! = 720

19. Fiind dat un numr natural n nenul s se determine numrul


de zerouri cu care se termin n!.
//Numrul ultimelor zerouri ale lui n!
#include<stdio.h>
#include<conio.h>
int main ()
{int n,i,k;
long long nfact;
printf("n=");
scanf("%d", &n);
nfact=1;
for(i=1; i<=n; i++)
{nfact=nfact*i;}
printf(" %d! = %d se termina cu ",n,nfact);
k=0;
while(nfact%10==0)
{k++;
nfact=nfact/10;}
printf(" %d zerouri \n", k);
getch();}

Un exemplu de rulare este urmtorul:


n=11

65

Instruciuni
11! = 39916800 se termina cu

2 zerouri

20. Urmtorul program calculeaz S(n)=1!+2!+...+n!, pentru n


un numr natural. Prima variant, folosete directe formula lui S,
ceea ce nseamn c fiecare termen este calculat separat.
#include <stdio.h>
#include <conio.h>
int main()
{
int s, i, j, n, nf;
printf("Valoarea lui n este : ");
scanf("%d",&n);
s=0;
for(int i=1; i<=n; ++i) {
nf=1;
for(int j=1; j<=i; ++j)
nf *= j;
s = s + nf;
}
printf("S(%d) = %d\n", n, s);
getch();
}

21. O variant mai eficient pentru exemplu anterior obinem


dac observm c putem refolosi valorile calculate la pasul
anterior pentru a calcula valoarea curent.
#include <stdio.h>
#include <conio.h>
int main()
{
int s, i, n, nf;
printf("Valoarea lui n este : ");
scanf("%d",&n);
s=0;
nf=1;
for(int i=1; i<=n; ++i) {
nf *= i;
s = s + nf;
}
printf("S(%d) = %d\n", n, s);
getch();
}

n ambele cazuri, rezultatul rulrii pentru n=6 este:


66

Bazele programrii calculatoarelor


Valoarea lui n este : 6
S(6) = 873

22. Programul urmtor afieaz primii n termeni ai irului lui


Fibonacci, definit prin: fib : N N , fib 0 1 , fib 1 1 ,
fib n fib( n 1) fib n 2 ,

n 2 .

Pentru a-i calcula, vom


folosi urmtoarea metod: notm cu ti termenul la pasul i, cu ti+1
termenul urmtor i cu ti+2 termenul de dup acesta. Astfel, pentru
fiecare valoare a lui i, afim valoarea ti, calculm ti+2 i facem
trecerea de la i la i+1 (adic ti=ti+1 i ti+1=ti+2).
#include <stdio.h>
#include <conio.h>
int main()
{
int i, n, ti, ti_plus_1, ti_plus_2;
printf("Valoarea lui n este : ");
scanf("%d",&n);
ti=ti_plus_1=1;
for(int i=0; i<n; ++i) {
printf("Fib(%i) = %i\n", i, ti);
ti_plus_2 = ti_plus_1 + ti;
ti = ti_plus_1;
ti_plus_1 = ti_plus_2;
}
getch();
}

Rezultatul rulrii pentru n=7 este:


Valoarea
Fib(0) =
Fib(1) =
Fib(2) =
Fib(3) =
Fib(4) =
Fib(5) =
Fib(6) =

lui n este : 7
1
1
2
3
5
8
13

23. Fiind dat un numr natural n nenul, s se determine


descompunerea lui n n sum de termeni ai irului lui Fibonacci.
#include "stdio.h"

67

Instruciuni
#include "conio.h"
int main()
{
int n,x0,x1,xn,xn1,xn2,dif;
printf(" n = ");
scanf("%d",&n);
if(n>1)
{
x0=1;
x1=1;
dif=n;
while(dif>2)
{
xn=x0;
xn1=x1;
xn2=xn1+xn;
while(xn2<dif)
{
xn=xn1;
xn1=xn2;
xn2=xn1+xn;
}
printf(" %d ",xn1);
dif=dif-xn1;
}
if(dif==2) printf(" %d ",x1+x0);
else printf(" %d ",x0);
}else printf(" Valoarea introdusa nu este in domeniu
\n");
getch();
}

Un exemplu de rulare a programului este:


n = 27
21 5

24. Este cunoscut faptul c exist numere naturale care se pot


reprezenta ca suma a trei cuburi distincte. De exemplu
36 13 23 33 1 8 27 . Programul urmtor determin toate
numerele naturale din mulimea 1, 2, , k care au aceast
proprietate, k citit de la tastatur.
// Test suma de trei cuburi distincte

68

Bazele programrii calculatoarelor


#include "stdio.h"
#include "conio.h"
int main()
{
int k,n,c1,c2,c3,i,dif;
printf(" k = ");
scanf("%d",&k);
for(n=1;n<=k;n++)
{
i=1;
while(i*i*i<n)
{
c3=i*i*i;
i++;
}
dif=n-c3;
i=1;
while(i*i*i<dif)
{
c2=i*i*i;
i++;
}
dif=dif-c2;
if(dif!=1)
{
i=1;
while(i*i*i<=dif)
{
c1=i*i*i;
i++;
}
}
else
c1=1;
if(n==c1+c2+c3 && c1!=c2 && c1!=c3 && c2!=c3)
{
printf(" %d satisface proprietatea \n",n);
printf(" %d = %d + %d + %d \n",n,c1,c2,c3);
}
}
getch();
}

Un exemplu de rulare este:


k = 100

69

Instruciuni
36 satisface proprietatea
36 = 1 + 8 + 27
73 satisface proprietatea
73 = 1 + 8 + 64
92 satisface proprietatea
92 = 1 + 27 + 64
99 satisface proprietatea
99 = 8 + 27 + 64

25. Fie a i b dou numere neturale nenule. Determinarea


produsului celor do numere poate fi fcut cu algoritmul rusesc
de nmulire. Fie suma o variabil care, n final va memora
valoarea produsului a * b . Dac a este impar se face atribuirea
suma=suma+b. Dac a este par se mparte a la doi i se
nmulete b cu doi. Algoritmul continu ct timp a>=1. n final
variabila suma are valoarea egal cu cea a produsului a * b .
Programul urmtor codific algoritmul rusesc de nmulire.
// Produsul rusesc
#include "stdio.h"
#include "conio.h"
int main()
{
int a,b,sum,asalv,bsalv;
printf(" a = ");
scanf("%d",&a);
printf(" b = ");
scanf("%d",&b);
asalv=a;
bsalv=b;
printf(" a
b
produs \n");
sum=0;
while(a>=1)
{
printf(" %d
%d
%d \n",a,b,sum);
while(a%2==0)
{
a=a/2;
b=b*2;
}
sum=sum+b;
printf(" %d
%d
%d \n",a,b,sum);
a=a/2;
b=b*2;

70

Bazele programrii calculatoarelor


}
printf(" %d * %d = %d \n",asalv,bsalv,sum);
getch();
}

Rularea programului produce rezultatele:


a = 24
b = 25
a
b
24
25
3
200
1
400
1
400
24 * 25 = 600

produs
0
200
200
600

a = 93
b = 10
a
b
93
10
93
10
46
20
23
40
11
80
11
80
5
160
5
160
2
320
1
640
93 * 10 = 930

produs
0
10
10
50
50
130
130
290
290
930

26. Urmtorul program aproximeaz

numrul

folosind

1
. Valoarea aproximativ este afiat la
2
i 1 i
fiecare 1000 de pai i la ultimul pas.

formula n 6

#include <stdio.h>
#include <conio.h>
#include <math.h>
int main()
{
int n;
double s, p;
printf("Valoarea lui n este : ");
scanf("%d",&n);

71

Instruciuni
s = 0;
for(int i=1; i<=n; ++i) {
s += 1.0/(i*i);
if(i == n || i % 1000 == 1) {
p = sqrt(6*s);
printf("pi(%i) = %f\n", i, p);
}
}
getch();
}

Rezultatul rulrii pentru n=10000 este:


Valoarea lui n este : 10000
pi(1) = 2.449490
pi(1001) = 3.140639
pi(2001) = 3.141116
pi(3001) = 3.141274
pi(4001) = 3.141354
pi(5001) = 3.141402
pi(6001) = 3.141434
pi(7001) = 3.141456
pi(8001) = 3.141473
pi(9001) = 3.141487
pi(10000) = 3.141497

27. Urmtorul program calculeaz suma cifrelor unui numr


natural. Ct timp valoarea lui n este nenul, programul folosete
operatorul % pentru a obine ultima cifr i operatorul / pentru a
elimina aceast cifr din numr.
#include <stdio.h>
#include <conio.h>
int main()
{
int c, n, s;
printf("Valoarea
scanf("%d",&n);
s=0;
while (n>0) {
c = n%10; //
n = n/10; //
printf("Adun
c, n);
s += c;
}

72

lui n este : ");

restul impartirii
catul impartirii
%d la suma. A mai ramas %d\n",

Bazele programrii calculatoarelor


printf("Suma cifrelor este %d\n",s);
getch();
}

Pentru valoarea 12345 programul furnizeaz rezultatele:


Valoarea lui n este :
Adun 5 la suma. A mai
Adun 4 la suma. A mai
Adun 3 la suma. A mai
Adun 2 la suma. A mai
Adun 1 la suma. A mai
Suma cifrelor este 15

12345
ramas
ramas
ramas
ramas
ramas

1234
123
12
1
0

28. Urmtorul program determin rsturnatul unui numr


natural. n acest context, pentru n a1a2 ...ak , se numete
rsturnatul lui n numrul natural ak ak 1...a1 . De exemplu,
rsturnatul numrului 12345 este numrul 54321.
#include <stdio.h>
#include <conio.h>
int main()
{
int c, n, nr;
printf("Valoarea lui n este : ");
scanf("%d",&n);
nr=0;
while (n>0) {
c = n%10; // restul impartirii
n = n/10; // catul impartirii
printf("Adaug %d la numarul %d. A mai ramas
%d\n", c, nr, n);
nr = nr * 10 + c;
}
printf("Rasturnatul este %d\n", nr);
getch();
}

Pentru valoarea 12345 programul furnizeaz rezultatele:


Valoarea lui n este : 12345
Adaug 5 la numarul 0. A mai ramas 1234
Adaug 4 la numarul 5. A mai ramas 123
Adaug 3 la numarul 54. A mai ramas 12
Adaug 2 la numarul 543. A mai ramas 1
Adaug 1 la numarul 5432. A mai ramas 0

73

Instruciuni
Rasturnatul este 54321

29. Un numr natural p se numte palindrom dac este egal cu


rsturnatul su. Un numr natural p se numete superpalindrom
dac p i ptratul su sunt palindroame. Programul urmtor
determin i afieaz primele n superpalindroame.
//Superpalindroame
#include<conio.h>
#include<stdio.h>
int main()
{ int n,k,ipatrat,inou,
ipatratnou,isalv,ipsalv,ipal,ippal,i;
printf(" n =");
scanf( "%d", &n);
printf(" Primele %d superpalindroame \n\n",n);
k=0;
i=0;
while(k<n)
{
isalv=i;
inou=0;
while(i)
{
inou=inou+(i%10);
inou=inou*10;
i=i/10;
}
inou=inou/10;
if(isalv==inou) ipal=1;
else ipal=0;
ipatrat=isalv*isalv;
ipsalv=ipatrat;
ipatratnou=0;
while(ipatrat)
{
ipatratnou=ipatratnou+(ipatrat%10);
ipatratnou=ipatratnou*10;
ipatrat=ipatrat/10;
}
ipatratnou=ipatratnou/10;
if(ipsalv==ipatratnou) ippal=1;
else ippal=0;
if(ipal==1 && ippal==1)
{
printf(" %d %d\n", isalv, ipsalv);

74

Bazele programrii calculatoarelor


k++;
i=isalv+1;
}
else i=isalv+1;
}
getch();
}

Un rezultat al rulrii programului este:


n =11
Primele 11 superpalindroame
0 0
1 1
2 4
3 9
11 121
22 484
101 10201
111 12321
121 14641
202 40804
212 44944

30. Programul urmtor citete un numr ntreg n i folosind


instruciunea if, dac 1 n 7 , atunci afieaz numele zilei
corespunztoare din sptmn, altfel afieaz "Eroare".
#include <stdio.h>
#include <conio.h>
int main()
{
int n;
printf("Introduceti n:");
scanf("%i", &n);
if(n == 1) printf("Luni");
else if(n == 2) printf("Marti");
else if(n == 3) printf("Miercuri");
else if(n == 4) printf("Joi");
else if(n == 5) printf("Vineri");
else if(n == 6) printf("Sambata");
else if(n == 7) printf("Duminica");
else printf("Eroare");
getch();
}

75

Instruciuni

31. Relum exemplul anterior, folosind instruciunea switch.


#include <stdio.h>
#include <conio.h>
int main()
{
int n;
printf("Introduceti n:");
scanf("%i", &n);
switch(n)
{
case 1: printf("Luni"); break;
case 2: printf("Marti"); break;
case 3: printf("Miercuri"); break;
case 4: printf("Joi"); break;
case 5: printf("Vineri"); break;
case 6: printf("Sambata"); break;
case 7: printf("Duminica"); break;
default: printf("Eroare");
}
getch();
}

n ambele cazuri, programul furnizeaz rezultatul:


Introduceti n:6
Sambata

O variant mai simpl (i mai elegant) este prezentat n


capitolul 6. Aceasta folosete un vector de iruri de
caractere pentru a memora numele zilelor.

32. Programul urmtor calculeaz cel mai mare divizor comun a


dou numere folosind metoda cu scderi a lui Euclid.
#include <stdio.h>
#include <conio.h>
int main()
{
int m, n;
printf("Introduceti m si n:");
scanf("%i%i", &m, &n);
while(m != n)
if(m > n) m -= n;
else n-= m;
printf("cmmdc = %i", m);

76

Bazele programrii calculatoarelor


}

getch();

Programul furnizeaz urmtoarele rezultate:


Introduceti m si n:153 9
cmmdc = 9

4.6. Exerciii
36. Scriei un program C care calculeaz produsul cifrelor unui
numr natural.
37. Scriei un program C care determin dac un numr natural
n este prim sau compus.
38. Scriei un program C care determin divizorii unui un numr
natural n.
39. Scriei un program C care citete un numr natural n i dac
1 n 12 afieaz numele lunii a n-a, altfel afieaz "Eroare".
n!
40. Scriei un program C care calculeaz Ank
pentru n
(n k )!
i k numere naturale.
n!
41. Scriei un program C care calculeaz Cnk
pentru
k !(n k )!
n i k numere naturale.
42. Scriei un program C care calculeaz n k pentru n i k
numere naturale.
43. Scriei un program C care aproximeaz numrul e folosind
n
1
formula en pentru un numr natural n.
i 0 i !

77

Funcii standard de intrare/ieire

55.. FFUUNNCCIIII SSTTAANNDDAARRDD DDEE IINNTTRRAARREE//IIEEIIRREE


Dei limbajul C nu conine nici o instruciune pentru citirea
datelor (intrare) de la utilizator sau afiarea rezultatelor (ieire) pe
ecran, exist un numr mare de funcii standard pentru operaii
de intrare/ieire. Aceste funcii se gsesc n biblioteca stdio.h
(stdio este un acronim pentru standard input/output). Tot aici sunt
definite constantele EOF (End Of File) i NULL. Aceste valori sunt
returnate de diverse funcii cnd prelucrarea datelor s-a finalizat
(datorit terminrii datelor sau datorit unei erori).

5.1. Funcii pentru caractere


Funciile pentru caractere au o utilizare limitat, fiind
folosite pentru citirea i afiarea informaiei caracter cu caracter,
fr nici o prelucrare n prealabil.
Tabel 5.1 Funcii standard de intrare/ieire la nivel de caracter

Prototip

Descriere

int
Efect: afieaz caracterul cu codul
putchar
(int ASCII c pe ecran
c)
int
getchar()

Rezultat: valoarea c sau EOF n caz


de eroare
Efect: citete de la tastatur un
singur caracter
Rezultat: codul ASCII al caracterului
citit sau EOF dac s-au terminat datele sau a
aprut o eroare

Funcia getchar ateapt apsarea tastei Enter nainte de


a returna primul caracter introdus. La urmtoarele apeluri,
funcia returneaz restul caracterelor tastate nainte de
apsarea tastei Enter.

De exemplu, secvena urmtoare afieaz pe ecran


primul caracter introdus de utilizator de la tastatur:
int c;

78

Bazele programrii calculatoarelor


puts("Tastati un caracter si apasati Enter");
c = getchar();
putchar(c);

5.2. Funcii pentru iruri de caractere


Funciile pentru iruri de caractere permit citirea i
afiarea informaiei sub form de ir de caracter, fr alte
prelucrri.
Tabel 5.2 Funcii standard de intrare/ieire pentru iruri de caractere

Prototip

Descriere

int puts
Efect: afieaz pe ecran irul din
(char *s)
variabila s i trece pe linia urmtoare

Rezultat: un numr nenegativ n caz


de succes sau EOF n caz de eroare
char*
Efect: citete un ir de caractere de la
gets (char *s) tastatura pn la apsarea tastei Enter i l
pune n memorie la adresa s
Rezultat: adresa s a irului citit sau
NULL daca s-au terminat datele sau a aprut o
eroare
De exemplu, secvena urmtoare afieaz pe ecran un
mesaj introdus de utilizator de la tastatur:
char sir[80];
puts("Tastati un text si apasati Enter");
gets(sir);
puts("Ati tastat:");
puts(sir);

5.3. Funcii cu formatare


Funciile cu formatare permit citirea i afiarea informaiei
dup o prelucrare n prealabil a acesteia. Prelucrarea se
realizeaz conform unor coduri de format scrii de programator
ntr-un ir de caractere.

79

Funcii standard de intrare/ieire


Tabel 5.3 Funcii standard de intrare/ieire cu formatare

Prototi
p

Descriere

int
Efect: scrie pe ecran irul fmt n care
printf (char codurile de format sunt nlocuite cu valorile
*fmt, ...);

expresiilor marcate prin trei puncte;


Rezultat: numrul de caractere scrise
sau EOF n caz de eroare
int
Efect: citete de la tastatur date
scanf
(char conform irului fmt i le pune n memorie la
*fmt, ...);
adresele marcate prin trei puncte;
Rezultat: numrul de coduri de format
prelucrate corect sau EOF n caz de eroare
De exemplu, secvena urmtoare preia de la utilizator
valoarea variabilei n i afieaz un mesaj ce conine aceast
valoare.
int n;
printf("Introduceti n:");
scanf("%i", &n); // &n este adresa variabilei n
printf("Valoarea lui n este %i\n", n);

5.3.1. Codurile de format ale funciei printf


Primul parametru al funciei printf este un ir de
caractere alctuit din caractere normale, secvene escape i
coduri de format. Caracterele normale (exceptnd %) i
secvenele escape vor fi afiate pe ecran exact aa cum apar n
ir. n schimb, fiecare cod de format va fi nlocuit cu valoarea
parametrului corespunztor lui: primul cod de format folosete
valoarea celui de-al doilea parametru al funciei, al doilea cod de
format folosete valoarea celui de-al treilea argument al funciei,
.a.m.d. Un cod de format este alctuit (n ordine de la stnga la
dreapta) din:
caracterul %, care marcheaz nceputul codului de format
(dac vrem s afim un %, atunci trebuie scris %%);
un caracter de umplere (opional) conform cu Tabel 5.4;
80

Bazele programrii calculatoarelor

un caracter modificator (opional) pentru valori numerice


conform Tabel 5.5;
dimensiunea minim a cmpului (opional);
un punct urmat de precizia de afiare (opional);
un caracter pentru subtipul informaiei (opional) conform
cu Tabel 5.6;
un caracter pentru tipul informaiei conform cu Tabel 5.7.
Dimensiunea minim a cmpului determin numrul
minim de caractere care vor fi afiate (daca informaia ocup mai
puine caractere, atunci ea va fi completat conform caracterului
de umplere).
Precizia determin numrul de zecimale afiate n cazul
valorilor numerice reale, respectiv numrul maxim de caractere
afiate n cazul irurilor de caractere.
Dimensiunea i precizia pot fi numere zecimale pozitive
sau caracterul asterisc, caz n care acestea sunt furnizate n lista
parametrilor sub forma unui parametru ntreg.
Tabel 5.4 Caractere de umplere

C
Descriere
aracter
s
informaia este completat n partea stng cu
paiu
spaii (opiunea implicit)
0
informaia este completat n partea stng cu
(zero)
zerouri
informaia este completat n partea dreapt
(minus)
cu spaii
Tabel 5.5 Caractere modificatori pentru valori numerice

C
aracter
+

Descriere

pentru formatele i, d, u, e, E, f, g i G specific


afiarea semnului valorilor numerice pozitive (implicit,
semnul este afiat doar pentru valorile negative)
#
pentru formatul o specific afiarea prefixului
0
#
pentru formatele x i X specific afiarea
81

Funcii standard de intrare/ieire

prefixului 0x, respectiv 0X


pentru formatele e, E i f specific afiarea
punctului zecimal chiar i pentru numere fr zecimale
#
pentru formatele g i G specific afiarea
zerourilor nesemnificative de la sfritul numrului
#

Tabel 5.6 Caractere pentru subtip folosite n formatul funciei printf

C
aracter
h

Descriere

pentru formatele d, i, o, x i X specific


subtipul short int
h
pentru formatul u specific subtipul short
unsigned int

pentru formatele d, i, o, x i X specific

subtipul long int


pentru formatul u specific subtipul long
unsigned int

Tabel 5.7 Caractere pentru tip folosite n formatul funciei printf

C
aracter
d
i
u

Tip
parametru

int
int
unsi
gned int
unsi
o
gned int
unsi
x
gned int

X
f
e
E
g
82

unsi
gned int
doub
le
le
le
le

doub
doub
doub

Format ieire
numr ntreg scris n baza 10
numr ntreg scris n baza 10
numr ntreg scris n baza 10
numr ntreg scris n baza 8
numr ntreg scris n baza 16,
cu literele "abcdef"
numr ntreg scris n baza 16,
cu literele "ABCDEF"
numr real scris n baza 10
numr real scris n baza 10 cu
exponent "e"
numr real scris n baza 10 cu
exponent "E"
format e sau f (care este mai
scurt)

Bazele programrii calculatoarelor

G
c
s

le

doub

format E sau f (care este mai


scurt)

int
char

un caracter
un ir de caractere

void

un pointer (i.e. o adres de


memorie)
De exemplu, secvena urmtoare:
p

char ch = 'h', *str = "test";


int in = 12;
double db = 2.15;
printf("|%d|%+d|%4d|\n",in, in, in);
printf("|%04d|%0*d|\n", in, 9, in);
printf("|%X|%x|%#x|\n", in, in, in);
printf("|%o|%#o|\n", in, in);
printf("|%c|\n", ch);
printf("|%s|%6s|%-6s|%.2s|\n", str, str, str, str);
printf("|%f|%e|%g|\n", db, db, db);
printf("Adresa variabilei i este %p", &in);

produce urmtorul rezultat:


|12|+12| 12|
|0012|000000012|
|C|c|0xc|
|14|014|
|h|
|test| test|test |te|
|2.150000|2.150000e+000|2.15|
Adresa variabilei i este 0022FF6C

5.3.2. Codurile de format ale funciei scanf


Formatul funciei scanf este alctuit din caractere de
spaiere (vezi seciunea 2.1), caractere normale i coduri de
format. Caracterele de spaiere sunt citite, dar nu sunt memorate,
ele fiind interpretate ca separatori ntre datele de intrare.
Caracterele normale (exceptnd %) vor fi citite, dar nu vor fi
memorate. Dac se citete un caracter diferit de cel ateptat
atunci funcia se oprete din cititul datelor. n locul fiecrui cod,
funcia citete o valoare de intrare i o memoreaz la o adres
trimis funciei ca parametru: primul cod de format folosete
83

Funcii standard de intrare/ieire

adresa din al doilea argument al funciei, al doilea cod de format


folosete adresa din al treilea argument al funciei, .a.m.d. Un
cod de format este alctuit (n ordine de la stnga la dreapta) din:
caracterul %, care marcheaz nceputul codului de format
(dac vrem s citim un %, atunci trebuie scris %%);
un caracter asterisc (opional) care specific c informaia
va fi citit, dar nu va fi memorat;
dimensiunea maxim a cmpului (opional);
un caracter pentru subtipul informaiei (opional) conform
cu Tabel 5.8;
un caracter pentru tipul informaiei conform cu Tabel 5.9.
Dimensiunea maxim a cmpului definete numrul
maxim de caractere care vor fi citite (daca se ntlnete un
caracter de spaiere sau care intr n conflict cu formatul curent,
atunci citirea oprete).
n locul caracterului s (folosit pentru citirea unui ir de
caractere) se poate specifica un ir format numai din anumite
caractere scriind mulimea caracterelor permise ntre paranteze
ptrate. Dac primul caracter din mulime este sgeata n sus (^),
atunci va fi acceptat orice caracter care nu aparine mulimii.
Tabel 5.8 Caractere pentru subtip folosite n formatul funciei scanf

C
aracter
h

Descriere

pentru formatele d, i, n, o i x specific


subtipul short int
h
pentru formatul u specific subtipul short
unsigned int

l
l

pentru formatele d, i, n, o i x specific


subtipul long int
pentru formatul u specific subtipul long
unsigned int

84

pentru formatul f specific tipul double (n loc


de float)

Bazele programrii calculatoarelor


Tabel 5.9 Caractere pentru tip folosite n formatul funciei scanf

C
aracter
d

Tip
parametru

Format intrare

int*

numr ntreg scris n baza


10

long
int*

I
u

10
int*

long
int*
unsign
ed int*

unsign
ed long*
unsign
o
ed int*
unsign
O
ed long*
unsign
x
ed int*

X
f
, e, E, g,
G
c

numr ntreg scris n baza

unsign
ed long*
float*

numr ntreg scris n baza 8,


10 sau 16
numr ntreg scris n baza 8,
10 sau 16
numr ntreg fr semn
scris n baza 10
numr ntreg fr semn
scris n baza 10
numr ntreg scris n baza 8
numr ntreg scris n baza 8
numr ntreg scris n baza
16
numr ntreg scris n baza
16
numr real scris n baza 10
cu sau fr exponent

char*

un
caracter
(inclusiv
caractere de spaiere)
char*
s
un ir de caractere
int*
n
nimic
(la
adresa
din
parametru va fi memorat numrul de
caractere citite pn n prezent)
void**
p
un pointer (rar folosit)
De exemplu, secvena urmtoare:

char ch, str[30];


int in;
float fl;

85

Funcii standard de intrare/ieire


double db;
printf("Introduceti date: ");
scanf("%i%f%lf%s%c", &in, &fl, &db, str, &ch);
printf("Valori: %i %f %f %s %c", in,fl,db,str,ch);

produce rezultatul de mai jos. De remarcat c n cazul variabilei


str nu s-a folosit operatorul & (deoarece str este un vector de
caractere), iar codul %s a oprit citirea datelor la primul spaiu,
urmtorul caracter fiind preluat de codul %c.
Introduceti date: 5 4.23 3.2 test program
5 4.230000 3.200000 test p

5.4. Funcii cu formatare pentru iruri de caractere


Funcia sprintf funcioneaz similar cu funcia printf,
cu excepia c scrierea datelor se va face ntr-un ir de caractere
i nu pe ecran. n mod similar, funcia sscanf funcioneaz ca
funcia scanf, cu excepia c citirea datelor se va face dintr-un ir
de caractere i nu de la tastatur.
Tabel 5.10 Funcii standard cu formatare pentru iruri de caractere

Prototip

Descriere

int
Efect: scrie n irul dest irul fmt n
sprintf (char* care codurile de format sunt nlocuite cu
dest,
char
valorile expresiilor marcate prin trei puncte;
*fmt, ...);

Rezultat: numrul de caractere scrise


sau EOF n caz de eroare
int
Efect: citete din irul srs date
sscanf
(char* conform irului fmt i le pune n memorie la
srs,
char
adresele marcate prin trei puncte;
*fmt, ...);
Rezultat: numrul de coduri de
format prelucrate corect sau EOF n caz de
eroare

5.5. Exemple
33. Programul urmtor citete de la tastatur caracter cu
caracter i afieaz pe ecran doar literele. Programul se oprete
la citirea primului caracter punct.
86

Bazele programrii calculatoarelor


#include <stdio.h>
#include <conio.h>
int main()
{
int car;
puts("Introduceti textul:");
do {
car = getchar();
if(car >= 'A' && car <= 'Z' ||
car >= 'a' && car <= 'z')
putchar(car);
}while(car != EOF && car != '.');
getch();
}
Introduceti textul:
Limbajul C are 32 de instructiuni. Asta e bine.
LimbajulCaredeinstructiuni

34. Programul urmtor citete de la tastatur linie cu linie i


afieaz pe ecran liniile dup ce majusculele au fost transformate
n minuscule (folosind funcia strlwr, descris n capitolul 9).
Programul se oprete la citirea primei linii care ncepe cu un
punct.
#include <stdio.h>
#include <conio.h>
#include <string.h>
int main()
{
char mesaj[150];
puts("Introduceti textul:");
while(gets(mesaj) && mesaj[0] != '.') {
strlwr(mesaj);
puts(mesaj);
}
getch();
}
Introduceti textul:
Limbajul C are doar 32 de instructiuni.
limbajul c are doar 32 de instructiuni.
Asta e bine!
asta e bine!
.gata

87

Funcii standard de intrare/ieire

35. Programul urmtor afieaz tabla nmulirii.


#include <stdio.h>
#include <conio.h>
int main()
{
int l,c;
for(l = 1; l<= 10; ++l) {
for(c = 1; c <= 10; ++ c)
printf("%5d", l*c);
printf("\n");
}
getch();
}

Rezultatul execuiei este urmtorul:


1
2
3
4
5
6
7
8
9
10

2
4
6
8
10
12
14
16
18
20

3
6
9
12
15
18
21
24
27
30

4
8
12
16
20
24
28
32
36
40

5
10
15
20
25
30
35
40
45
50

6
12
18
24
30
36
42
48
54
60

7
14
21
28
35
42
49
56
63
70

8
16
24
32
40
48
56
64
72
80

9 10
18 20
27 30
36 40
45 50
54 60
63 70
72 80
81 90
90 100

36. Programul urmtor afieaz tabela codurilor ASCII.


Programul listeaz pe fiecare linie, n ordine cresctoare coduri
ASCII n baza 10, 8 i 16, i caracterul asociat acestora. Dup
22 de linii, execuia se suspend pn la apsarea unei tastei.
Rezultatul execuiei acestui program este similar cu tabelul din
Anexa 2 Setul de caractere ASCII.
#include <stdio.h>
#include <conio.h>
int main()
{
int i;
puts("Cod 10\tCod 8\tCod 16\tCaracter");
for(i=0;i<=255;i++)
{
printf("%3i\t%#4o\t%#4X\t%c\n", i, i, i, i);
if(i % 22 == 21) {
getch();

88

Caracter");
}
}
}

Bazele programrii calculatoarelor


puts("Cod 10\tCod 8\tCod 16\t

37. Programul urmtor afieaz o tabel de coresponden


pentru temperaturi n grade Celsius, Farenheit i Kelvin.
#include <stdio.h>
#include <conio.h>
int main()
{
float c, k, f;
puts("Celsius\tKelvin\tFarenheit");
for(c=-30;c<=30;c+=10)
{
f = 32 + 9*c/5;
k = c - 273.15;
printf("%g\t%g\t%g\n", c, k, f);
}
getch();
}

Rezultatul programului este urmtorul:


Celsius
-30
-20
-10
0
10
20
30

Kelvin
-303.15
-293.15
-283.15
-273.15
-263.15
-253.15
-243.15

Farenheit
-22
-4
14
32
50
68
86

5.6. Exerciii
44. Scriei un program C care afieaz valorile polinomului
p( x) 2,1x2 3,5x 8, 2 pentru toate valorile [n, n p, n 2 p,..., m] ,
unde n, p i m sunt numere reale citite de la tastatur.
45. Scriei un program C care citete un ntreg zecimal de cel
mult 5 cifre de la tastatura i l afieaz ncadrat de 2 caractere %
astfel: n octal, pe 10 poziii, aliniat la dreapta, i n hexazecimal,
pe 15 poziii i aliniat la stnga.
89

Funcii standard de intrare/ieire

46. Scriei un program C care citete dou numere


hexazecimale separate prin virgul i afieaz suma lor n baza 8
i 10, separate prin dou puncte.
47. Scriei un program care citete de la tastatur un numr
natural n i un ir de caractere s i afieaz doar primele n
caractere din s.
48. Scriei un program C care citete un caracter de la tastatur
folosind funcia scanf i afieaz codul su ASCII n baza 8 i 10.
49. Scriei un program C care afieaz reprezentarea n baza 2
a unui numr ntre n, citit de la tastatur.
50. Scriei un program C care citete de la tastatur un numr
ntreg n ntre 2 i 8 i afieaz pe ecran un desen cu o linie de
lungime n, astfel:
|T'T'T'T'T'T'T'T'T'T'T'T'T'T'T'T'T'T'T'T'T'T'T'T'T|
||
'
|
'
|
'
|
'
|
'
|
'
||
|0
1
2
3
4
5
6|
!_________________________________________________!

90

Bazele programrii calculatoarelor

66.. TTIIPPUURRII DDEE DDAATTEE CCO


OM
MP
PU
US
SE
E
6.1. Masive
Masivele de date sunt tablouri de date de acelai tip,
standard sau definit de utilizator, dispuse contiguu n memorie.
Un astfel de tablou poate avea mai multe dimensiuni. Numrul
dimensiunilor tabloului este limitat doar de memoria calculatorului
pe care ruleaz programul care folosete masive de date.
Masivul care are o singur dimensiune se numete vector sau ir.
Masivul care are dou dimensiuni se numete matrice. Un masiv
cu k dimensiuni se declar astfel:
tip nume[dim1][dim2][dimk]

unde: tip este tipul datelor din masiv, nume este numele
masivului, iar dim1, dim2, ..., dimk sunt expresii constante a cror
valori reprezint numrul de componente pentru fiecare
dimensiune.
De exemplu, urmtoarea secven de program declar
vectorul v cu 20 de elemente de tip ntreg, matricea mat cu 5x5
elemente de tip caracter i masivul tridimensional masiv cu 3x4x3
elemente de tip real.
int v[20];
char mat[5][5];
float masiv[3][4][2];

Numrul total de elemente ale unui masiv cu k dimensiuni


este egal cu dim1*dim2*...*dimk, iar pentru memorarea unui masiv
cu
tipul
tip
i
k
dimensiuni
sunt
necesari
sizeof(tip)*dim1*dim2*...*dimk octei. Accesarea unui element al
masivului se face cu construcia nume[i1][i2][in], unde i1, i2, , in
sunt coordonatele elementului pe fiecare dintre dimensiuni (0 ij
< dimj, 1jk).
Masivele pot fi iniializate la declarare astfel:
tip nume[dim1][dim2]...[dimk]={v1, v2, ..., vn};

91

Tipuri de date compuse

valorile v1, v2, ..., vn, fiind stocate n masiv n ordine de la


coordonatele mici (0,0,..., 0) la coordonatele mari (dim1-1, dim21,..., dimk-1).

Pentru a fora completarea valorilor n anumite locaii ale


masivului, acestea trebuie grupate ntre acolade astfel:

tip nume[dim1][dim2]...[dimk]={{v1,...,vp}, {vp+1,...},


{...,vn}};

Dimensiunea cea mai important (dim1) poate s lipseasc,


ea fiind determinat automat din numrul valorilor de
iniializare, astfel:

tip nume[][dim2]...[dimk]= {v1, v2, ..., vn};

Dac numrul de valori folosite la iniializare depete


numrul de elemente din masiv atunci compilatorul genereaz un
mesaj de eroare. Dac numrul de valori folosite la iniializare
este mai mic dect numrul de elemente din masiv, atunci restul
valorilor sunt iniializate cu 0.
De exemplu, prin declaraia
int v[4]={-1,2,4,0};

sunt iniializate componentele vectorului cu identificatorul vector


cu valori ntregi astfel: v[0]=-1, v[1]=2, v[2]=4. Echivalent, se
poate folosi declaraia:
int v[]={-1,2,4,0};

sau
int v[4]={-1,2,4};

6.2. Structuri
Spre deosebire de masive, care grupeaz sub un singur
nume, date de acelai tip, structura este un tip nou de dat care
grupeaz date de tipuri diferite. Un element al unei structuri se
numete membru sau cmp al structurii. Un membru al unei
structuri poate fi folosit fie ca un singur tip de dat, fie ca o dat
individual. Fiecare membru al unei structuri are un tip predefinit
92

Bazele programrii calculatoarelor

sau definit de utilizator, n particular putnd fi tot o structur. O


structur se declar cu ajutorul cuvntului cheie struct, astfel:
struct tipstructura {
tip1 memebru1;
tip2 memebru2;
...
tipn memebrun;
};

Prin aceast declaraie este definit un ablon, un tip nou


de dat cu numele tipstructura care are n membri, fiecare
membrui avnd tipul tipi. n particular, tipi poate fi de o
structur, caz n care se spune c structurile cu tipurile
tipstructura i tipi sunt imbricate.
La compilare dup o astfel de declaraie nu se rezerv
memorie deoarece este declarat un tip de dat. Declararea unor
variabile de tipul tipstructura se poate face ca pentru orice tip
predefinit, astfel:
tipstructura variabila1, variabila2,, variabilak;

Efectul obinut prin declaraiile de mai sus se poate obine


cu declaraia:
struct tipstructura {
tip1 memebru1;
tip2 memebru2;
...
tipn memebrun;
} variabila1, variabila2,, variabilak;

Dac tipstructura este absent, se spune c a fost


definit o structur anonim. n acest caz, cel puin o variabil
trebuie s fie prezent.
Accesarea membrului membrui al variabilei variabilap
se face cu ajutorul operatorului de selecie direct . astfel:
variabilap.memebrui = valoare;
variabila = variabilap.memebrui;

De exemplu, declaraiile urmtoare:


struct student {
char nume[20];

93

Tipuri de date compuse


char prenume[20];
int nota;
};

declar tipul de dat student care are urmtorii membri: vectorii


de caractere nume i prenume, i variabila de tip ntreg nota.
Declaraia:
student studenti[25];

declar vectorul studenti cu 25 de elemente de tip student.


Expresia studenti[i].nota face referire la membrul nota al
componentei de rang i a vectorului studenti.
Declaraiile urmtoare:
struct grupastudiu {
char disciplina[50];
student studenti[25];
};
grupastudiu anstudiu[5];

definesc tipul structur grupastudiu i vectorul anstudiu cu 5


de componente de tipul grupastudiu. Expresia:
anstudiu[2].studenti[3].nota = 10;

atribuie valoarea 10 notei celui de-al patrulea student din a treia


grupa din anul de studiu.
Structurile se pot iniializa la declarare asemntor cu
iniializarea masivelor. De exemplu, instruciunea urmtoare:
student std={Ionescu,Dan,9};

declar i iniializeaz variabila std corespunztoare studentului


Ionescu Dan, care are nota 9.
La asignarea unei variabile de tip structur, se realizeaz
o copie a structurii surs n variabila destinaie. De asemenea,
structurile pot fi folosite ca parametri pentru funcii. n cazul n
care tipul unui parametru este o structur, la apelul funciei se
creeaz o copie a structurii care va fi folosit de funcie. Dac
parametrul este un pointer la o structur, funcia are acces direct
la zona de memorie a structurii folosind operatorul ->.

94

Bazele programrii calculatoarelor


De exemplu, funcia afiseaza primete ca parametru un
pointer la o structur student i afieaz informaii despre

studentul respectiv:
void afiseaza(struct student *p) {
printf("%s %s %d\n", p->nume, p->prenume, p>nota);
}

n acest caz, referirea la cmpurile structurii se realizeaz


cu ajutorul operatorului de selecie indirect -> prin construcia
p->nota, sau cu construcia (*p).nota. Apelul funciei se
realizeaz astfel:
f(&std);
f(&anstudiu[2].studenti[3]);

6.3. Uniuni
Uniunile ofer utilizatorului posibilitatea refolosirii
aceleiai zone de memorie pentru a memora date de tipuri diferite
la momente diferite de timp. Astfel, o zon de memorie poate
memora date de tip int, pentru ca ulterior aceeai zon s
memoreze date de tip float, ceea ce nu are loc n cazul
structurilor. Scopul acestor reutilizri ale memoriei este
economisirea acesteia.
Uniunile se declar i se folosesc la fel ca structurile,
deosebirea constnd n nlocuirea cuvntului cheie struct cu
cuvntul cheie union. n cazul structurilor se rezerv pentru
fiecare membru cte o zon de memorie de dimensiune
corespunztoare. n cazul uniunilor se rezerv o singur zon de
memorie, de dimensiune egal cu valoarea maxim a
dimensiunilor necesare membrilor si. n cazul uniunilor
utilizatorul trebuie s monitorizeze tipurile de date aflate n
memorie, n fiecare moment al execuiei programului.
n declaraia:
union anstudiu {
char cod;
int numar;
} an;

95

Tipuri de date compuse

este declarat tipul de dat anstudiu de tip uniune i variabila an


de acest tip.

6.4. Cmpuri
Un cmp este un ir de bii definit ca membru al unei
structuri. Un cmp se declar ca un membru de tip unsigned,
numele fiind urmat de un ntreg care precizeaz dimensiunea n
bii a cmpului respectiv. n memorie cmpurile sunt grupate, n
ordinea declarrii lor, de la dreapta spre stnga. Forma general
de declarare a unor cmpuri este:
struct tipstructura {
...
unsigned camp1:dim1;
unsigned camp2:dim2;
...
} identificator;

n care campi este numele cmpului i care ocup dimi bii. Nici
un cmp nu poate avea o dimensiune mai mare dect lungimea
unui cuvnt calculator (32 bii). Nu se pot defini masive de
cmpuri. Operatorul unar adres & nu poate avea ca operand un
cmp.
Prin declaraia:
struct {
unsigned bitii01:2;
unsigned bitii25:4;
unsigned bitii68:3;
} campuri;

este definit structura cmpuri cu cmpurile de bii bitii01 (2


bii), bitii25 (4 bii) i bitii68 (3 bii).

6.5. Exemple
38. Programul urmtor citete un numr ntreg n i dac
1 n 7 , atunci afieaz numele zilei corespunztoare din
sptmn, altfel afieaz "Eroare".
#include <stdio.h>
#include <conio.h>

96

Bazele programrii calculatoarelor


int main()
{
int n;
char *zile[] = {"Eroare", "Luni", "Marti",
"Miercuri", "Joi", "Vineri", "Sambata", "Duminica"};
printf("Introduceti n:");
scanf("%i", &n);
if(n>=1 && n<=7)
printf(zile[n]);
else
printf(zile[0]);
getch();
}

39. Urmtorul program determin valoarea minim i poziia sa


ntr-un vector de numere reale:
#include <stdio.h>
#include <conio.h>
int main()
{
int i,n,pmin;
float v[100];
printf("Introduceti numarul de termeni:");
scanf("%d",&n);
printf("Introduceti componentele:\n");
for(i=0; i<n; i++) {
printf("v[%d]=", i);
scanf("%f",&v[i]);
}
for(pmin=0,i=1; i<n; i++)
if(v[pmin]>v[i])
pmin = i;
printf("Minimul este v[%d]=%f\n", pmin,
v[pmin]);
getch();
}

Rularea programului genereaz urmtoarele rezultate:


Introduceti numarul de termeni: 5
Introduceti componentele:
v[0]= 23.1
v[1]= -2.3
v[2]= 4.5
v[3]= -11.2
v[4]= 9.8

97

Tipuri de date compuse


Minimul este v[3] = -11.200000

40. Urmtorul program determin suma componentelor unui


vector de numere ntregi:
#include <stdio.h>
#include <conio.h>
int main()
{
int i,n,suma;
int v[100];
printf("Introduceti numarul de termeni:");
scanf("%d",&n);
printf("Introduceti componentele:\n");
for(i=0; i<n; i++) {
printf("v[%d]=", i);
scanf("%d",&v[i]);
}
for(suma=0, i=0; i<n; i++)
suma += v[i];
printf("Suma este %d\n", suma);
getch();
}

Rularea programului genereaz urmtoarele rezultate:


Introduceti numarul de termeni: 5
Introduceti componentele:
v[0]= 23
v[1]= -20
v[2]= 4
v[3]= -11
v[4]= 9
Suma este 5

41. n programul urmtor se citete un numr natural


n N * , n 99 i vectorii a a0 , a1 , , an 1 , b b0 , b1 , , bn 1 ,
fiecare cu n componente numere reale i se genereaz vectorul
c bn 1 , bn 2 , , b0 , a0 , a1 , , an 1 .
// Generare vector
#include "stdio.h"
#include "conio.h"
int main()
{

98

Bazele programrii calculatoarelor


float a[100],b[100],c[100];
int i,j,n;
printf(" Numar componente ");
scanf("%d",&n);
if(n>0 && n<=99)
{
printf(" Componentele vectorului a \n");
for(i=0;i<n;i++)
{
printf(" a[%d] = ",i);
scanf("%f",&a[i]);
}
printf(" Componentele vectorului b \n");
for(i=0;i<n;i++)
{
printf(" b[%d] = ",i);
scanf("%f",&b[i]);
}
for(i=n-1;i>=0;i--)
c[n-i-1]=b[i];
for(i=0;i<n;i++)
c[n+i]=a[i];
printf(" Vectorul c = ( ");
for(i=0;i<2*n;i++)
printf(" %f ",c[i]);
printf(" )\n");
}
else
printf(" %d nu este in domeniu \n",n);
getch();
}

Un exemplu de rulare este:


Numar componente 2
Componentele vectorului a
a[0] = 1
a[1] = 2
Componentele vectorului b
b[0] = 3
b[1] = 4
Vectorul c = ( 4.000000 3.000000
2.000000 )

1.000000

99

Tipuri de date compuse

42. Programul urmtor citete un caracter, un ir de caractere i


determin numrul de apariii (dac exist) ale caracterului citit n
ir.
// Frecventa caracterului c dintr-un vector de
caractere
#include "stdio.h"
#include "conio.h"
int main()
{
int n=0,i=0;
char s[50],c;
puts(" Sirul ");
gets(s);
puts(" Caracterul ");
scanf("%c",&c);
while(s[i]!='\0')
{
if(s[i]==c) n++;
i++;
}
if(n==0) printf(" Sirul %s nu contine caracterul %c
\n",s,c);
else
printf(" Numarul de caractere %c din sirul %s este
egal cu %d \n",c,s,n);
getch();
}

Un exemplu de rulare este:


Sirul
frecventa caracter in sir
Caracterul
#
Sirul frecventa caracter in sir nu contine
caracterul #
Sirul
frecventa caracter in sir
Caracterul
e
Numarul de caractere e din sirul frecventa caracter
in sir este egal cu 3

100

Bazele programrii calculatoarelor

43. Urmtorul program determin numrul de cuvinte dintr-un


ir de caractere. Un cuvnt este irul de caractere cuprins ntre
unul din urmtorii separatori: spaiu, virgul, punct virgul.
//Numar de cuvinte separate de spatiu ' ', virgula
',', punct si virgula ';'
#include "stdio.h"
#include "conio.h"
int main()
{
char sir[100];
int nc,i;
puts(" Sirul :");
gets(sir);
i=0;
if(sir[i]==' ' || sir[i]==',' || sir[i]==';')
nc=-1;
else nc=0;
while(sir[i]!='\0')
{
if(sir[i]==' ' || sir[i]==',' || sir[i]==';')
{
nc++;
i++;
while(sir[i]==' ' || sir[i]==',' || sir[i]==';')
i++;
}
i++;
}
nc++;
printf(" Numar cuvinte %d \n",nc);
getch();
}

Un exemplu de rulare este:


Sirul :
numar; de , cuvinte;;; din , sir
Numar cuvinte 5

44. Urmtorul program determin i sorteaz descresctor


frecvenele de apariie ale tuturor caracterelor dintr-un ir de
caractere.
101

Tipuri de date compuse


// Frecventele sortate descrescator ale caracterelor
dintr-un sir
#include "stdio.h"
#include "conio.h"
int main()
{
char sir[100],c[100],smartor[100],auxc;
int nap[100],i,j,k,ncardist,auxi;
puts(" Sirul : ");
gets(sir);
for(i=0;sir[i]!='\0';i++)
smartor[i]=sir[i];
i=0;
while(sir[i]!='\0')
{
nap[i]=1;
c[i]=sir[i];
j=i+1;
while(sir[j]!='\0')
{
if(sir[i]==sir[j])
{
for(k=j;sir[k]!='\0';k++)
sir[k]=sir[k+1];
sir[k]='\0';
nap[i]++;
}
else
j++;
}
i++;
}
ncardist=i;
printf(" Frecventele nesortate ale caracterelor\n\n
In sirul %s \n",smartor);
for(k=0;k<ncardist;k++)
printf(" Caracterul %c apare de %d ori
\n",c[k],nap[k]);
getch();
printf(" Frecventele sortate descrescator ale
caracterelor\n\n In sirul %s \n",smartor);
for(i=0;i<ncardist;i++)
for(j=i+1;j<ncardist;j++)
if(nap[i]<=nap[j])
{
auxc=c[i];

102

Bazele programrii calculatoarelor


c[i]=c[j];
c[j]=auxc;
auxi=nap[i];
nap[i]=nap[j];
nap[j]=auxi;
}
for(k=0;k<ncardist;k++)
printf(" Caracterul %c apare de %d ori
\n",c[k],nap[k]);
getch();
}

Un exemplu de rulare este:


Sirul :
determinarea frecventelor
Frecventele nesortate ale caracterelor
In sirul determinarea frecventelor
Caracterul d apare de 1 ori
Caracterul e apare de 6 ori
Caracterul t apare de 2 ori
Caracterul r apare de 4 ori
Caracterul m apare de 1 ori
Caracterul i apare de 1 ori
Caracterul n apare de 2 ori
Caracterul a apare de 2 ori
Caracterul
apare de 1 ori
Caracterul f apare de 1 ori
Caracterul c apare de 1 ori
Caracterul v apare de 1 ori
Caracterul l apare de 1 ori
Caracterul o apare de 1 ori
Frecventele sortate descrescator ale caracterelor
In sirul determinarea
Caracterul e apare de
Caracterul r apare de
Caracterul a apare de
Caracterul n apare de
Caracterul t apare de
Caracterul o apare de
Caracterul l apare de
Caracterul v apare de
Caracterul c apare de
Caracterul f apare de

frecventelor
6 ori
4 ori
2 ori
2 ori
2 ori
1 ori
1 ori
1 ori
1 ori
1 ori

103

Tipuri de date compuse


Caracterul
apare
Caracterul i apare
Caracterul m apare
Caracterul d apare

de
de
de
de

1
1
1
1

ori
ori
ori
ori

45. Urmtorul program determin rdcinile ntregi ale


polinoamelor cu coeficieni ntregi. Fie P Z X , gradP n N * ,
P X an X n an1 X n1

a1 X a0 ,

ai Z ,

i 0,1,..., n ,

an 0 . Este cunoscut faptul c rdcinile ntregi ale polinomului,


dac exist, se gsesc printre divizorii termenului liber a0 .
Programul are ca date de intrare gradul n i coeficienii a0 , a1 ,..., an
ai polinomului i ca date de ieire rdcinile sale ntregi. Se
determin toi divizorii termenului liber i pentru fiecare din ei se
calculeaz valoarea polinomului. Dac aceast valoare este nul,
atunci divizorul respectiv este rdcin ntreag a polinomului.
#include <stdio.h>
#include <conio.h>
int main()
{
int coef[10], i, j, n, m;
printf("Gradul polinomului:");
scanf("%d", &n);
for (i=0; i<=n; ++i) {
printf("Coeficientul %d: ", i);
scanf("%d", &coef[i]);
}
m = coef[0]<0 ? -coef[0] : coef[0];
for (i=-m; i<=m; ++i)
if(i==0 || m%i == 0) {
long valoare = 0, putere = 1;
for(j = 0; j<=n; ++j) {
valoare += coef[j] * putere;
putere *= i;
}
if(valoare == 0)
printf("%d este radacina\n", i);
}
getch();
}

104

Bazele programrii calculatoarelor

Pentru P X X 6 X 11X 6 , care are rdcinile


3

ntregi x1 1 , x2 2 i x3 3 , programul furnizeaz rezultatele:


Gradul polinomului:3
Coeficientul 0: -6
Coeficientul 1: 11
Coeficientul 2: -6
Coeficientul 3: 1
1 este radacina
2 este radacina
3 este radacina

Pentru

P X X 3 2X 2 X 2 ,

care are rdcinile

ntregi x1 1 , x2 1 i x3 2 , programul furnizeaz rezultatele:


Gradul polinomului:3
Coeficientul 0: 2
Coeficientul 1: -1
Coeficientul 2: -2
Coeficientul 3: 1
-1 este radacina
1 este radacina
2 este radacina

46. Urmtorul program sorteaz cresctor componentele unui


vector de numere reale prin metoda bulelor:
#include <stdio.h>
#include <conio.h>
int main()
{
int i,j,n,pmin;
float v[100], aux;
printf("Introduceti numarul de termeni:");
scanf("%d",&n);
printf("Introduceti componentele:\n");
for(i=0; i<n; i++) {
printf("v[%d]=",i);
scanf("%f",&v[i]);
}
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
if(v[i]>v[j]) {
aux=v[i];

105

Tipuri de date compuse


v[i]=v[j];
v[j]=aux;
}
printf("Vectorul sortat crescator este:\n");
for(i=0;i<n;i++)
printf("a[%d] = %f\n",i,v[i]);
getch();
}

Rularea programului genereaz urmtoarele rezultate:


Introduceti numarul de termeni: 5
Introduceti componentele:
v[0]= 23.1
v[1]= -2.3
v[2]= 4.5
v[3]= -11.2
v[4]= 9.8
Sirul sortat crescator este :
v[0] = -11.200000
v[1] = -2.300000
v[2] = 4.500000
v[3] = 9.800000
v[4] = 23.100000

47. Urmtorul program calculeaz produsul a dou matrice de


numere reale:
#include <stdio.h>
#include <conio.h>
int main()
{
float a[20][20],b[20][20],c[20][20];
int m,n,p,q,i,j,k;
printf("Numarul de linii al matricei A:");
scanf("%d",&m);
printf("Numarul de coloane al matricei A:");
scanf("%d",&n);
printf("Numarul de linii al matricei B:");
scanf("%d",&p);
printf("Numarul de coloane al matricei B:");
scanf("%d",&q);
if(n==p) {
printf("Se calculeaza produsul A*B\n");
for(i=0;i<m;i++)
for(j=0;j<n;j++) {
printf("a[%d][%d]=",i,j);

106

Bazele programrii calculatoarelor


scanf("%f",&a[i][j]);

}
for(i=0;i<p;i++)
for(j=0;j<q;j++) {
printf("b[%d][%d]=",i,j);
scanf("%f",&b[i][j]);
}
for(i=0;i<m;i++)
for(j=0;j<q;j++) {
c[i][j]=0;
for(k=0;k<n;k++)
c[i][j] += a[i][k]*b[k][j];

printf("c[%d][%d]=%f\n",i,j,c[i][j]);
}
} else {
printf("Produsul A*B nu este definit\n");
}
getch();

1 1 2
1 2
De exemplu, fie matricele A
i B
.
2 0 1
3 4
1 2 1 1 2 5 1 4
Produsul este A B


.
3 4 2 0 1 11 3 10
Numarul de linii a matricei A: 2
Numarul de coloane a matricei A: 2
Numarul de linii a matricei B: 2
Numarul de coloane a matricei B: 3
Se calculeaza produsul A*B
a[0][0] = 1
a[0][1] = 2
a[1][0] = 3
a[1][1] = 4
b[0][0] = -1
b[0][1] = 1
b[0][2] = 2
b[1][0] = -2
b[1][1] = 0
b[1][2] = 1
c[0][0]= -5.000000
c[0][1]= 1.000000
c[0][2]= 4.000000

107

Tipuri de date compuse


c[1][0]= -11.000000
c[1][1]= 3.000000
c[1][2]= 10.000000

48. Urmtorul program reprezint un dicionar romn-englezfrancez "de jucrie". Programul folosete funcii pentru iruri de
caractere descrise n capitolul 9.
#include <stdio.h>
#include <string.h>
#include <conio.h>
char* cuvinte[][3] = {
"masa", "table", "table",
"scaun", "chair", "chaise",
"mancare", "food", "nourriture",
"apa", "water", "eau",
"om", "human", "humain",
NULL, NULL, NULL
};
int main(void)
{
char cuv_rom[80];
int i;
printf("Introduceti cuvantul romana:");
gets(cuv_rom);
/* cautam cuvantul in dictionar */
for(i = 0; cuvinte[i][0] != NULL; ++i)
if(!strcmp(cuv_rom, cuvinte[i][0])) {
printf("Engleza: %s\nFranceza: %s\n",
cuvinte[i][1], cuvinte[i][2]);
break;
}
if(cuvinte[i][0] == NULL)
printf("Cuvant necunoscut.\n");
getch();
}

49. Relum exemplul dicionarului, dar de aceast dat


cuvintele sunt memorate n variabile de tip structur.
#include <stdio.h>
#include <string.h>
#include <conio.h>
struct cuvant {

108

Bazele programrii calculatoarelor


char *romana, *engleza, *franceza;
} cuvinte[] = {
{"masa", "table", "table"},
{"scaun", "chair", "chaise"},
{"mancare", "food", "nourriture"},
{"apa", "water", "eau"},
{"om", "human", "humain"},
NULL, NULL, NULL
};
int main(void)
{
char cuv_rom[80];
int i;
printf("Introduceti cuvantul romana:");
gets(cuv_rom);
/* cautam cuvantul in dictionar */
for(i = 0; cuvinte[i].romana != NULL; ++i)
if(!strcmp(cuv_rom, cuvinte[i].romana)) {
printf("Engleza: %s\nFranceza: %s\n",
cuvinte[i].engleza, cuvinte[i].franceza);
break;
}
if(cuvinte[i].romana == NULL)
printf("Cuvant necunoscut.\n");
getch();
}

50. Exemplu urmtor citete informaiile unei grupe de studeni,


le sorteaz descresctor dup not i afieaz rezultatele.
#include <stdio.h>
#include <conio.h>
int main()
{
struct student {
char nume[20];
char prenume[20];
int nota;
} student[25], aux;
int i,j,n;
printf("Numar studenti:");
scanf("%d",&n);
for(i=0;i<n;i++) {
printf("Nume si prenume student %d:", i+1);

109

Tipuri de date compuse


scanf("%s%s",student[i].nume,
student[i].prenume);
printf("Nota studentului %s %s:",
student[i].nume, student[i].prenume);
scanf("%d",&student[i].nota);
}
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
if(student[i].nota < student[j].nota) {
aux=student[i];
student[i]=student[j];
student[j]=aux;
}
printf("Rezultatele grupei:\n");
for(i=0;i<n;i++)
printf("%s %s\t%d\n", student[i].nume,
student[i].prenume, student[i].nota);
getch();
}

Rularea programului furnizeaz urmtoarele rezultate:


Numar studenti 5
Nume si prenume student 1 Ion Dan
Nota studentului Ion Dan 8
Nume si prenume student 2 Ilie Victor
Nota studentului Ilie Victor 7
Nume si prenume student 3 Ionescu Vlad
Nota studentului Ionescu Vlad 6
Nume si prenume student 4 Popescu Ion
Nota studentului Popescu Ion 9
Nume si prenume student 5 Dima Florin
Nota studentului Dima Florin 10
Rezultatele grupei:
Ionescu Vlad
6
Ilie Victor
7
Ion Dan
8
Popescu Ion
9
Dima Florin
10

51. Presupunem c dorim s prelucrm o mulime de puncte din


plan. Despre fiecare punct ne intereseaz numele i coordonatele
acestuia. n final afim distanele dintre oricare dou puncte.
110

Bazele programrii calculatoarelor

Vom defini o structur de date care reprezint informaiile despre


un punct din plan.
#include <stdio.h>
#include <math.h>
#include <conio.h>
struct Punct {
float x;
// coordonata x
float y;
// coordonata y
char nume[20]; // numele
};
int main()
{
struct Punct pt[10];// maxim 10 de puncte
int i, j, n; // numarul real de puncte
printf("Numarul de puncte: ");
scanf("%d", &n);
for(i = 0; i<n; ++i) {
printf("Punctul %d.\n", i);
printf("\tNume: ");
scanf("%s", pt[i].nume);
printf("\tCoordonata pe axa Ox: ");
scanf("%d", &pt[i].x);
printf("\tCoordonata pe axa Oy: ");
scanf("%d", &pt[i].y);
}
for(i=0; i<n; ++i)
for(j=0; j<n; ++j)
printf("Distanta de la %s la %s este
%f.\n", pt[i].nume, pt[j].nume, sqrt(pt[i].x*pt[j].x
+ pt[i].y*pt[j].y));
getch();
}

6.6. Exerciii
51. Scriei un program C care afieaz suma elementelor pare
i produsul elementelor impare dintr-un vector de numere reale.
52. Scriei un program C care afieaz poziia primei apariii a
unui numr m ntr-un vector de numere reale.
53. Scriei un program C care afieaz produsul scalar a doi
vectori de numere reale.
54. Scriei un program C care afieaz suma a doi vectori de
numere reale.
111

Tipuri de date compuse

55. Scriei un program C care afieaz suma a dou matrice de


numere reale.
56. Scriei un program C care citete un numr natural
n N * , n 99 i vectorii a a0 , a1 , , an 1 , b b0 , b1 , , bn 1 ,
fiecare cu n componente numere reale i se genereaz vectorul
c b0 , b1 , , bn 1 , a0 , a1 , , an 1 .
57. Scriei un program C care citete un numr natural
n N * , n 99 i vectorii a a0 , a1 , , an 1 , b b0 , b1 , , bn 1 ,
fiecare cu n componente numere reale i se genereaz vectorul
c b0 , a0 , b1 , a1 , , bn 1 , an 1 .
58. Scriei un program C care simuleaz evoluia unei populaii
de virui. Aceti se afl n anumite noduri ale unei reele cu
dimensiune n x n. Un virus triete dac are 2 sau 3 vecini, altfel
moare (sufocat sau de singurtate). ntr-un nod liber cu 2 sau 3
vecini, se nate un virus.
59. Scriei un program C care gestioneaz un vector cu
informaii despre un angajat. Informaiile trebuie memorate ntr-o
structur. Programul trebuie s permit adugarea i tergerea
de elemente din vector.

112

Bazele programrii calculatoarelor

77.. FFUUNNCCIIII
Pentru scrierea unor programe de complexitate cel puin
medie, exist posibilitatea organizrii unor date i a unor aciuni
asupra lor, ntr-o entitate independent, numit funcie. Limbajul
C pune la dispoziia utilizatorului diverse funcii predefinite,
numite funcii standard. Utilizatorul poate s defineasc i s
utilizeze propriile sale funcii, numite funcii utilizator.
Exist o funcie standard, principal, funcia main(),
apelat de sistemul de operare la nceputul execuiei oricrui
program. Funciile apelate pot comunica cu funciile apelante prin
intermediul parametrilor.

7.1. Declararea i definirea funciilor


Pentru a fi utilizat ntr-un program C, o funcie trebuie
nti declarat (i ulterior definit). O funcie se declar pentru ca
tipul ei, precum i tipul i numrul argumentelor sale s fie
cunoscute n vederea utilizrii ei viitoare de ctre alte funcii. O
funcie se definete specificnd tipul i numele ei, tipul i numele
argumentelor sale, precum i corpul funciei (compus din
declaraii i instruciuni).

Argumentele unei funcii precizate la definirea ei se numesc


parametri formali, n timp ce argumentele precizate la apelul
ei se numesc parametri actuali.
Sintaxa declaraiei unei funcii este:

tip identificator(lista parametri formali)


{
declaraii i instruciuni
}

unde
tip identificator(lista parametri formali)

se numete antet al funciei, iar restul reprezint corpul funciei.


Elementul tip reprezint tipul valorii ntoarse prin apelul funciei,
113

Funcii
iar identificator este numele funciei. Pentru funciile care nu
returneaz nici o valoare, tipul funciei este void. Pentru fiecare
parametru din lista parametri formali trebuie specificat tipul

i numele. Lista parametrilor formali poate s fie i vid, caz n


care poate fi nlocuit cu cuvntul void.
Corpul funciei se execut pn la executarea ultimei
instruciuni sau pn la executarea instruciunii return. Dac
funcia returneaz o valoare atunci se folosete forma
return expresie;

a instruciunii return. Prin executarea acestei instruciuni se


evalueaz expresia, se atribuie funciei valoarea expresiei i se
ncheie execuia funciei. Tipul expresiei din instruciunea return
trebuie s fie compatibil cu tipul funciei. Dac funcia nu
returneaz valori, instruciunea return poate s lipseasc sau se
folosete forma
return;

n limbajul C nu este admis definirea unei funcii n cadrul


altei funcii i nu snt permise salturi cu instruciunea goto n
afara funciei.

Dac un parametru formal este un masiv, acesta poate fi


declarat fr a indica valoarea maxim a primei dimensiuni.
Valorile maxime ale celorlalte dimensiuni trebuie scrise.
Urmtoarele prototipuri conin parametrul formal vector care este
un masiv unidimensional (vector):
int f(int vector[]);
int f(int vector[50]);

Prototipuri de mai jos conin parametrul formal masiv


care este un masiv tridimensional:
int f(int masiv[][50][50]);
int f(int masiv[50][50][50]);

7.1.1. Prototipul funciilor


O funcie poate fi folosit nainte de a fi definit dac ea a
fost declarat. Declararea se realizeaz prin scrierea antetului
114

Bazele programrii calculatoarelor

funciei urmat de caracterul ';' (construcie denumit prototip),


astfel:
tip identificator(lista parametri formali);

Prototipul unei funcii informeaz compilatorul despre tipul


valorii pe care o va returna funcia i despre tipurile tuturor
parametrilor. Numele parametrilor pot lipsi, fiind suficient
specificarea tipurilor lor. Prototipul trebuie inserat n program
naintea primului apel al funciei. De exemplu, urmtoarele
prototipuri sunt identice i corecte:
int functie(int param1, float param2, char param3);
int functie(int, float, char);

7.1.2. Transferul parametrilor


Parametrii funciilor se pot transmite prin valoare, prin
referin i prin intermediul variabilelor globale. La transmiterea
parametrilor prin valoare, valorile din funcia apelant sunt
copiate n parametrii actuali ai funciei, i nu pot fi modificate de
ctre funcia apelat deoarece aceasta lucreaz cu copii ale lor.
n cazul transmiterii parametrilor prin referin (sau prin
pointeri) funcia apelant furnizeaz funciei apelate adresa zonei
de memorie unde sunt pstrate datele. Funcia apelat poate
modifica aceste date accesnd direct zona respectiv de
memorie.
O alt metode de transfer al parametrilor este
transmiterea acestora prin variabile globale. Aceast metod se
bazeaz pe faptul c variabilele globale sunt accesibile din orice
funcie.

7.2. Apelul funciilor


Apelul unei funcii se face prin scrierea numelui acesteia
urmat de parametrii actuali ai funciei scrii ntre paranteze
rotunde i separai prin virgule. Parametrii actuali trebuie s
corespund cu cei formali prin ordine, tip i numr. O funcie se
poate apela recursiv din alt funcie sau direct, chiar din interiorul
ei.
115

Funcii

Dac funcia nu are parametri, ntre paranteze nu se scrie


nimic. Valoarea ntoars de funcie particip la evaluarea valorii
finale a expresiei n care apare.
Utilizarea unei funcii din bibliotec impune includerea
fiierului asociat, cu directiva #include:
#include numebiblioteca.h

sau
#include <numebiblioteca.h>

De exemplu, secvena:
int f(int x)
{
return x-1;
}

declar o funcie care are identificatorul f, un parametru formal


de tip ntreg x, i care returneaz o valoare de tip ntreg.
Instruciunea return x-1; ntoarce ca valoare a funciei
valoarea lui x minus 1, deci apelul f(5) va returna valoarea 4.
Transmiterea parametrului este fcut prin valoare. De exemplu:
#include <stdio.h>
#include <conio.h>
int f(int x)
{
return x-1;
}
int main()
{
int x;
printf("Valoarea lui x = ");
scanf("%d",&x);
printf("f (%d) = %d \n",x,f(x));
getch();
}

Rularea programului conduce la rezultatele:


Valoarea lui x = 5
f (5) = 4

116

Bazele programrii calculatoarelor

7.3. Transmiterea parametrilor


n limbajul C exist dou posibiliti de transfer a datelor
ntre funcia apelant i cea apelat: prin parametri i prin
variabile globale. Prin utilizarea variabilelor globale nu se face un
transfer propriu-zis, ci se folosesc n comun anumite zone de
memorie partajat ntre toate funciile din program.

7.3.1. Transferul prin parametri


n limbajul C transferul prin parametri se poate realiza
prin valoare i prin referin. n acest transferului prin valoare,
valoarea parametrului este copiat, iar funcia apelat lucreaz
cu aceast copie. Deci operaiile efectuate asupra unui parametru
formal transmis prin valoare (adic orice parametru care are tip
fundamental), nu modific, la ieirea din funcie, parametrul
actual corespunztor. n plus, transferul valorii este nsoit de
eventuale conversii de tip, realizate pe baza informaiilor despre
funcie de care dispune compilatorul. n concluzie, parametrii
transmii prin valoare se pot modifica n corpul funciei, dar dup
terminarea apelului funciei apelate n funcia apelant acetia au
aceleai valori pe care le-au avut naintea apelului. Din acest
motiv, transferul prin valoare este folosit pentru transmiterea
datelor de intrare.
Exemplu urmtor prezint o funcie de calcul a sumei
primelor n numere naturale. Parametrul n este transmis prin
valoare. Funcia suma are un singur parametru, k, de tip int,
care este parametru de intrare. Funcia returneaz valoarea
sumei prin numele su.
#include <stdio.h>
#include <conio.h>
int suma(int k) // parametrul transmis prin valoare
{
int s = 0,i;
for(i=1;i<=k;i++)
s+=i;
return s;
}
int main()
{

117

Funcii
int n;
printf(" Valoarea lui n = ");
scanf("%d",&n);
printf("Suma primelor %d numere naturale este
%d\n", n, suma(n));
getch();
}

Pentru n=10 programul furnizeaz valoarea 55.


Valoarea lui n = 10
Suma primelor 10 numere naturale este 55

Folosind transferul prin valoare se pot transmite funciei


numai parametri de intrare. Pentru a transmite parametri de ieire
se folosete transferul prin referin (adic prin pointeri), adic se
transmit funciei adrese de variabile. Pointerii sunt subiectul
capitolului 8, dar, pe scurt, antetul unei funcii care folosete
transferul de parametri de tip referin este (observai folosirea
caracterului asterisc nainte de numele variabilei):
tip identificator(, tip *variabila,)

Parametrii transmii prin referin se pot modifica n


corpul funciei, iar dup terminarea apelului funciei acetia au
valorile primite n timpul execuiei funciei apelate. n acest caz,
funcia primete ca parametru adresa zonei de memorie unde se
gsesc datele i poate s le actualizeaz pe acestea modificnd
coninutul zonei de memorie.
Relum exemplul anterior. Acum, funcia suma are un
parametru formal de intrare k i un parametru formal de ieire s,
care este un pointer la tipul int.
#include <stdio.h>
#include <conio.h>
// Parametrul n se transmite prin valoare
// Parametrul s se transmite prin adresa
int suma(int k,int *s)
{
int sum = 0,i;
for(i=1;i<=k;i++)
sum+=i;
*s=sum;
}

118

Bazele programrii calculatoarelor


int main()
{
int n,sum;
printf("Valoarea lui n = ");
scanf("%d",&n);
// Apelul functiei
suma(n,&sum); // &sum inseamna adresa lui sum
printf("Suma primelor %d numere naturale este
%d\n", n, sum);
getch();
}

Programul urmtor citete valorile unor variabile a i b i


apeleaz funcia tipar. Aceasta primete prin referin
variabilele a i b, modific valorile de la adresele lor i tiprete
noile valori. Dup apelul funciei tipar, n funcia main se
tipresc din nou valorile celor dou variabile.
#include <stdio.h>
#include <conio.h>
void tipar(int *a, int *b)
{
*a=*a+3;
*b=*b+4;
printf("In tipar:\n");
printf("a = %d \n b = %d \n",*a,*b);
}
int main()
{
int a,b;
printf("Valoarea lui a : ");
scanf("%d",&a);
printf("Valoarea lui b : ");
scanf("%d",&b);
tipar(&a,&b);
printf("Valorile dupa apelul functiei sunt:\n");
printf("a = %d \n b = %d \n",a,b);
getch();
}

Ce anume se ntmpl la execuia programului pentru


a=5 i b=7? Funcia main apeleaz funcia tipar avnd ca
parametri actuali adresele variabilelor a i b. La adresa variabilei
a este memorat valoarea 5, iar la adresa variabilei b este
memorat valoarea 7. Funcia tipar adun valoarea 3 la
119

Funcii

coninutul de la adresa lui a i valoarea 4 la coninutul de la


adresa lui b, astfel nct noile valori ale lui a i b sunt respectiv 8
i 11. Aceste valori se pstreaz dup apelul funciei tipar.
Valoarea lui a : 5
Valoarea lui b : 7
In tipar:
a = 8
b = 11
Valorile dupa apelul functiei sunt:
a = 8
b = 11

Pentru parametrii de tip masiv de date, transferul prin


referin se face n mod implicit, deoarece numele masivului este
pointer ctre zona de memorie unde este stocat masivul. Astfel
urmtoarele prototipuri snt echivalente:
tip identificator1(int masiv[]);
tip identificator2(int *masiv);

Urmtorul exemplu prezint o funcie pentru calculul


sumei componentelor unui vector. Funcia suma are doi parametri
de intrare. Citirea vectorului se realizeaz cu funcia citvector.
Parametrul vector este transferat prin referin deoarece este un
masiv de ntregi.
#include <stdio.h>
#include <conio.h>
void citvector(int k,int vector[])
{
int i;
for(i=0;i<k;i++)
{
printf("v [ %d ] = ",i);
scanf("%d",&vector[i]);
}
}
int suma(int k,int vector[])
{
int s = 0,i;
for(i=0; i<k; i++)
s+=vector[i];
return s;
}

120

Bazele programrii calculatoarelor


int main()
{
int n,v[100],i;
printf("Numar de componente n = ");
scanf("%d",&n);
citvector(n, v);
printf("Suma componentelor este: %d\n",
suma(n,v));
getch();
}

Rezultatul execuiei programului este:


Numar de componente n = 3
v [ 0 ] = 11
v [ 1 ] = 22
v [ 2 ] = 33
Suma componentelor este: 66

7.3.2. Transferul prin variabile globale


Variabilele globale se declar n afara funciilor, inclusiv
n afara funciei main() i pot fi referite din orice alte funcii,
inclusiv din funcia main(). Astfel, transferul de parametri ntre
funcia apelant i cea apelat se poate face i prin variabile
globale.
Pentru exemplificare, relum unul dintre exemplele
anterioare. Parametrii de intrare ai funciei suma sunt declarai ca
variabile globale. Funcia suma are lista parametrilor formali vid.
#include <stdio.h>
#include <conio.h>
int n, vector[100]; // variabile globale
void citvector()
{
int i;
for(i=0;i<n;i++) {
printf(" v [ %d ] = ",i);
scanf("%d", &vector[i]);
}
}
int suma()
{
int s = 0,i;
for(i=0;i<n;i++)

121

Funcii
s+=vector[i];
return s;
}
int main()
{
int i;
printf(" Numar de componente n = ");
scanf("%d",&n);
citvector();
printf("Suma componentelor este: %d\n",suma());
getch();
}

Cele dou metode de transmitere a parametrilor (prin


variabile globale i prin parametri) pot fi folosite mpreun. De
exemplu, declarm numai vectorul vector variabil global.
Funcia suma are un singur parametru formal k.
#include <stdio.h>
#include <conio.h>
// Declararea variabilei globale vector
int vector[100];
void citvector(int k)
{
int i;
for(i=0;i<k;i++) {
printf(" v [ %d ] = ",i);
scanf("%d", &vector[i]);
}
}
int suma(int k)
{
int s = 0,i;
for(i=0;i<k;i++)
s+=vector[i];
return s;
}
int main()
{
int n;
printf(" Numar de componente n = ");
scanf("%d",&n);
citvector(n);
printf("Suma componentelor: %d\n", suma(n));
getch();
}

122

Bazele programrii calculatoarelor

7.4. Recursivitate
Recursivitatea este o tehnic de programare frecvent
utilizat n implementarea funciilor. Tehnica recursivitii const
n autoapelul funciei (de ctre ea nsi), n mod direct sau
indirect. Tehnica poate fi folosit n cazul problemelor cu natur
recursiv i simplific scrierea programelor prin scrierea direct a
formulelor recursive.
Definiia unui proces recursiv trebuie s satisfac condiia
de consisten, adic s se termine ntr-un numr finit de pai.
Un exemplu de funcie inconsistent este urmtorul: fie
1
n0

funcia f : N N N , f n
, n N . De
n

f
n

1
altfel

exemplu, f 2 2 f 3 2 3 f 4 ... , ceea ce arat c acest

proces recursiv nu este finit.


Un exemplu de funcie consistent este urmtorul: fie
1
n0

funcia f : N N , f n
, n N . Evident:
n f n 1 altfel
f (3) 3 f 2 3 2 f 1 3 2 1 f 0 3 2 1 1 3! 6 , ceea ce

arat c acest proces recursiv este finit.


La baza recursivitii st o zon de memorie organizat
ca o stiv. La fiecare apel al funciei se salveaz automat n stiv
valorile variabilelor din funcie i adresele de revenire (adresa
urmtoarei instruciuni care urmeaz a fi executat dup apelul).
Acest lucru simplific programarea, dar implic un consum
suplimentar de timp i memorie datorit operaiilor cu stiva.
Recursivitatea este de dou tipuri: direct i indirect. O
funcie recursiv se numete direct recursiv, dac n definiia ei
exist cel puin un autoapel al ei. O funcie recursiv se numete
indirect recursiv dac, se autoapeleaz prin intermediul unei alte
funcii, care i ea se autoapeleaz prin intermediul primei funcii.
n cazul recursivitii indirecte, funciile care se
autoapeleaz indirect trebuie fcute cunoscute compilatorului prin
prototipurile lor, scrise naintea definiiilor lor. Urmtoarele
programe ilustreaz cele dou tipuri de recursivitate.
123

Funcii

De exemplu, funcia factorial recursiv


anterior, poate fi implementat n limbajul C astfel:

prezentat

long factorial (unsigned int n) {


if(n==0)
return 1;
else
return n*factorial(n-1);
}

7.5. Exemple
52. Programul urmtor prezint o funcie pentru determinarea
celui mai mare divizor comun a dou numere naturale cu
algoritmul lui Euclid i un program care testeaz aceast funcie.
n program se definete funcia euclid de tip ntreg care are
parametrii formali p i q de tip ntreg. Funcia returneaz valoarea
cmmdc(p,q). Apelul funciei cu parametrii actuali m i n,
euclid(m,n) determin calculul cmmdc(m,n).
#include <stdio.h>
#include <conio.h>
int euclid(int p, int q)
{
int r;
while(r=p%q) {
p=q;
q=r;
}
return q;
}
int main()
{
int m,n;
printf("Valoarea lui m = ");
scanf("%d",&m);
printf("Valoarea lui n = ");
scanf("%d",&n);
printf("cmmdc(%d,%d) = %d \n", m, n,
euclid(m,n));
getch();
}

Pentru m=48 i n=18 programul afieaz:


124

Bazele programrii calculatoarelor


Valoarea lui m = 48
Valoarea lui n = 18
cmmdc(48,18) = 6

53. Exemplul urmtor prezint folosirea prototipului funciei


euclid pentru declararea acesteia nainte de a fi definit. n
program este scris mai nti prototipul funciei euclid, iar funcia
este definit abia dup definiia funciei main().
#include <stdio.h>
#include <conio.h>
int euclid(int, int); //
int main()
{
int m,n;
printf("Valoarea lui
scanf("%d",&m);
printf("Valoarea lui
scanf("%d",&n);
printf("cmmdc(%d,%d)
euclid(m,n));
getch();
}
int euclid(int p, int q)
{
int r;
while(r=p%q) {
p=q;
q=r;
}
return q;
}

Prototipul functiei

m = ");
n = ");
= %d \n", m, n,

// Definitia functiei

54. Fie n un numr natural. Conform criteriului de divizibilitate


cu 3, numrul n este divizibil cu 3 dac suma cifrelor numrului
n este un numr divizibil cu 3. n programul urmtor este definit
o funcie care implementeaz criteriul de divizibilitate cu 3.
// Test divizibilitate cu 3
#include "stdio.h"
#include "conio.h"
int test3(int n)
{
int s,uc,nsalv;

125

Funcii
nsalv=n;
s=0;
while(n!=0)
{
uc=n%10;
s+=uc;
n/=10;
}
printf(" Suma cifrelor numarului %d este %d
\n",nsalv,s);
if(s%3) return 0;
else return 1;
return s;
}
int main()
{
int n;
printf(" n = ");
scanf("%d",&n);
if(test3(n))
printf(" Numarul %d este divizibil cu 3 \n",n);
else
printf(" Numarul %d nu este divizibil cu 3
\n",n);
getch();
}

Un exemplu de rulare este:


n = 123456789
Suma cifrelor numarului 123456789 este 45
Numarul 123456789 este divizibil cu 3
n = 1234
Suma cifrelor numarului 1234 este 10
Numarul 1234 nu este divizibil cu 3

55. Fie n un numr natural. Conform criteriului de divizibilitate


cu 9, numrul n este divizibil cu 9 dac suma cifrelor numrului
n este un numr divizibil cu 9. n programul urmtor este definit
o funcie care implementeaz criteriul de divizibilitate cu 9.
// Test divizibilitate cu 9
#include "stdio.h"
#include "conio.h"
int test9(int n)

126

Bazele programrii calculatoarelor


{

int s,uc,nsalv;
nsalv=n;
s=0;
while(n!=0)
{
uc=n%10;
s+=uc;
n/=10;

}
printf(" Suma cifrelor numarului %d este %d
\n",nsalv,s);
if(s%9) return 0;
else return 1;
return s;
}
int main()
{
int n;
printf(" n = ");
scanf("%d",&n);
if(test9(n))
printf(" Numarul %d este divizibil cu 9 \n",n);
else
printf(" Numarul %d nu este divizibil cu 9
\n",n);
getch();
}

Un exemplu de rulare este:


n = 123456789
Suma cifrelor numarului 123456789 este 45
Numarul 123456789 este divizibil cu 9
n = 1234
Suma cifrelor numarului 1234 este 10
Numarul 1234 nu este divizibil cu 9

56. Fie n un numr natural. Conform criteriului de divizibilitate


cu 4, numrul n este divizibil cu 4 dac numrul format cu
ultimele dou cifre ale numrului n este un numr divizibil cu 4.
n programul urmtor este definit o funcie care implementeaz
criteriul de divizibilitate cu 4.
// Test divizibilitate cu 4

127

Funcii
#include "stdio.h"
#include "conio.h"
int test4(int n)
{
int udc,uc,k,nsalv;
nsalv=n;
udc=n%10;
n/=10;
k=1;
while(n!=0 && k<=1)
{
uc=n%10;
uc*=10;
udc+=uc;
k++;
n/=10;
}
printf(" Numarul format cu ultimele doua cifre\n");
printf(" ale numarului %d este egal cu %d
\n",nsalv,udc);
if(udc%4==0) return 1;
else return 0;
}
int main()
{
int n;
printf(" n = ");
scanf("%d",&n);
if(test4(n))
printf(" Numarul %d este divizibil cu 4 \n",n);
else
printf(" Numarul %d nu este divizibil cu 4
\n",n);
getch();
}

Un exemplu de rulare este:


n = 123456
Numarul format cu ultimele doua cifre
ale numarului 123456 este egal cu 56
Numarul 123456 este divizibil cu 4
n = 123
Numarul format cu ultimele doua cifre
ale numarului 123 este egal cu 23

128

Bazele programrii calculatoarelor


Numarul 123 nu este divizibil cu 4

57. Fie n un numr natural cu trei cifre. Conform criteriului de


divizibilitate cu 11, numrul n este divizibil cu 11 dac suma
dintre prima i ultima sa cifr este egal cu a doua cifr. n
programul urmtor este definit o funcie care implementeaz
criteriul de divizibilitate cu 11.
// Test divizibilitate cu 11
#include "stdio.h"
#include "conio.h"
int test11(int n)
{
int uc,nsalv,i,cif[3];
nsalv=n;
i=0;
while(n!=0)
{
uc=n%10;
cif[i]=uc;
i++;
n/=10;
}
if(cif[0]+cif[2]==cif[1])
return 1;
else return 0;
}
int main()
{
int n;
printf(" n = ");
scanf("%d",&n);
if(test11(n))
printf(" Numarul %d este divizibil cu 11 \n",n);
else
printf(" Numarul %d nu este divizibil cu 11
\n",n);
getch();
}

Un exemplu de rulare este:


n = 154
Numarul 154 este divizibil cu 11
n = 432

129

Funcii
Numarul 432 nu este divizibil cu 11

58. Programul urmtor definete o funcie pentru determinarea


sumei elementelor de pe coloana k a unei matrici ptrate, k citit
de la tastatur.
// Suma elementelor de pe coloana k
// a unei matrici patrate cu elemente numere intregi
#include "stdio.h"
#include "conio.h"
int sum(int a[][20], int n,int k)
{
int i,j,s;
s=0;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(j==k) s+=a[i][j];
return s;
}
int main()
{
int n,i,j,a[20][20],k;
printf(" Dimensiunea: ");
scanf("%d",&n);
printf(" Elementele matricei \n");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
printf(" a [ %d ][ %d ] = ",i,j);
scanf("%d",&a[i][j]);
}
printf(" Coloana pe care se calculeaza suma: ");
scanf("%d",&k);
if(k>=0 && k<=n-1)
printf(" Suma elementelor de pe coloana %d este %d
\n",k,sum(a,n,k));
else
printf(" Coloana %d inexistenta \n",k);
getch();
}

Un exemplu de rulare este:


Dimensiunea: 3
Elementele matricei
a [ 0 ][ 0 ] = 1

130

Bazele programrii calculatoarelor


a [ 0 ][ 1 ] = 2
a [ 0 ][ 2 ] = 3
a [ 1 ][ 0 ] = 4
a [ 1 ][ 1 ] = 5
a [ 1 ][ 2 ] = 6
a [ 2 ][ 0 ] = 7
a [ 2 ][ 1 ] = 8
a [ 2 ][ 2 ] = 9
Coloana pe care se calculeaza suma: 2
Suma elementelor de pe coloana 2 este 18

59. Programul urmtor definete o funcie pentru determinarea


sumei elementelor de pe linia k a unei matrici ptrate, k citit de
la tastatur.
// Suma elementelor de pe linia k
// a unei matrici patrate cu elemente numere intregi
#include "stdio.h"
#include "conio.h"
int sum(int a[][20], int n,int k)
{
int i,j,s;
s=0;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(i==k) s+=a[i][j];
return s;
}
int main()
{
int n,i,j,a[20][20],k;
printf(" Dimensiunea: ");
scanf("%d",&n);
printf(" Elementele matricei \n");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
printf(" a [ %d ][ %d ] = ",i,j);
scanf("%d",&a[i][j]);
}
printf(" Linia pe care se calculeaza suma: ");
scanf("%d",&k);
if(k>=0 && k<=n-1)
printf(" Suma elementelor de pe linia %d este %d
\n",k,sum(a,n,k));
else

131

Funcii
printf(" Linia %d inexistenta \n",k);
getch();
}

Un exemplu de rulare este:


Dimensiunea: 3
Elementele matricei
a [ 0 ][ 0 ] = 1
a [ 0 ][ 1 ] = 2
a [ 0 ][ 2 ] = 3
a [ 1 ][ 0 ] = 4
a [ 1 ][ 1 ] = 5
a [ 1 ][ 2 ] = 6
a [ 2 ][ 0 ] = 7
a [ 2 ][ 1 ] = 8
a [ 2 ][ 2 ] = 9
Linia pe care se calculeaza suma: 1
Suma elementelor de pe linia 1 este 15

60. Programul urmtor definete o funcie pentru determinarea


sumei elementelor de pe diagonala principal a unei matrici
ptrate. Facem observaia c elementul aij este pe diagonala
principal dac i j .
// Suma elementelor de pe diagonala principala
// a unei matrici patrate cu elemente numere intregi
#include "stdio.h"
#include "conio.h"
int sdp(int a[][20], int n)
{
int i,j,s;
s=0;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(i==j) s+=a[i][j];
return s;
}
int main()
{
int n,i,j,a[20][20];
printf(" Dimensiunea: ");
scanf("%d",&n);
printf(" Elementele matricei \n");
for(i=0;i<n;i++)

132

Bazele programrii calculatoarelor


for(j=0;j<n;j++)
{
printf(" a [ %d ][ %d ] = ",i,j);
scanf("%d",&a[i][j]);
}
printf(" Suma elementelor de pe diagonala principala
este %d \n",sdp(a,n));
getch();
}

Un exemplu de rulare este:


Dimensiunea: 3
Elementele matricei
a [ 0 ][ 0 ] = 1
a [ 0 ][ 1 ] = 2
a [ 0 ][ 2 ] = 3
a [ 1 ][ 0 ] = 4
a [ 1 ][ 1 ] = 5
a [ 1 ][ 2 ] = 6
a [ 2 ][ 0 ] = 7
a [ 2 ][ 1 ] = 8
a [ 2 ][ 2 ] = 9
Suma elementelor de pe diagonala principala este 15

61. Programul urmtor definete o funcie pentru determinarea


sumei elementelor de pe diagonala secundar a unei matrici
ptrate cu n linii i n coloane. Facem observaia c elementul aij
este pe diagonala secundar dac i j n 1 .
// Suma elementelor de pe diagonala secundara
// a unei matrici patrate cu elemente numere intregi
#include "stdio.h"
#include "conio.h"
int sum(int a[][20], int n)
{
int i,j,s;
s=0;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if((i+j)==n-1) s+=a[i][j];
return s;
}
int main()
{

133

Funcii
int n,i,j,a[20][20];
printf(" Dimensiunea: ");
scanf("%d",&n);
printf(" Elementele matricei \n");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
printf(" a [ %d ][ %d ] = ",i,j);
scanf("%d",&a[i][j]);
}
printf(" Suma elementelor de pe diagonala secundara
este %d \n",sum(a,n));
getch();
}

Un exemplu de rulare este:


Dimensiunea: 3
Elementele matricei
a [ 0 ][ 0 ] = 1
a [ 0 ][ 1 ] = 2
a [ 0 ][ 2 ] = 3
a [ 1 ][ 0 ] = 4
a [ 1 ][ 1 ] = 5
a [ 1 ][ 2 ] = 6
a [ 2 ][ 0 ] = 7
a [ 2 ][ 1 ] = 8
a [ 2 ][ 2 ] = 9
Suma elementelor de pe diagonala secundara este 15

62. Programul urmtor definete o funcie pentru determinarea


sumei elementelor aflate sub diagonala principal (subdiagonale)
a unei matrici ptrate cu n linii i n coloane. Facem observaia
c elementul aij este subdiagonal dac i j .
// Suma elementelor subdiagonale
// ale unei matrici patrate cu elemente numere
intregi
#include "stdio.h"
#include "conio.h"
int sum(int a[][20], int n)
{
int i,j,s;
s=0;
for(i=0;i<n;i++)
for(j=0;j<n;j++)

134

Bazele programrii calculatoarelor


if(i>j) s+=a[i][j];
return s;
}
int main()
{
int n,i,j,a[20][20];
printf(" Dimensiunea: ");
scanf("%d",&n);
printf(" Elementele matricei \n");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
printf(" a [ %d ][ %d ] = ",i,j);
scanf("%d",&a[i][j]);
}
printf(" Suma elementelor subdiagonale este %d
\n",sum(a,n));
getch();
}

Un exemplu de rulare este:


Dimensiunea: 3
Elementele matricei
a [ 0 ][ 0 ] = 1
a [ 0 ][ 1 ] = 2
a [ 0 ][ 2 ] = 3
a [ 1 ][ 0 ] = 4
a [ 1 ][ 1 ] = 5
a [ 1 ][ 2 ] = 6
a [ 2 ][ 0 ] = 7
a [ 2 ][ 1 ] = 8
a [ 2 ][ 2 ] = 9
Suma elementelor subdiagonale este 19

63. Programul urmtor definete o funcie pentru determinarea


sumei elementelor aflate deasupra diagonalei principale
(supradiagonale) a unei matrici ptrate cu n linii i n coloane.
Facem observaia c elementul aij este supradiagonal dac i j .
// Suma elementelor supradiagonale
// ale unei matrici patrate cu elemente numere
intregi
#include "stdio.h"
#include "conio.h"
int sum(int a[][20], int n)

135

Funcii
{
int i,j,s;
s=0;
for(i=0;i<n;i++)
for(j=0;j<n;j++)
if(i<j) s+=a[i][j];
return s;
}
int main()
{
int n,i,j,a[20][20];
printf(" Dimensiunea: ");
scanf("%d",&n);
printf(" Elementele matricei \n");
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
printf(" a [ %d ][ %d ] = ",i,j);
scanf("%d",&a[i][j]);
}
printf(" Suma elementelor supradiagonale este %d
\n",sum(a,n));
getch();
}

Un exemplu de rulare este:


Dimensiunea: 3
Elementele matricei
a [ 0 ][ 0 ] = 1
a [ 0 ][ 1 ] = 2
a [ 0 ][ 2 ] = 3
a [ 1 ][ 0 ] = 4
a [ 1 ][ 1 ] = 5
a [ 1 ][ 2 ] = 6
a [ 2 ][ 0 ] = 7
a [ 2 ][ 1 ] = 8
a [ 2 ][ 2 ] = 9
Suma elementelor supradiagonale este 11

64. Un numr natural n nenul se numete perfect dac este


egal cu suma divizorilor si diferii de n . Programul urmtor
citete un numr natural k i determin toate numerele perfecte
din mulimea 1, 2, , k . Testul de numr perfect este fcut de
funcia perfect. Funcia are ca parametru de intrare intregul n
136

Bazele programrii calculatoarelor

i returneaz prin numele su valoarea 1 dac n este numr


perfect sau valoarea zero dac n nu este numr perfect.
// Numerele perfecte din multimea {1,2,...,k}
#include "stdio.h"
#include "conio.h"
int perfect(int n)
{
int i,sum_div;
for(sum_div=0,i=1;i<=n/2;i++)
if(n%i==0)
sum_div+=i;
if(n==sum_div)
return 1;
else return 0;
}
int main()
{
int k,n;
printf(" k = ");
scanf("%d",&k);
for(n=1;n<=k;n++)
if(perfect(n))
printf(" %d este numar perfect \n",n);
getch();
}

Un exemplu de rulare este:


k = 10000
6 este numar perfect
28 este numar perfect
496 este numar perfect
8128 este numar perfect

65. Programul din exemplul anterior poate fi modificat astfel


nct s determine primele k numere perfecte. O variant este
urmtoarea:
// Primele k numere perfecte
#include "stdio.h"
#include "conio.h"
int perfect(int n)
{
int i,sum_div;
for(sum_div=0,i=1;i<=n/2;i++)

137

Funcii
if(n%i==0)
sum_div+=i;
if(n==sum_div)
return 1;
else return 0;
}
int main()
{
int i,k,n;
printf(" k = ");
scanf("%d",&k);
printf(" Primele %d numere perfecte sunt \n",k);
i=1;
n=1;
while(n<=k)
{
if(perfect(i))
{
printf(" %d este numar perfect \n",i);
i++;
n++;
}
else
i++;
}
getch();
}

Un exemplu de execuie este:


k = 4
Primele 4 numere perfecte sunt
6 este numar perfect
28 este numar perfect
496 este numar perfect
8128 este numar perfect

66. Dou numere naturale n i m se numesc numere prietene


dac suma divizorilor lui m (fr numrul m ) este egal cu n i
suma divizorilor lui n (fr numrul n ) este egal cu m . De
exemplu numerele 220 i 284 sunt prietene. Programul urmtor
testeaz dac dou numere naturale sunt sau nu numere
prietene. n program sunt definite dou funcii: sum_div pentru
determinarea sumei divizorilor parametrului de intrare i
138

Bazele programrii calculatoarelor


prietene care testeaz dac parametrii de intrare sunt numere

prietene. Se poate observa c dac un numr este perfect atunci


el este numr prieten cu el nsui.
// Test numere prietene
#include "stdio.h"
#include "conio.h"
int sum_div(int n)
{
int i,sd;
for(i=1,sd=0;i<=n/2;i++)
if(n%i==0)
sd+=i;
return sd;
}
int prietene(int n, int m)
{
if(n==sum_div(m) && m==sum_div(n))
return 1;
else return 0;
}
int main()
{
int n,m;
printf(" n = ");
scanf("%d",&n);
printf(" m = ");
scanf("%d",&m);
if(prietene(n,m))
printf(" Numerele %d si %d sunt prietene
\n",n,m);
else
printf(" Numerele %d si %d nu sunt prietene
\n",n,m);
getch();
}

Un exemplu de rulare este:


n = 220
m = 284
Numerele 220 si 284 sunt prietene
n = 28
m = 28
Numerele 28 si 28 sunt prietene

139

Funcii
n = 220
m = 264
Numerele 220 si 264 nu sunt prietene

67. Programul din exemplul anterior poate fi modificat astfel


nct s determine toate perechile de numere prietene distincte,
mai mici sau egale cu o valoare dat p .
// Perechile de numere prietene distincte mai mici
decat p
#include "stdio.h"
#include "conio.h"
int sum_div(int n)
{
int i,sd;
for(i=1,sd=0;i<=n/2;i++)
if(n%i==0)
sd+=i;
return sd;
}
int prietene(int n, int m)
{
if(n==sum_div(m) && m==sum_div(n))
return 1;
else return 0;
}
int main()
{
int k,i,j,n,p;
printf(" p = ");
scanf("%d",&p);
n=1;
for(i=1;i<=p;i++)
for(j=i+1;j<=p;j++)
if(prietene(i,j))
{
printf("%d Numerele %d si %d sunt prietene
\n",n,i,j);
n++;
}
getch();
}

Un exemplu de rulare este:


140

Bazele programrii calculatoarelor


p = 2000
1 Numerele 220 si 284 sunt prietene
2 Numerele 1184 si 1210 sunt prietene

68. Este cunoscut faptul c orice numr natural par se poate


reprezenta ca suma adou numere prime (descompunerea
Goldbach). Programul urmtor descompune numrul natural par
n suma a dou numere prime. Pentru testul de numr prim am
folosit funcia prim.
//Proprietatea Goldbach
#include "stdio.h"
#include "conio.h"
int prim(int n)
{
int i,p;
p=1;
for(i=2;i<=n/2;i++)
if(n%i==0)
p=0;
return p;
}
int main()
{
int n,i,dif,p;
printf(" n = ");
scanf("%d",&n);
if(n%2==0)
{
i=2;
while(i<n-1)
{
if(prim(i))
{
p=i;
i++;
}
else
i++;
}
dif=n-p;
printf(" %d = %d + %d \n",n,dif,p);
}
else
printf(" %d nu este numar par \n",n);

141

Funcii
getch();
}

Rularea programului conduce la rezultatele:


n = 12
12 = 5 + 7
n = 13
13 nu este numar par

69. Programul urmtor determin i afieaz descompunerea


Goldbach pentru toate numerele pare din mulimea 4,5, , k , k
citit de la tastatur.
//Proprietatea Goldbach pe multimea {3,4,...,k}
#include "stdio.h"
#include "conio.h"
int prim(int n)
{
int i,p;
p=1;
for(i=2;i<=n/2;i++)
if(n%i==0)
p=0;
return p;
}
int main()
{
int k,n,i,dif,p;
printf(" k = ");
scanf("%d",&k);
for(n=4;n<=k;n++)
{
if(n%2==0)
{
i=2;
while(i<n-1)
{
if(prim(i))
{
p=i;
i++;
}
else
i++;

142

Bazele programrii calculatoarelor


}
dif=n-p;
printf(" %d = %d + %d \n",n,dif,p);
}
}
getch();
}

O rulare a programului produce rezultatele:


k = 30
4 = 2 + 2
6 = 3 + 3
8 = 3 + 5
10 = 3 + 7
12 = 5 + 7
14 = 3 + 11
16 = 3 + 13
18 = 5 + 13
20 = 3 + 17
22 = 3 + 19
24 = 5 + 19
26 = 3 + 23
28 = 5 + 23
30 = 7 + 23

70. Este cunoscut faptul c produsul a oricror dou numere


naturale consecutive este un numr natural cuprins ntre dou
numere impare dintre care cel puin unul este numr prim.
Programul urmtor verific acest rezultat pentru fiecare numr
natural din mulimea 2,3, , n , n citit de la tastatur. Testul de
numr prim este fcut de funcia prim.
//Produs numere consecutive
#include "stdio.h"
#include "conio.h"
int prim(int n)
{
int i,p;
p=1;
for(i=2;i<=n/2;i++)
if(n%i==0)
p=0;
return p;
}

143

Funcii
int main()
{
int k,n,produs;
printf(" n = ");
scanf("%d",&n);
for(k=2;k<=n;k++)
{
produs=k*(k+1);
printf(" %d < %d * %d = %d < %d \n",produs1,k,k+1,produs,produs+1);
if(prim(produs-1))
printf(" %d este numar prim \n",produs-1);
if(prim(produs+1))
printf(" %d este numar prim \n",produs+1);
}
getch();
}

Rezultatele unei rulri sunt:


n = 5
5 < 2 * 3 = 6 < 7
5 este numar prim
7 este numar prim
11 < 3 * 4 = 12 < 13
11 este numar prim
13 este numar prim
19 < 4 * 5 = 20 < 21
19 este numar prim
29 < 5 * 6 = 30 < 31
29 este numar prim
31 este numar prim

71. Program pentru determinarea tuturor numerelor de cinci


cifre, din intervalul li, ls , li numar cu cinci cifre, care au
urmtoarele proprieti:
a) ultima cifr este egal cu 7;
b) printre primele patru cifre, cifra 1 apare o singur dat;
c) suma tuturor cifrelor este un numr impar;
d) primele patru cifre sunt distincte.
n program sunt definite trei funcii utilizator pentru determinarea
ultimei cifre, sumei cifrelor, numrului de cifre i dou funcii care
testeaz dac primele patru cifre sunt distincte i respectiv dac
144

Bazele programrii calculatoarelor

printre primele patru cifre, cifra 1 apare o singur dat. Programul


este prezentat n continuare:
// Determinarea tuturor numerelor cu 5 cifre cu
proprietatile
// 1. Ultima cifra este 7
// 2. Printre primele patru cifre, cifra 1 apare
exact o singura data
// 3. Suma tuturor cifrelor este un numar impar
// 4. Primele patru cifre sunt distincte
#include "stdio.h"
#include "conio.h"
int v[4];
// Prototipurile functiilor utilizator
int
int
int
int
int

uc(int);
sc(int);
nc(int);
dis(void);
c1(void);

// Functia care determina ultima cifra


int uc(int n)
{
int u;
u=n%10;
return u;
}
// Functia care determina suma cifrelor si care
// construieste vectorul format cu primele patru
cifre
int sc(int n)
{
int sc, uc, i;
sc=0;
i=0;
uc=n%10;
sc=sc+uc;
while(n)
{
n=n/10;
uc=n%10;
sc=sc+uc;

145

Funcii

v[i]=uc;
i++;
}
return sc;

// Functia care determina numarul de cifre ale


numarului n
int nc(int n)
{
int s;
s=0;
while(n)
{
n=n/10;
s++;
}
return s;
}
// Functia care testeaza daca primele patru cifre
sunt distincte
int dis(void)
{
int i,j,ok;
ok=1;
for(i=0;i<4;i++)
for(j=i+1;j<4;j++)
if(v[i]==v[j]) ok=0;
return ok;
}
// Functia care testeaza daca printre primele patru
cifre
// exista cifra 1
int c1(void)
{
int i, ok;
ok=0;
for(i=0;i<3;i++)
if(v[i]==1) ok=1;
return ok;
}
// Functia principala
int main()

146

Bazele programrii calculatoarelor


{

int li,ls,i,nt;
nt=0;
printf(" li = ");
scanf("%d",&li);
printf(" ls = ");
scanf("%d",&ls);
if(li <= ls && nc(li)==5)
{
for(i=li;i<=ls;i++)
{
if(sc(i)%2==1){
if(dis() && c1() && uc(i)==7){
nt++;
printf(" %d. i = %d \n",nt,i);
}}
}
printf(" Numar total de numere %d \n",nt);
}
else
printf(" Numarul %d nu are 5 cifre sau %d > %d
\n",li,li,ls);
getch();
}

Un exemplu de rulare este:


li = 20000
ls = 21000
1. i = 20137
2. i = 20157
3. i = 20177
4. i = 20197
5. i = 20317
6. i = 20517
7. i = 20717
8. i = 20917
Numar total de numere 8

72. Funcie pentru determinarea lungimii unui ir de caractere.


// Functie pentru determinarea lungimii unui sir de
caractere
#include "stdio.h"
#include "conio.h"
void strlen(char *s,int &n)
{

147

Funcii
int i;
for(i=0;*(s+i)!='\0';i++);
n=i;
}
int main()
{
char s[100];
int lung;
puts(" Sirul ");
gets(s);
strlen(s,lung);
printf(" Sirul %s are %d caractere \n",s,lung);
getch();
}

Un exemplu de rulare este urmtorul:


Sirul
Determinarea lungimii
Sirul Determinarea lungimii are 21 caractere

73. Funcie pentru copierea unui ir de caractere.


//Functie pentru copierea unui sir de caractere
#include "stdio.h"
#include "conio.h"
char * strcpy(char *sd, char *ss)
{
int i;
for(i=0;*(ss+i)!='\0';*(sd+i)=*(ss+i),i++);
*(sd+i)='\0';
return sd;
}
int main()
{
char sirs[20],sird[100],*sd;
puts(" Sir sursa ");
gets(sirs);
sd=strcpy(sird,sirs);
puts(" Sirul sursa ");
printf(" %s \n",sirs);
puts(" Sirul destinatie ");
printf(" %s \n",sird);
printf(" Adresa sir destinatie returnata de
functie este %x \n",sd);
printf(" Adresa sir destinatie din functia main
este %x \n",sird);

148

Bazele programrii calculatoarelor


}

getch();

Sir sursa
functie pentru copiere sir de caractere
Sirul sursa
functie pentru copiere sir de caractere
Sirul destinatie
functie pentru copiere sir de caractere
Adresa sir destinatie returnata de functie este
22fec0
Adresa sir destinatie din functia main este 22fec0

74. Funcie pentru concatenarea a dou iruri de caractere.


//Functie pentru concatenarea a doua siruri
#include "stdio.h"
#include "conio.h"
char * strcat(char *sd, char *ss)
{
int i,ld;
for(i=0;*(sd+i)!='\0';i++);
ld=i;
i=0;
while(*(ss+i)!='\0')
{
*(sd+ld+i)=*(ss+i);
i++;
}
*(sd+ld+i)='\0';
return sd;
}
int main()
{
char sirs[20],sird[100],*sd;
puts(" Sir sursa ");
gets(sirs);
puts(" Sir destinatie ");
gets(sird);
sd=strcat(sird,sirs);
puts(" Sirul concatenat ");
printf(" %s \n",sird);
printf(" Adresa sir destinatie returnata de
functie este %x \n",sd);
printf(" Adresa sir destinatie din functia main
este %x \n",sird);
getch();

149

Funcii
}
Sir sursa
concatenare
Sir destinatie
functie pentru
Sirul concatenat
functie pentru concatenare
Adresa sir destinatie returnata de functie este
22fec0
Adresa sir destinatie din functia main este 22fec0

75. Funcie pentru determinarea primei apariii a unui caracter


ntr-un ir de caractere.
//Functie de cautare a unui caracter intr-un sir
//Functia returneaza adresa primei aparitii a
caracterului sau NULL
#include "stdio.h"
#include "conio.h"
char * strchr(char *s, char c)
{
int i,gasit=0;
char *adr;
i=0;
while(*(s+i)!='\0')
{
if(*(s+i)==c)
{
adr=s+i;
gasit=1;
break;
}
else i++;
}
if(gasit) return adr;
else return NULL;
}
int main()
{
char sir[20],c,*s;
int n;
puts(" Sirul ");
gets(sir);
puts(" Caracterul ");
scanf("%c",&c);

150

Bazele programrii calculatoarelor


s=strchr(sir,c);
if(s)
{
n=s-sir;
printf(" Caracterul %c are prima aparitie
in sirul %s pe pozitia %d \n",c,sir,n);
}
else
printf(" Caracterul %c nu apare in sirul %s
\n",c,sir);
getch();
}

Un exemplu de rulare este:


Sirul
abecedar
Caracterul
c
Caracterul c are prima aparitie in sirul abecedar
pe pozitia 3
Sirul
abecedar
Caracterul
#
Caracterul # nu apare in sirul abecedar

76. Variant recursiv a algoritmului lui Euclid. Determinarea


celui mai mare divizor comun cu algoritmul lui Euclid poate fi
fcut recursive, folosind relaia de recuren:
m
daca n 0

.
cmmdc (m, n)
cmmdc m, cmmdc n, m%n daca n 0
Programnd aceast relaie de recuren se obine urmtorul
cod:
// Varianta recursiva a algoritmului lui Euclid
#include "stdio.h"
#include "conio.h"
int cmmdc(int m, int n)
{
if(n==0) return m;
else return cmmdc(n,m%n);

151

Funcii
}
int main()
{
int m,n;
printf(" m = ");
scanf("%d",&m);
printf(" n = ");
scanf("%d",&n);
if(cmmdc(m,n)==1)
printf(" Numerele %d si %d sunt prime intre ele
\n",m,n);
else
printf(" Numerele %d si %d nu sunt prime intre
ele \n",m,n);
printf(" cmmdc( %d , %d ) = %d
\n",m,n,cmmdc(m,n));
getch();
}

Se obin rezultatele:
m = 124
n = 24
Numerele 124 si 24 nu sunt prime intre ele
cmmdc( 124 , 24 ) = 4
77. Program urmtor afieaz primii n termeni ai irului lui
Fibonacci, definit prin: fib : N N , fib 0 1 , fib 1 1 ,
fib n fib( n 1) fib n 2 , n 2 .
#include <stdio.h>
#include <conio.h>
int fib(int n)
{
if (n==0 || n==1)
return 1;
else
return fib(n-1)+fib(n-2);
}
int main()
{
int n,i;

152

Bazele programrii calculatoarelor


printf("Generarea recursiva a termenilor sirului
lui Fibonacci \n");
printf("Rangul maxim n = ");
scanf("%d",&n);
printf("Primii %d termeni din sirul
Fibonacci:\n", n);
for(i=0;i<n;i++)
printf("Termenul de rang %d in sirul Fibonacci
este %d \n",i,fib(i));
getch();
}
Generarea recursiva a termenilor sirului lui
Fibonacci
Rangul maxim n = 5
Primii 6 termeni ai sirului Fibonacci sunt:
Termenul de rang 0 in sirul Fibonacci este 1
Termenul de rang 1 in sirul Fibonacci este 1
Termenul de rang 2 in sirul Fibonacci este 2
Termenul de rang 3 in sirul Fibonacci este 3
Termenul de rang 4 in sirul Fibonacci este 5

78. Programul afieaz primii n termeni din irurile aritmeticgeometric-armonic ale lui Gauss, definite de relaiile de recuren:
a b c
a0 p 0 ,
b0 q 0 ,
c0 r 0 ,
an n1 n1 n1 ,
3
3
, n N * .
bn 3 an1 bn1 cn1 , cn
1
1
1

an1 bn1 cn1


#include <stdio.h>
#include <conio.h>
#include <math.h>
double p,q,r;
double a(int);
double b(int);
double c(int);
double a(int n)
{
if (n==0) return p;
else return (a(n-1)+b(n-1)+c(n-1))/3;
}
double b(int n)
{

153

Funcii
if (n==0) return q;
else return pow(a(n-1)*b(n-1)*c(n-1), 1./3);
}
double c(int n)
{
if (n==0) return r;
else return 3/(1/a(n-1)+1/b(n-1)+1/c(n-1));
}
int main()
{
int n,i;
printf("Sirurile aritmetic-geometric-armonic ale
lui Gauss\n");
printf("a( 0 ) = p = ");
scanf("%lf", &p);
printf("b( 0 ) = q = ");
scanf("%lf", &q);
printf("c( 0 ) = r = ");
scanf("%lf", &r);
printf(" Rangul maxim al termenilor n = ");
scanf("%i", &n);
for(i=0;i<n;i++)
printf("a( %d ) = %.4f\tb( %d ) = %.4f\tc(
%d ) = %.4f\n", i, a(i), i, b(i), i, c(i));
getch();
}
Sirurile aritmetic-geometric-armonic
a( 0 ) = p = 1
b( 0 ) = q = 2
c( 0 ) = r = 3
Rangul maxim al termenilor n = 4
a( 0 ) = 1.0000 b( 0 ) = 2.0000 c(
a( 1 ) = 2.0000 b( 1 ) = 1.8171 c(
a( 2 ) = 1.8178 b( 2 ) = 1.8117 c(
a( 3 ) = 1.8117 b( 3 ) = 1.8117 c(

ale lui Gauss

0
1
2
3

)
)
)
)

=
=
=
=

3.0000
1.6363
1.8056
1.8117

79. Programul urmtor afieaz pentru orice pereche


m, n N N , pentru i 0,1,..., m , j 0,1,..., n , valorile funciei lui
Ackerman definit astfel: Ack : N N N ,

n 1,
m0

Ack m, n
Ack m 1,1 ,
n 0 , m, n N N .
Ack m 1, Ack m, n 1 , altfel

154

Bazele programrii calculatoarelor

Pentru m>3, funcia lui Ackerman este puternic recursiv i


determinarea valorilor ei poate s dureze foarte mult.

#include <stdio.h>
#include <conio.h>
int ack(int m,int n)
{
if (m==0)
return n+1;
else if (n==0)
return ack(m-1,1);
else
return ack(m-1,ack(m,n-1));
}
int main()
{
int n,m,i,j;
printf(" Functia lui Ackerman \n");
printf(" Tastati valoarea lui m = ");
scanf("%d",&m);
printf(" Tastati valoarea lui n = ");
scanf("%d",&n);
for(i=0;i<=m;i++)
for(j=0;j<=n;j++)
printf("Ackerman ( %d , %d ) = %d\n",
i, j, ack(i,j));
getch();
}
Functia lui Ackerman
Tastati valoarea lui
Tastati valoarea lui
Ackerman ( 0 , 0 ) =
Ackerman ( 0 , 1 ) =
Ackerman ( 0 , 2 ) =
Ackerman ( 1 , 0 ) =
Ackerman ( 1 , 1 ) =
Ackerman ( 1 , 2 ) =
Ackerman ( 2 , 0 ) =
Ackerman ( 2 , 1 ) =
Ackerman ( 2 , 2 ) =
Ackerman ( 3 , 0 ) =
Ackerman ( 3 , 1 ) =
Ackerman ( 3 , 2 ) =

m = 3
n = 2
1
2
3
2
3
4
3
5
7
5
13
29

155

Funcii

80. Programul afieaz pentru orice interval a, b R , i pentru


ba

orice n N * , toate valorile f a i


, i 0,1,..., n , ale funciei
n

Manna-Pnueli definit prin: f : R R ,

x 1,
x 12

, x R .
f ( x)
f
f
x

2
,
altfel

#include <stdio.h>
#include <conio.h>
double f(double x)
{
if (x>=12)
return x-1;
else
return f(f(x+2));
}
int main()
{
float x,a,b,h;
int n,i;
printf(" Intervalul [a,b] \n");
printf("a = ");
scanf("%lf", &a);
printf("b = ");
scanf("%lf", &b);
printf(" Numarul de puncte n = ");
scanf("%i", &n);
h=(b-a)/n;
for(i=0;i<=n;i++){
x=a+i*h;
printf("MP( %g ) = %g\n", x, f(x));
}
getch();
}
Intervalul
a = 11.5
b = 13.5
Numarul de
MP( 11.5 )
MP( 11.7 )
MP( 11.9 )
MP( 12.1 )

156

[a,b]
puncte n = 10
= 11.5
= 11.7
= 11.9
= 11.1

Bazele programrii calculatoarelor


MP(
MP(
MP(
MP(
MP(
MP(
MP(

12.3
12.5
12.7
12.9
13.1
13.3
13.5

)
)
)
)
)
)
)

=
=
=
=
=
=
=

11.3
11.5
11.7
11.9
12.1
12.3
12.5

81. Problema turnurilor din Hanoi


Se dau trei tije notate A, B, C, aezate n poziie vertical.
Pe tija A se gsesc n discuri care au razele r1>r2>...>rn, aezate
n ordine descresctoare a razelor ncepnd de la baza tijei.
Problema const n determinarea mutrilor necesare transferului
celor n discuri de pe tija A pe tija B, n final discurile fiind aezate
pe tija B n aceeai ordine ca pe tija A. O mutare const n
aezarea unui singur disc pe o tij goal, sau peste un disc cu
raza mai mare, pe oricare dintre tije. Nu se poate aeza un disc
cu raz mai mare peste un disc cu raza mai mic. . Rezolvarea
problemei se poate face astfel: dac n 1 se mut discul de pe
tija surs pe tija destinaie, problema fiind astfel rezolvat. Dac
n 1 se mut primele n 1 discuri de pe tija s pe tija m folosind
ca tij de manevr d , apoi se mut discul rmas pe tija s pe tija
d , i n final se mut cele n 1 discuri de pe tija m pe tija d ,
folosind ca tij de manevr tija s . Notm cu hn, s, d , m irul
mutrilor necesare rezolvrii problemei i cu a b mutarea
primului disc de pe tija a pe tija b . Se obine relaia de recuren
a irului de mutri din problema turnurilor din Hanoi:
sd
daca n 1

.
hn, s, d , m
hn 1, s, m, d s d hn 1, m, d , s daca n 1
Rezolvarea const n programarea relaii de recuren a irului de
mutri din problema turnurilor din Hanoi. Programul afieaz
pentru orice n N * dat, mutrile care conduc la soluia problemei.
#include <stdio.h>
#include <conio.h>
void hanoi(int n, char a, char b, char c)

157

Funcii
{
if (n==1) {
printf("Se muta discul %d de pe %c pe %c\n",
n, a, b);
} else {
hanoi(n-1,a,c,b);
printf("Se muta discul %d de pe %c pe %c\n",
n, a, b);
hanoi(n-1,c,b,a);
}
}
int main()
{
int n;
printf("Problema turnurilor din Hanoi\n");
printf("Numarul de discuri n = ");
scanf("%d",&n);
hanoi(n,'A','B','C');
getch();
}
Problema turnurilor din Hanoi
Numarul de discuri n = 3
Se muta discul 1 de pe A pe B
Se muta discul 2 de pe A pe C
Se muta discul 1 de pe B pe C
Se muta discul 3 de pe A pe B
Se muta discul 1 de pe C pe A
Se muta discul 2 de pe C pe B
Se muta discul 1 de pe A pe B

7.6. Exerciii
60. S se scrie funcia void citirevector(int v[], int n)
care citete de la tastatur n numere ntregi i le memoreaz n
vectorul v.
61. S se scrie funcia void afiarevector(int v[], int
n) care afieaz pe ecran primele n numere ntregi din vectorul v.
62. Scriei un program C care s testeze cele dou funcii (adic
citete un vector de la tastatur i l afieaz pe ecran).
63. Scriei o funcie care afieaz suma elementelor pare i
produsul elementelor impare dintr-un vector i un program C care
s o testeze.
158

Bazele programrii calculatoarelor

64. Scriei o funcie care afieaz elementele maxim i minim


dintr-un vector i un program C care s o testeze.
65. Scriei o funcie care ntoarce poziia primei apariii a unui
numr m ntr-un vector i un program C care s o testeze.
66. Scriei o funcie care adun doi vectori i pune rezultatul n
al treilea vector, i un program C care s o testeze.
67. Scriei o funcie care sorteaz valorile unui vector de
numere reale i un program care s o testeze.
68. Scriei o funcie nerecursiv care returneaz valoarea n! (n
este parametrul funciei) i un program C care s o testeze
(Indicaie: folosii formula n! = 1 * 2 * ... * n).
69. Scriei o funcie recursiv care returneaz valoarea n! (n
este parametrul funciei) i un program C care s o testeze
(Indicaie: folosii formula recursiv n! = n * (n-1)! pentru n>1 i
n!=1 pentru n=0 sau 1).
70. Scriei o funcie nerecursiv care returneaz al n-lea termen
din irul lui Fibonacci (n este parametrul funciei) i un program C
care s o testeze (Indicaie: folosii formula t 1=1, t2=1, ti+2=ti+ti+1
pentru i>1).
71. Scriei o funcie recursiv care returneaz al n-lea termen
din irul lui Fibonacci (n este parametrul funciei) i un program C
care s o testeze (Indicaie: folosii formula recursiv ti=ti-1+ti-2
pentru n>2 i ti=1 altfel).
72. Scriei o funcie nerecursiv care returneaz valoarea
cmmdc(m,n) (m i n sunt parametrii funciei) i un program C care
s o testeze (Indicaie: ct timp m este diferit de n, se scade din
variabila mai mare valoarea variabilei mai mici; cnd m=n atunci
m e cmmdc).
73. Scriei o funcie nerecursiv care returneaz valoarea
cmmdc(m,n) (m i n sunt parametrii funciei) i un program C care
s o testeze (Indicaie: folosii formula recursiv cmmdc(a,b) = a,
daca b=0; cmmdc(a,b) = cmmdc(b, a%b), daca a>b; cmmdc(a,b)
= cmmdc(a, b%a), daca a<=b;).

159

Pointeri i gestiunea dinamic a memoriei

88.. P
PO
OIIN
NTTE
ER
RII
II G
GE
ES
STTIIU
UN
NE
EA
AD
DIIN
NA
AM
MIIC
C
A
AM
ME
EM
MO
OR
RIIE
EII
8.1. Pointeri
Un pointer este o variabil a crei valoare este o adres
din memoria calculatorului. Prin intermediul pointerului,
programatorul poate accesa i modifica informaia stocat n
memorie la adresa indicat de acesta. Pentru a accesa ntr-un
mod coerent informaia stocat n memorie, fiecare pointer are un
tip de baz care determin tipul informaiei aflate n memorie.
Pentru a declara o variabil de tip pointer se folosete
sintaxa:
tip *nume;

unde tip reprezint tipul de baz al pointerului, iar nume


reprezint numele variabilei pointer. Tipul informaiei referite de
ctre un pointer poate fi: un tip fundamental, tipul void, o
structur, o uniune, un tablou, o funcie sau alt pointer. Un pointer
cu tipul de baz void este un pointer ctre o informaie al crei tip
nu se cunoate exact.
De exemplu, declaraiile urmtoare
int *varsta;
char *nume;

declar pointerul varsta care va conine adresa unui numr


ntreg i pointerul nume care va conine adresa unui caracter.

8.2. Operatorii &, * i ->


Operatorul unar & (denumit n acest context operatorul de
refereniere) se poate folosi pentru a obine adresa unei variabile.
Aceast adres poate fi memorat ntr-un pointer. n sens invers,
informaia din memorie de la o anumit adres (memorat ntr-un
pointer) poate fi accesat folosind operatorul unar * (denumit n
acest context operatorul de derefereniere).
De exemplu, n urma execuiei secvenei de program
int x = 3, *px;

160

Bazele programrii calculatoarelor


px = &x;
*px = 5;

variabila x capt valoarea 5, deoarece pointerul px conine


adresa variabilei x, deci instruciunea *px = 5 este echivalent
cu x = 5.
Dac p este un pointer ctre o structur sau o uniune,
rezultatul expresiei *p este structura (sau uniunea) a crei
adres este memorat n p. Pentru a accesa membrii acesteia
folosind operatorul punct (care are o prioritate mai mare dect
operatorul *), expresia *p trebuie scris ntre paranteze rotunde
astfel: (*p).membru. Pentru a evita aceast construcie, putem
folosi operatorul -> (caracterul minus urmat de caracterul mai
mare) astfel: p->membru.

Operatorii * i -> nu se pot aplica pointerilor de tip void.


Indiferent de tipul pointerului, acestuia i se poate atribui
valoarea 0, cu semnificaia "pointer neiniializat".
n biblioteca stdio.h, este definit constanta simbolic NULL
cu valoarea 0, a crei folosire este recomandat n locul
valorii 0 n cazul pointerilor.

8.3. Aritmetica pointerilor


n afar de operatorul &, un pointer poate fi folosit n
diverse expresii cu operatorii de adunare, scdere i indexare,
astfel: adunarea/scaderea unui pointer i ntreg, scderea a doi
pointeri i indexarea unui pointer cu un ntreg. n fiecare dintre
aceste operaii se ine cont de tipul informaiei pe care o
adreseaz pointerul, deci ele nu pot fi aplicate pointerilor de tip
void.
Dac p este un pointer cu tipul de baz t i n est un
numr ntreg, atunci expresiile p+n i p-n sunt corecte, rezultatul
lor fiind adrese de tipul t. Astfel, dac privim memoria
calculatorului ca un vector cu elemente de tipul t, atunci rezultatul
expresiei p+n este adresa elementului aflat la n elemente distan
dup p, iar rezultatul expresiei p-n este adresa elementului aflat
la n elemente distan naintea lui p.
161

Pointeri i gestiunea dinamic a memoriei

Dac p i q sunt pointeri cu tipul de baz t, atunci


expresiile p-q i q-p sunt corecte, rezultatul lor fiind un numr
ntreg. Astfel, dac privim memoria calculatorului ca un vector cu
elemente de tipul t, atunci rezultatul expresiei p-q este numrul
de elemente de la p la q, iar rezultatul expresiei q-p este numrul
de elemente de la q la p,
q-p=4

p-3

p+3

Dac p este un pointer cu tipul de baz t i n un numr


ntreg, atunci expresia p[n] este corect, rezultatul ei fiind o
valoare de tipul t. Astfel, dac privim memoria calculatorului ca un
vector cu elemente de tipul t, atunci rezultatul expresiei p[n] este
valoarea elementului aflat la n elemente distan dup lui p.
Practic, expresia p[n] este echivalent cu expresia *(p+n).
De exemplu, n urma execuiei instruciunilor urmtoare:
int vec[10]; // un vector cu 10 elemente intregi
int *p = &vec[2]; // p este pointer la al 3-lea
element din vec
int *q = &vec[4]; // q este pointer la al 5-lea
element din vec

p+2 este egal cu q, p-q este egal cu 2, q-2 este egal cu p, iar p[2],
q[0], *q i vec[4] reprezint aceeai informaie.

8.4. Legtura ntre tablouri i pointeri


Aa cum s-a observat n seciunea anterioar, un pointer
poate fi folosit pentru a accesa elementele unui masiv. Acest
lucru este posibil deoarece numele unui masiv este un pointer
ctre zona de memorie unde sunt stocate elementele acestuia.

162

Bazele programrii calculatoarelor

Totui, valoarea acestui pointer nu poate fi modificat (deci este


un pointer constant).
Din acest motiv, un ir de caractere (care este de fapt un
vector cu elemente de tip char i ultimul caracter NUL) poate fi
privit ca un pointer la informaii de tip char (vezi capitolul 8).
Aceast relaie se poate generaliza i pentru masive
multidimensionale. De exemplu, pentru urmtoarele instruciuni:
int tab[10][20][30];
int *pt = &tab[0][0][0];

elementul tab[m][n][p] poate fi accesat i prin construciile


(echivalente)
*(pt+(m*30+n)*20+p)
(pt+((m*30+n)*20)[p]
(pt+m*30*20)[n*20 + p]
pt[(m*30+n)*20 + p]

8.5. Gestiunea dinamic a memoriei


n limbajul C, dimensiunea fiecrei variabile trebuie
cunoscut n momentul compilrii programului; pentru variabilele
cu tip fundamental, dimensiunea este furnizat implicit de tipul
acestor; pentru masive, dimensiunea este furnizat explicit prin
dimensiunile acestora (i tipul elementelor), etc.
Pentru a lucra cu informaii ale cror dimensiuni nu sunt
cunoscute la momentul compilrii programului exist dou
alternative: declararea la compilare a unor dimensiuni care
acoper n mod sigur necesarul de memorie sau alocarea
memoriei necesare n timpul execuiei programului.
Funciile standard pentru gestiunea dinamic a memoriei
se gsesc n biblioteca malloc.h. Pentru a fi generale, aceste
funcii lucreaz cu pointeri de tip void, deci este necesar ca
programatorul s execute conversii explicite de tip.
Tabel 8.1 Funcii standard pentru gestiunea dinamic a memoriei

Prototi
p

Descriere

void*

Efect: aloc o zon de memorie de

calloc

163

Pointeri i gestiunea dinamic a memoriei


(unsigned
dimensiune cnt*size octei i completeaz cu
cnt,
valoarea 0 coninutul acesteia.
unsigned
Rezultat: adresa zonei de memorie
size)

alocate sau NULL n caz de eroare


Efect: aloc o zon de memorie de
malloc
dimensiune
size octei
(unsigned
Rezultat: adresa zonei de memorie
size)
alocate sau NULL n caz de eroare
void*
Efect: realoc zona de memorie
realloc
indicat
de pointerul ptr astfel nct s aib
(void * ptr,
dimensiunea
size octei
unsigned
Rezultat: adresa zonei de memorie
size)
realocate sau NULL n caz de eroare
void
Efect: elibereaz zona de memorie
free
(void indicat de pointerul ptr
*ptr);
void*

Algoritmul general de lucru n cazul folosirii dinamice a


memoriei const n alocarea memorie, folosirea ei i, n final,
eliberarea acesteia.
De exemplu, dac vrem s citim de la tastatur un numr
variabil de valori ntregi putem folosi urmtoarea secven:
int i, nrvalori, *valori;
printf(Introduceti numarul de valori: );
scanf(%d, &nrvalori); // citim numarul de valori
valori = (int *) calloc(nrvalori, sizeof(int));
if(valori == NULL) {
printf(Memorie insuficienta\n);
} else {
for (i = 0; i < nrvalori; ++i) {
printf(Introduceti valoarea a %d-a: ,
i+1);
scanf(%d, &valori[i]);
}
// alte operatii...
free(valori);
}

164

Bazele programrii calculatoarelor

8.6. Funcii pentru operaii cu blocuri de memorie


Aceste funcii permit prelucrarea simpl informaiei din
memorie la nivel de octei, dar cu o vitez ridicat. Funciile
standard pentru manipularea blocurilor de memorie se gsesc n
biblioteca string.h. n prototipurile acestor funcii, parametrul c
de tip int reprezint de fapt un octet (sau un caracter). Ele pot fi
folosite att pentru zone de memorie alocate dinamic, ct i
pentru zone de memorie declarate static.
Tabel 8.2 Funcii standard pentru manipularea blocurilor de memorie

Prototi
p
void*
memcpy (void
*dest,
void
*src,
unsigned
cnt)
void*
memccpy
(void *dest,
void
*src,
int
c,
unsigned
cnt)

Descriere
Efect: copiaz cnt octei din zona de
memorie src n dest (src i dest trebuie s fie
disjuncte)
Rezultat: adresa destinaie dest

Efect: copiaz cnt octei din zona de


memorie src n dest sau pn la apariia
primului octet c.
Rezultat: adresa din destinaie a
octetului care urmeaz dup c sau NULL dac c
nu apare n destinaie (i s-au copiat cnt octei)
void*
Efect: copiaz cnt octei din zona de
memmove
memorie
src n dest (nu neaprat disjuncte).
(void *dest,
Rezultat: adresa surs src.
void
*src,
unsigned
cnt)
void*
Efect: caut valoarea c n primii cnt
memchr (void octei din zona de memorie src
*src, int c,
Rezultat: adresa octetului c sau NULL
unsigned
dac c nu a fost gsit
cnt)
void*
Efect: scrie valoarea c n primii cnt
memset (void octei din zona de memorie dest
*dest,
int
Rezultat: adresa destinaie dest
c,
unsigned
cnt)
int
Efect: compar n ordine cel mult cnt

165

Pointeri i gestiunea dinamic a memoriei


memcmp (void octei din zonele de memorie src1 i src2
*src1,
void
Rezultat: valoarea 0 dac informaia din
*src2,
src1 este identic cu cea din src2; o valoare
unsigned
negativ dac primul octet diferit din src1 este
cnt)

mai mic dect octetul corespunztor din src2; o


valoare pozitiv dac primul octet diferit din src1
este mai mare dect octetul corespunztor din
src2
int
Efect: compar n ordine cel mult cnt
memicmp
octei
din
zonele de memorie src1 i src2, fr a
(void *src1,
face
distincie
ntre literele mari i mici.
void
*src2,
Rezultat: valoarea 0 dac informaia din
unsigned
cnt)
src1 este la fel cu cea din src2; o valoare
negativ dac primul octet diferit din src1 este
mai mic dect octetul corespunztor din src2; o
valoare pozitiv dac primul octet diferit din src1
este mai mare dect octetul corespunztor din
src2
De exemplu, pentru a copia coninutul unui vector de
numere ntregi cu 20 de elemente n alt vector putem folosi
urmtoare secven de program:
int src[20], dest[20];
...
memcpy(dest, src, sizeof(src));

8.7. Exemple
82. Programul urmtor citete un vector de dimensiune n (n citit
de la tastatura) i l afieaz n ordine invers. Dimensiunea
maxim a vectorului depinde doar de memoria calculatorului,
nefiind fixat la compilare. Accesul la elementele vectorului se
face prin pointeri i operatorul de derefereniere.
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
int main()
{
int n, i;

166

Bazele programrii calculatoarelor


int *vector;
printf("Dimensiunea vectorului n:");
scanf("%i", &n);
vector = (int*) malloc(sizeof(int) * n);
for(i=0; i<n; ++i) {
printf("Introduceti v[%d]:", i);
scanf("%i", vector + i);
}
for(i=n - 1; i>=0; --i)
printf("v[%i] = %i\n", i, *(vector + i));

free(vector);
getch();

Rezultatul execuiei programului este:


Dimensiunea
Introduceti
Introduceti
Introduceti
Introduceti
Introduceti
Introduceti
v[5] = 6
v[4] = 5
v[3] = 4
v[2] = 3
v[1] = 2
v[0] = 1

vectorului n:6
v[0]:1
v[1]:2
v[2]:3
v[3]:4
v[4]:5
v[5]:6

83. Urmtorul program citete un vector de n numere i verific


dac este palindrom. Dimensiunea maxim a vectorului depinde
doar de memoria calculatorului, nefiind fixat la compilare.
Accesul la elementele vectorului se face prin pointeri i operatorul
de indexare.
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
int main()
{
int n, i, pal=1;
int *vector;
printf("Dimensiunea vectorului n:");
scanf("%i", &n);

167

Pointeri i gestiunea dinamic a memoriei


vector = (int*) malloc(sizeof(int) * n);
for(i=0; i<n; ++i) {
printf("Introduceti v[%d]:", i);
scanf("%i", &vector[i]);
}
for(i=0; i<n/2 && pal == 1; ++i)
if(vector[i] != vector[n-i-1])
pal = 0;
if(pal == 1)
printf("Vectorul este palindrom.\n");
else
printf("Vectorul nu este palindrom.\n");
free(vector);
getch();
}

Rezultatul execuiei programului este:


Dimensiunea vectorului n:5
Introduceti v[0]:1
Introduceti v[1]:5
Introduceti v[2]:3
Introduceti v[3]:5
Introduceti v[4]:1
Vectorul este palindrom.

84. Urmtorul program determin ordinea valorilor x i y ntr-un


vector de ntregi, folosind pointeri ctre tipul ntreg.
// Ordinea aparitiei valorilor x si y intr-un vector
de intregi
#include "stdio.h"
#include "conio.h"
int main()
{
int *p,*q,a[50],x,y,i,n;
p=a;
q=a;
printf(" n = ");
scanf("%d",&n);
for(i=0;i<n;i++)
{
printf(" a[%d]= ",i);
scanf("%d",a+i);
}
printf(" x = "); scanf("%d",&x);
printf(" y = "); scanf("%d",&y);

168

Bazele programrii calculatoarelor


if(x!=y)
{
while( *p!=x && p<=a+n ) p++;
while( *q!=y && q<=a+n ) q++;
if(p==a+n+1 || q==a+n+1)
printf(" %d sau %d nu este
componenta a sirului \n",x,y);
else
if(p>q) printf(" y = %d
precede x = %d \n",y,x);
else
printf(" x = %d
precede y = %d \n",x,y);
getch();
}
else printf(" x = y \n");
printf(" Sfarsit \n");
getch();
}

Un exemplu de rulare este urmtorul:


n = 5
a[0]= -12
a[1]= 3
a[2]= 21
a[3]= 54
a[4]= -2
x = 54
y = 3
y = 3 precede x = 54

85. Algoritmul de sortare prin numarare count_sort.


Presupunem c dorim s sortm n numere naturale din intervalul
[1, m]. Algoritmul const n construirea unui vector v al
frecventelor de apariie, n care v[i] este egal cu numrul
apariiilor numrului i. Cele n numere pot fi ordonate folosind
frecventele lor de apariie. De exemplu (n=7 i m=7) s
presupunem c dorim s sortm elementele din mulimea {7, 2, 2,
2, 3, 4, 4}. Se construiete vectorul frecventelor v[1]=0 (1 nu este
n mulime), v[2]=3 (2 apare de trei ori), v[3]=1, v[4]=2, v[5]=0,
v[6]=0, v[7]=1. Pentru fiecare i cu proprietatea v[i]!=0, se afieaz
i de v[i] ori. Vectorul sortat va fi 2, 2, 2, 3, 4, 4, 7.
169

Pointeri i gestiunea dinamic a memoriei


//Sortare crescatoare prin metoda de numarare
count_sort
#include <stdio.h>
#include <malloc.h>
// Prototipurile functiilor folosite in program
void citeste_numere(int *, int, int); // citirea
celor n numere naturale cuprinse intre 1 si 100
void init_v(int *, int); // initializarea vectorului
frecventelor
void count_sort(int *, int *, int,int); //functia
pentru sortare prin numarare
void afis_sortc(int *, int); //functia de afisare
crescatoare a celor n numere sortate
void afis_sortd(int *, int); //functia de afisare
descrescatoare a celor n numere sortate
// Functia pentru citirea vectorului
void citeste_numere(int x[],int n, int m)
{
int i;
for(i=0;i<n;i++) {
printf(" Numarul %d = ",i+1);
scanf("%d",x+i);
if(x[i] <= 0 || x[i] > m) {
printf(" Numarul %d nu
este in domeniu \n",x[i]);
break;
}
}
}
// Functia de initializare a vectorului frecventelor
void init_v(int v[], int m)
{
int i;
for(i=1;i<=m;v[i]=0,i++);
}
// Functia count de sortare
void count_sort(int x[], int v[], int n, int m)
{
int i,f,k;
printf(" Sortare \n");
for( k= 1 ; k <= m ; k++ ) {

170

Bazele programrii calculatoarelor


f=0;
for(i = 0;i < n;i++)
if(x[i]==k) f++;
v[k]=f;

}
// Functia pentru afisarea crescatoare a numerelor
void afis_sortc(int v[], int m)
{
int i,k;
printf(" Afisare crescatoare \n");
for(i=1;i <= m;i++) {
if(v[i]!=0)
for(k=1;k<=v[i];k++)
printf("%d ",i);
}
printf("\n");
}
// Functia pentru afisarea descrescatoare a
numerelor
void afis_sortd(int v[], int m)
{
int i,k;
printf(" Afisare descrescatoare \n");
for(i=m;i >= 1 ;i--) {
if(v[i]!=0)
for(k=1;k<=v[i];k++)
printf("%d ",i);
}
printf("\n");
}
// Vectorul numere (alocat dinamic) contine numerele
citite
// Vectorul v este vectorul (alocat dinamic)
// frecventelor numerelor in vectorul numere
// n numarul de numere citite
// nmax si m limitele lui n respectiv a valorilor
numerelor citite
int main()
{
long int nmax = 1000000;
int n, m = 100, *numere, *v;

171

Pointeri i gestiunea dinamic a memoriei


char c;// variabila folosita in evitarea
utilizarii functiei getch()
printf(" n = ");
scanf("%d",&n);
//testul valorii lui n
if(n > 0 && n < nmax) {
//alocare memorie pentru vectorul de numere care
se va citi
if(numere=(int *)malloc(n*sizeof(int)))
{
// citire numere
citeste_numere(numere,n,m);
//alocare memorie pentru vectorul frecventelor
if(v=(int *)malloc(m*sizeof(int)))
{
//initializare vector frecvente
init_v(v,m);
//sortarea prin numarare
count_sort(numere,v,n,m);
//afisarea crescatoare a vectorului sortat
afis_sortc(v,m);
//afisarea descrescatoare a vectorului sortat
afis_sortd(v,m);
//eliberarea zonelor de memorie alocate
free(numere);
free(v);
}
else printf(" Alocare esuata \n");
}
else printf(" Alocare esuata \n");}
else printf(" Numarul %d nu este in domeniu
\n",n);
scanf("%c%c",&c,&c);// Asteptare un caracter
}

Un exemplu de rulare a programului este:


n = 7
Numarul
Numarul
Numarul
Numarul
Numarul
Numarul
Numarul
Sortare

172

1
2
3
4
5
6
7

=
=
=
=
=
=
=

7
2
2
2
3
4
4

Bazele programrii calculatoarelor


Afisare crescatoare
2 2 2 3 4 4 7
Afisare descrescatoare
7 4 4 3 2 2 2

86. Urmtorul program citete un vector de n numere ntregi (n


citit de la tastatur) i calculeaz valoarea SAU exclusiv ntre
toate elementele vectorului.
#include<stdio.h>
#include<stdlib.h>
#include<conio.h>
int main()
{
int n, i, r = 0;
int *vector;
printf("Dimensiunea vectorului n:");
scanf("%i", &n);
vector = (int*) malloc(sizeof(int) * n);
for(i=0; i<n; ++i) {
printf("Introduceti v[%d]:", i);
scanf("%i", vector + i);
}
for(i=0; i<n; ++i)
r ^= *(vector + i);
printf("Rezultat: %d", r);
free(vector);
getch();
}

Rezultatul execuiei programului este:


Dimensiunea
Introduceti
Introduceti
Introduceti
Introduceti
Introduceti
Rezultat: 5

vectorului n:5
v[0]:1
v[1]:2
v[2]:3
v[3]:7
v[4]:2

8.8. Exerciii
74. Scriei o funcie care primete ca parametri dou numere
naturale m i n i citete de la tastatur o matrice de numere
reale de dimensiune m x n. Memoria necesar pentru stocarea
173

Pointeri i gestiunea dinamic a memoriei

matricei trebuie alocat dinamic de ctre funcie. Scriei un


program C care testeaz funcia.
75. Scriei o funcie care permite adunarea a dou matrice i un
program C care testeaz funcia. Memoria necesar pentru
stocarea rezultatului trebuie alocat dinamic de ctre funcie.
76. Scriei o funcie care permite nmulirea a dou matrice i un
program C care testeaz funcia. Memoria necesar pentru
stocarea rezultatului trebuie alocat dinamic de ctre funcie.
77. Scriei o funcie care primete ca parametru un pointer la
caractere i returneaz numrul de caractere de la acea locaie
pn la primul caracter NUL (cu codul ASCII 0).
78. Scriei o funcie care primete ca parametru doi pointeri la
caractere i copiaz caracter cu caracter, coninutul zonei de
memorie indicate de primul pointer n zona de memorie indicat
de al doilea pointer. Copierea se oprete dup primul caracter
NUL (cu codul ASCII 0).

174

Bazele programrii calculatoarelor

99.. FFUUNNCCIIII PPEENNTTRRUU IIRRUURRII DDEE CCAARRAACCTTEERREE


9.1. iruri de caractere
n limbajul C, un ir de caractere este de fapt un vector de
caractere, ultimul caracter fiind caracterul NUL, care are codul
ASCII 0. n general, irurile de caractere se scriu ntre ghilimele
sub form de secvene de caractere normale i secvene escape
(e.g. "acesta este un sir"). Tipul irurilor de caractere este
char[], adic vector de caractere, dar avnd n vedere relaia
ntre tablouri i pointer, putem scrie char*, adic pointer la date
de tip caracter. De exemplu, conform tabelului cu codurile ASCII
din Anexa 2 Setul de caractere ASCII, irul de caractere
"Limbajul C" este stocat n memoria calculatorului astfel:
76 105 109 98 97 106 117 108 32 67 0

Acest lucru poate fi verificat uor cu urmtorul program:


#include <stdio.h>
#include <conio.h>
int main()
{
int i;
char sir[] = "Limbajul C";
for(i=0; i<=10; ++i)
printf("%d ", sir[i]);
getch();
}

9.2. Funcii pentru iruri de caractere


Dac dorim ca irurile de caractere pe care le afim s
fie create dinamic, n funcie de anumite condiii, sau s fie
preluate de la utilizator, sau s efectum anumite operaii cu ele,
atunci trebuie s folosim funcii specializate pentru aceste lucruri.
Funciile standard pentru prelucrarea irurilor de
caractere se gsesc n biblioteca string.h. n prototipurile
acestor funcii, parametrul c de tip int reprezint de fapt un
caracter (sau un octet).
175

Funcii pentru iruri de caractere


Tabel 9.1 Funcii standard pentru iruri de caractere

Prototi
p

Descriere

unsign
Efect: calculeaz lungimea irului de
ed
strlen caractere sir
(char *sir)

Rezultat: lungimea irului de caractere

sir
char*
Efect: transform majusculele din irul
strlwr (char sir n minuscule
*sir)

Rezultat: adresa irului modificat (adic

sir)
char*
Efect: transform minusculele din irul
strupr (char sir n majuscule
*sir)

Rezultat: adresa irului modificat (adic

sir)
char*
strcat (char dest
*dest,
char
*src)

Efect: adaug irul src la sfritul irului


Rezultat: adresa irului modificat (adic

dest)

char*
Efect: adaug cel mult cnt caractere din
strncat
irul src la sfritul irului dest
(char *dest,
Rezultat: adresa irului modificat (adic
char
*src,
dest)
unsigned
cnt)
char*
Efect: caut prima apariie n irul src a
strchr (char caracterului c.
*src, int c)

Rezultat: adresa caracterului c sau


NULL dac c nu a fost gsit
char*
Efect: caut ultima apariie n irul src a
strrchr
caracterului
c.
(char
*src,
Rezultat: adresa caracterului c sau
int c)
NULL dac c nu a fost gsit
char*
Efect: caut prima apariie n irul src a
strstr (char subirului sub.
*src,
char
Rezultat: adresa irului sub n src sau
*sub)
NULL dac sub nu a fost gsit
176

Bazele programrii calculatoarelor


char*
Efect: inverseaz irul (va fi scris de la
strrev (char coada la cap)
*sir)

Rezultat: adresa irului modificat (adic

sir)
char*
Efect: copiaz irul src n irul dest
strcpy (char
Rezultat: adresa irului modificat (adic
*dest,
char
dest)
*src)
char*
Efect: copiaz cel mult cnt caractere din
strncpy
irul
src
n irul dest (numrul de caractere
(char *dest,
char
*src, copiate este minimul dintre cnt i lungimea
irului src).
unsigned
cnt)
Rezultat: adresa irului modificat (adic

dest)
char*
Efect: copiaz irul src ntr-o zon de
strdup (char memorie alocat cu malloc; programatorul
*src)
trebuie s elibereze cu funcia free zona de

char*
strset (char
*dest,
int
c)

memorie cnd nu o mai folosete.


Rezultat: adresa zonei de memorie
alocat
Efect: scrie caracterul c n fiecare
poziie din irul dest.
Rezultat: adresa irului modificat (adic
dest)
Efect: scrie caracterul c n primele cnt
poziii din irul dest.
Rezultat: adresa irului modificat (adic
dest)

char*
strnset
(char *dest,
int
c,
unsigned
cnt)
char*
Efect: compar caracterele din irurile
strcmp (char src1 i src2
*src1,
char
Rezultat: valoarea 0 dac irurile src1 i
*src2)

src2 sunt identice; o valoare negativ dac


primul caracter diferit din src1 este mai mic
dect caracterul corespunztor din src2; o
valoare pozitiv dac primul caractere diferit din
src1 este mai mare dect caracterul
corespunztor din src2.
177

Funcii pentru iruri de caractere


char*
Efect: compar caracterele din irurile
stricmp
src1
i
src2,
fr a face distincie ntre literele
(char *src1,
mari i mici.
char *src2)

Rezultat: valoarea 0 dac irurile src1 i


src2 sunt la fel; o valoare negativ dac primul
caracter diferit din src1 este mai mic dect
caracterul corespunztor din src2; o valoare
pozitiv dac primul caractere diferit din src1
este mai mare dect caracterul corespunztor
din src2.
char*
Efect: compar cel mult cnt caractere
strncmp
din irurile src1 i src2
(char *src1,
Rezultat: valoarea 0 dac irurile src1 i
char
*src2,
src2 sunt identice n zona comparat; o valoare
unsigned
cnt)
negativ dac primul caracter diferit din src1
este mai mic dect caracterul corespunztor din
src2; o valoare pozitiv dac primul caractere
diferit din src1 este mai mare dect caracterul
corespunztor din src2.
char*
Efect: compar cel mult cnt caractere
strnicmp
din irurile src1 i src2, fr a face distincie
(char *src1,
char
*src2, ntre literele mari i mici.
Rezultat: valoarea 0 dac irurile src1 i
unsigned
cnt)
src2 sunt la fel n zona comparat; o valoare
negativ dac primul caracter diferit din src1
este mai mic dect caracterul corespunztor din
src2; o valoare pozitiv dac primul caractere
diferit din src1 este mai mare dect caracterul
corespunztor din src2.
Secvena urmtoare de program exemplific utilizarea
funciilor pentru iruri de caractere prezentate anterior:
char s1[] = "Limba",
int n;
n = strlen(s1);
n = strcmp(s1, s2);
strlwr(s1);
n = strcmp(s1, s2);

178

s2="Limbajul C", *s3;


//
//
//
//

n este 5
n este -1
s1 este "limba"
n este 1

Bazele programrii calculatoarelor


strupr(s1);
// s1 este "LIMBA"
n = strnicmp(s1, s2, 5); // n este 0
s3 = strstr(s2, " "); // s3 este subsirul " C" din s2
strcat(s1, s3);
// s1 este "LIMBA C"
strnset(s1, '#');
// s1 este "#######"
strcpy(s3, s1);
// s3 este "#######", deci
// s2 este "Limbajul#######"

9.3. Funcii pentru clasificarea caracterelor


n afar de funciile pentru iruri de caractere, biblioteca
standard ctype.h ofer diverse funcii pentru testarea categoriei
unui caracter (dac e majuscul, minuscul, cifr, etc.) i
eventual transformarea acestuia (din majuscule n minuscule i
invers). Aceste funcii primesc ca unic parametru caracterul care
trebuie testat sau modificat.
Tabel 9.2 Funcii standard pentru clasificarea caracterelor

Prot
otip
int
isalpha
(int c)
int
islower
(int c)
int
isupper
(int c)
int
isdigit
(int c)
int
isxdigit
(int c)
int
isalnum
(int c)
int
isblank

Descriere
Efect: testeaz dac c este o liter
Rezultat: 1 dac c este liter, 0 altfel
Efect: testeaz dac c este o minuscul
Rezultat: 1 dac c este minuscul, 0 altfel
Efect: testeaz dac c este o majuscul
Rezultat: 1 dac c este majuscul, 0 altfel
Efect: testeaz dac c este o cifr
Rezultat: 1 dac c este cifr, 0 altfel
Efect: testeaz dac c este o cifr
hexazecimal
Rezultat: 1 dac c este hexazecimal, 0
altfel
Efect: testeaz dac c este liter sau cifr
(echivalent cu expresia isalpha(c) || isdigit(c))
Rezultat: 1 dac c este liter sau cifr, 0
altfel
Efect: testeaz dac c este caracter gol
179

Funcii pentru iruri de caractere


(int c)
(spaiu sau tab)

Rezultat: 1 dac c este caracter gol, 0


altfel
int
isspace
(int c)

int
iscntrl
(int c)
int
ispunct
(int c)
int
isgraph
(int c)
int
isprint
(int c)
int
tolower
(int c)
int
toupper
(int c)

180

Efect: testeaz dac c este caracter de


spaiere (spaiu, tab, new line, vertical tab, form
feed sau carriage return)
Rezultat: 1 dac c este caracter de
spaiere, 0 altfel
Efect: testeaz dac c este caracter de
control (adic are codul ASCII ntre 0 i 31)
Rezultat: 1 dac c este caracter de
control, 0 altfel
Efect: testeaz dac c este caracter de
punctuaie
Rezultat: 1 dac c este caracter de
punctuaie, 0 altfel
Efect: testeaz dac c are o reprezentare
grafic (adic este caracter tipribil vizibil).
Rezultat: 1 dac c are reprezentare
grafic, 0 altfel
Efect: testeaz dac c este un caracter
afiabil
Rezultat: 1 dac c este caracter afiabil, 0
altfel
Efect: testeaz dac c este majuscul i
returneaz minuscula corespunztoare
Rezultat: minuscula corespunztoare lui
c, dac c este majuscul, sau valoarea lui c, altfel
Efect: testeaz dac c este minuscul i
returneaz majuscula corespunztoare
Rezultat: majuscula corespunztoare lui
c, dac c este minuscul, sau valoarea lui c, altfel

Bazele programrii calculatoarelor

9.4. Exemple
87. Programul urmtor citete un mesaj de la tastatur i
afieaz un extras din acesta. Extrasul este specificat prin poziia
de nceput i lungimea maxim admis.
#include <stdio.h>
#include <string.h>
#include <conio.h>
int main()
{
char mesaj[256], extras[256];
int i, n, l;
printf("Introduceti un text:\n");
gets(mesaj);
printf("Pozitie de start: ");
scanf("%i", &n);
printf("Lungime: ");
scanf("%i", &l);
i = 0;
do {
extras[i] = mesaj[i+n];
++i;
} while(extras[i-1] != 0 && i<l);
printf("Extras: %s", extras);
getch();
}
Introduceti un text:
Limbajul C are doar 32 de instructiuni!
Pozitie de start: 9
Lungime: 10
Extras: C are doar

88. Programul urmtor citete un mesaj de la tastatur i


afieaz mesajul n oglind (de la dreapta la stnga).
#include <stdio.h>
#include <conio.h>
#include <string.h>
int main()
{
char mesaj[256];
int i, len;
printf("Introduceti un text:\n");
gets(mesaj);

181

Funcii pentru iruri de caractere


len = strlen(mesaj);
for(i = 0; i<len/2; ++i) {
char temp = mesaj[i];
mesaj[i] = mesaj[len - i - 1];
mesaj[len - i - 1] = temp;
}
printf("Rezultat:\n%s", mesaj);
getch();
}
Introduceti un text:
Limbajul C
Rezultat:
C lujabmiL

89. Programul urmtor citete un mesaj de la tastatur i un


numr ntreg n i afieaz mesajul codificat prin nlocuirea
fiecrui caracter cu caracterul aflat la distan n n tabela
codurilor ASCII.
#include <stdio.h>
#include <string.h>
#include <conio.h>
int main()
{
char mesaj[256];
int i, len, n;
printf("Introduceti un text:\n");
gets(mesaj);
printf("Introduceti n:");
scanf("%d", &n);
len = strlen(mesaj);
for(i = 0; i<len; ++i)
mesaj[i] += n;
printf("Rezultat:\n%s", mesaj);
getch();
}
Introduceti un text:
Limbajul C
Introduceti n:1
Rezultat:
Mjncbkvm!D

De remarcat, c un mesaj codificat cu valoarea n poate fi


decodificat cu valoarea -n.
182

Bazele programrii calculatoarelor


Introduceti un text:
Mjncbkvm!D
Introduceti n:-1
Rezultat:
Limbajul C

90. Programul urmtor verific dac un ir este palindrom (adic


citit de la dreapta la stnga i de la stnga la dreapta obinem
acelai cuvnt).
#include <stdio.h>
#include <string.h>
#include <conio.h>
int main()
{
char mesaj[256];
int i, len, pal = 1;
printf("Introduceti un text:\n");
gets(mesaj);
len = strlen(mesaj);
for(i = 0; i<len/2; ++i)
if(mesaj[i] != mesaj[len - i - 1])
pal = 0;
if(pal == 1)
printf("Sirul este palindron.");
else
printf("Sirul nu este palindrom.");
getch();
}
Introduceti un text:
capac
Sirul este palindrom.

91. Programul urmtor verific dac un ir este palindrom fr a


face diferene ntre majuscule i minuscule, folosind funciile
bibliotecii string.h.
#include <stdio.h>
#include <string.h>
#include <conio.h>
int main()
{
char mesaj[256], oglinda[256];
int i, len;
printf("Introduceti un text:\n");

183

Funcii pentru iruri de caractere


gets(mesaj);
strcpy(oglinda, mesaj);
strrev(oglinda);
if(stricmp(oglinda, mesaj) == 0)
printf("Sirul este palindron.");
else
printf("Sirul nu este palindron.");
getch();
}

92. Programul urmtor citete un mesaj de la tastatur i


elimin din acesta prima apariie a unui subir citit tot de la
tastatur.
#include <stdio.h>
#include <string.h>
#include <conio.h>
int main()
{
char mesaj[256], subsir[50], *inceput;
int i, len;
printf("Introduceti un text:\n");
gets(mesaj);
printf("Introduceti subsirul:\n");
gets(subsir);
inceput = strstr(mesaj, subsir);
if(inceput != NULL) {
len = strlen(subsir);
strcpy(inceput, inceput+len);
}
printf("Rezultat:\n%s", mesaj);
getch();
}
Introduceti un text:
Limbajul C are doar 32 de instructiuni!
Introduceti subsirul:
doar 32 de
Rezultat:
Limbajul C are instructiuni!

93. Programul urmtor afieaz cuvintelor dintr-un ir


caractere cte unul pe linie. n acest context, un cuvnt este
ir de caractere cuprins ntre doi separatori. Prin separator
nelege aici, orice caracter. Programul primete la intrare un
184

de
un
se
ir

Bazele programrii calculatoarelor

de caractere, o list de separatori i afieaz cuvintele din irul


introdus.
#include <stdio.h>
#include <string.h>
#include <conio.h>
int main()
{
char sir[100], sep[10], *pozitie;
printf("Introduceti textul");
gets(sir);
printf("Introduceti separatorii");
gets(sep);
printf(" Cuvintele din text sunt: \n");
pozitie=strtok(sir, sep);
while(pozitie) {
printf("%s\n", pozitie);
pozitie=strtok(NULL,sep);
}
getch();
}

Un exemplu de rulare este:


Introduceti textul:
Limbajul C are doar 32 de instructiuni!
Introduceti separatorii:
a d
Cuvintele din text sunt:
Limb
jul
C
re
o
r
32
e
instructiuni!

94. Programul urmtor citete un mesaj de la tastatur i


afieaz statistici despre acesta (lungimea total, numrul de
majuscule, minuscule, cifre, semne de punctuaie i caractere de
spaiere):
#include <stdio.h>
#include <string.h>

185

Funcii pentru iruri de caractere


#include <ctype.h>
#include <conio.h>
int main()
{
char mesaj[256];
int i, len, maj, min, cif, pct, spa;
printf("Introduceti un text:\n");
gets(mesaj);
len = strlen(mesaj);
maj = min = cif = pct = spa = 0;
for(i = 0; i<len; ++i)
if(islower(mesaj[i])) ++maj;
else if(isupper(mesaj[i])) ++min;
else if(isdigit(mesaj[i])) ++cif;
else if(ispunct(mesaj[i])) ++pct;
else if(isspace(mesaj[i])) ++spa;
printf("Lungime: %d\n", len);
printf("Majuscule: %d\n", maj);
printf("Minuscule: %d\n", min);
printf("Cifre: %d\n", cif);
printf("Semne de punctuatie: %d\n", pct);
printf("Spatii: %d\n", spa);
getch();
}
Introduceti un text:
Limbajul C are doar 32 de instructiuni!
Lungime: 39
Majuscule: 28
Minuscule: 2
Cifre: 2
Semne de punctuatie: 1
Spatii: 6

95. Programul urmtor transform un ir de caractere citit de la


tastatur astfel nct fiecare cuvnt s nceap cu o majuscul i
s conin n rest doar minuscule. Variabila cuvantnou este
folosit pentru afla dac prelucrm caracterele din interiorul unui
cuvnt, sau urmeaz s ncep un cuvnt nou.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
int main()
{

186

Bazele programrii calculatoarelor


char mesaj[256];
int i, len, cuvantnou = 1;
printf("Introduceti un text:\n");
gets(mesaj);
len = strlen(mesaj);
for(i = 0; i<len; ++i)
if(isalpha(mesaj[i]))
if(cuvantnou){
mesaj[i] = toupper(mesaj[i]);
cuvantnou = 0;
}else{
mesaj[i] = tolower(mesaj[i]);
}
else
cuvantnou = 1;
printf("Rezultat:\n%s", mesaj);
getch();
}
Introduceti un text:
limbajul c are doar 32 de instructiuni!
Rezultat:
Limbajul C Are Doar 32 De Instructiuni!

96. Funcie pentru nlocuirea unui caracter c dintr-un ir de


caractere, cu un alt caracter. Funcia nlocuiete toate apariiile
caracterului c n ir. Dac c nu a fost gsit se emite un mesaj.
/ Inlocuire caracter in sir de caractere
#include "stdio.h"
#include "conio.h"
#include "string.h"
int inlocuire(char *x, char cs, char cd)
{
int i,k,gasit;
i=0;
gasit=0;
for(i=0;i<strlen(x);i++)
{
if(*(x+i)==cs)
{
gasit=1;
*(x+i)=cd;
}}
if(gasit) return 1;
else return 0;

187

Funcii pentru iruri de caractere


}
int main()
{
char sir[200],cars,card;
puts(" Sirul ");
gets(sir);
puts(" Caracterul de inlocuit ");
cars=getche();
puts("\n Caracterul cu care inlocuiesc ");
card=getche();
if(inlocuire(sir,cars,card))
{
puts("\n Sirul modificat ");
puts(sir);
}
else
printf("\n Caracterul %c nu a fost gasit in
sirul %s \n",cars,sir);
getch();
}

Un exemplu de rulare este urmtorul:


Sirul
inlocuire caracter
Caracterul de inlocuit
c
Caracterul cu care inlocuiesc
?
Sirul modificat
inlo?uire ?ara?ter
Sirul
abac
Caracterul de inlocuit
!
Caracterul cu care inlocuiesc
?
Caracterul ! nu a fost gasit in sirul abac

97. Funcie pentru inserarea unui ir surs ntr-un ir destinaie


dup caracterul aflat pe poziia n n irul destinaie. Dac n=-1 se
insereaz irul surs n faa irului destinaie. Dac n este egal cu
lungimea irului destinaie minus 1 se obine concatenarea celor
dou iruri.
188

Bazele programrii calculatoarelor


//Inserare sir sursa in sir destinatie dupa pozitia
n
// Pentru n=-1 se insereaza in fata destinatiei
// Pentru n=(lungimea destinatiei - 1) se obtine
concatenare
#include "stdio.h"
#include "conio.h"
void insert(char *d, char *s, int n)
{
int is,id,im;
char m[100];
im=0;
id=n+1;
while(*(d+id)!='\0')
{
m[im]=*(d+id);
id++;
im++;
}
id=n+1;
m[im]='\0';
is=0;
while(*(s+is)!='\0')
{
*(d+id)=*(s+is);
id++;
is++;
}
im=0;
while(*(m+im)!='\0')
{
*(d+id)=*(m+im);
id++;
im++;
}
*(d+id)='\0';
}
int main()
{
char sird[100],sirs[100];
int n;
puts(" Sirul sursa ");
gets(sirs);
puts(" Sirul destinatie ");
gets(sird);
puts(" Pozitia de inceput a inserarii ");

189

Funcii pentru iruri de caractere


scanf("%d",&n);
insert(sird,sirs,n);
puts(sird);
getch();
}

Un exemplu de rulare este:


Sirul sursa
sir sursa
Sirul destinatie
sir destinatie
Pozitia de inceput a inserarii
-1
sir sursa sir destinatie
Sirul sursa
sir sursa
Sirul destinatie
sir destinatie
Pozitia de inceput a inserarii
3
sir sir sursa destinatie
Sirul sursa
sir sursa
Sirul destinatie
sir destinatie
Pozitia de inceput a inserarii
14
sir destinatie sir sursa

98. Funcie pentru tergerea tuturor apariiilor unui caracter


dintr-un ir de caractere. Dac irul nu conine caracterul
respectiv se emite un mesaj corespunztor.
// Stergere caracter
#include "stdio.h"
#include "conio.h"
#include "string.h"
int sterg(char *x, char c)
{
int i,k,j,este;
i=0;este=0;
while(i<strlen(x))
{

190

Bazele programrii calculatoarelor


j=i;
while(*(x+j)==c)
{
este=1;
for(k=j;*(x+k)!='\0';k++)
*(x+k)=*(x+k+1);
*(x+k+1)='\0';
}i++;}
return este;
}
int main()
{
char sir[200],sirm[200],car;
puts(" Sirul ");
gets(sir);
strcpy(sirm,sir);
puts(" Caracterul care va fi sters ");
scanf("%c",&car);
if(sterg(sir,car))
{
printf(" Caracterul %c a fost garsit in sirul %s
\n",car,sirm);
puts(" Sirul modificat ");
puts(sir);
}
else
printf(" Caracterul %c nu a fost gasit in sirul %s
\n",car,sir);
getch();
}

Un exemplu de rulare este:


Sirul
stergere caracter
Caracterul care va fi sters
c
Caracterul c a fost garsit in sirul stergere
caracter
Sirul modificat
stergere arater
Sirul
stergere caracter
Caracterul care va fi sters
#

191

Funcii pentru iruri de caractere


Caracterul # nu a fost gasit in sirul stergere
caracter

99. Programul urmtor transform toate minusculele unui ir de


caractere n majuscule i apoi, toate majusculele n minuscule.
// Minuscule majuscule
#include "stdio.h"
#include "conio.h"
#include "ctype.h"
void schimb_m_M(char x[])// minuscule in majuscule
{
int i;
i=0;
while(x[i]!='\0')
{
x[i]=toupper(x[i]);
i++;
}}
void schimb_M_m(char x[])// majuscule in minuscule
{
int i;
i=0;
while(x[i]!='\0')
{
x[i]=tolower(x[i]);
i++;
}}
int main()
{
char s[100];
puts(" Tastati un sir de caractere ");
gets(s);
schimb_m_M(s);
printf(" Transformarea tuturor minusculelor in
majuscule\n");
puts(" Sirul modificat este ");
puts(s);
getch();
schimb_M_m(s);
printf(" Transformarea tuturor majusculelor in
minuscule\n");
puts(" Sirul modificat este ");
puts(s);
getch();
}

192

Bazele programrii calculatoarelor

Un exemplu de rulare este:


Tastati un sir de caractere
TransFormare minuscule - MAJUSCULE
Transformarea tuturor minusculelor in majuscule
Sirul modificat este
TRANSFORMARE MINUSCULE - MAJUSCULE
Transformarea tuturor majusculelor in minuscule
Sirul modificat este
transformare minuscule - majuscule

100. Programul urmtor transform un ir de caractere citit de la


tastatur astfel nct primul cuvnt din fiecare fraz s nceap cu
majuscul, restul literelor fiind minuscule. Variabila frazanoua
este folosit pentru afla dac prelucrm caracterele din interiorul
unei fraze, sau urmeaz s ncepem o fraz nou.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <conio.h>
int main()
{
char mesaj[256];
int i, len, frazanoua = 1;
printf("Introduceti un text:\n");
gets(mesaj);
len = strlen(mesaj);
for(i = 0; i<len; ++i)
if(isalpha(mesaj[i]))
if(frazanoua){
mesaj[i] = toupper(mesaj[i]);
frazanoua = 0;
}else{
mesaj[i] = tolower(mesaj[i]);
}
else if(ispunct(mesaj[i]))
frazanoua = 1;
printf("Rezultat:\n%s", mesaj);
getch();
}
Introduceti un text:
limbajul c are putine instructiuni. asta e bine.
Rezultat:
Limbajul c are putine instructiuni. Asta e bine.

193

Funcii pentru iruri de caractere

9.5. Exerciii
79. Scriei un program C care citete de la tastatur un ir de
caractere A i un caracter B, i afieaz numrul de apariii ale
caracterului B n irul A.
80. Scriei un program C care citete de la tastatur dou iruri
de caractere A i B, i afieaz numrul de apariii ale irului B n
irul A.
81. Scriei un program C care citete de la tastatur dou iruri
de caractere A i B, i un numr natural n, i afieaz pe ecran
irul A n care a fost inserat irul B la poziia n.
82. Scriei un program C care citete de la tastatur iruri de
caractere i afieaz pe ecran lungimea i irul respectiv. Citirea
se oprete la introducerea irului vid (cu lungime 0) de ctre
utilizator.
83. Scriei un program C care citete de la tastatur iruri de
caractere i le afieaz pe ecran nlocuind majusculele cu
minuscule. Citirea se oprete la introducerea irului vid (cu
lungime 0) de ctre utilizator.
84. Scriei un program C care citete o succesiune de cuvinte.
Citirea se oprete la introducerea irului vid (cu lungime 0) de
ctre utilizator. Programul afieaz apoi cuvntul cel mai lung.
85. Scriei un program C care citete o succesiune de cuvinte.
Citirea se oprete la introducerea irului vid (cu lungime 0) de
ctre utilizator. Programul afieaz apoi cuvntul cel mai mare
din punct de vedere lexicografic (de exemplu, "casa" este mai
mare din punct de vedere lexicografic dect "dar").
86. Scriei un program C care citete o succesiune de cuvinte,
le sorteaz n ordine cresctoare i apoi le afieaz n aceast
ordine.

194

Bazele programrii calculatoarelor

1100.. FFUUNNCCIIII M
MA
ATTE
EM
MA
ATTIIC
CE
E
Biblioteca limbajului C pune la dispoziia utilizatorului un
numr de funcii matematice. Aceste funcii au prototipurile n
fiierul antet math.h, stdlib.h i/sau complex.h. Orice program
care folosete astfel de funcii trebuie s conin directivele
compilator:
#include <math.h>
#include <stdlib.h>
#include <complex.h>

mpreun cu aceste funcii, sunt disponibile valorile unor


constante remarcabile din matematic, definite prin constante
simbolice. Vom prezenta n continuare constantele simbolice i
cele mai utilizate dintre aceste funcii.
Tabel 10.1 Constante simbolice

Num

Valoare

Descriere

e
M_E

2.7182818284590

1.4426950408889

log2 e

452354
G2E
G10E
2
10

M_LO

634074
M_LO
M_LN
M_LN
M_PI

_2

M_PI
M_PI

_4

0.4342944819032
5182765
0.6931471805599
4530942
2.3025850929940
4568402
3.1415926535897
9323846
1.5707963267948
9661923
0.7853981633974
4830962

lg e

ln 2
ln10

4
195

Funcii matematice
M_1_
0.3183098861837
PI
9067154
M_2_
PI
M_2_
SQRTPI
M_SQ
RT2
M_SQ
RT1_2

0.6366197723675
8134308
1.1283791670955
1257390

1.4142135623730
9504880
0.7071067811865
4752440

1
2

Tabel 10.2 Funcii trigonometrice

Proto
tip
doub
le
sin
(double x)
doub
le
cos
(double x)
doub
le
asin
(double x)

Funcie
Returneaz sin x n 1,1
Returneaz cos x n 1,1
Returneaz
Argumentul x 1,1

arcsin x


, .
2 2

doub
arccos x
Returneaz
n
0, .
le
acos
(double x)
Argumentul x 1,1
doub

Returneaz tg x n R , x 2k 1 ,
le
tan
2
(double x)

k Z

doub
le
atan
(double x)
doub
le
atan2
(double x,
double y)

196


Returneaz arctg x n ,
2 2
x

Returneaz arctg n ,
2 2
y

Bazele programrii calculatoarelor


Tabel 10.3 Funcii putere i radical

Funcie

Prototi
p
doubl
e
pow
(double
x,
double y)
doubl
e
sqrt
(double x)

Returneaz

xy , x 0

Returneaz

x , x0

Tabel 10.4 Funcii exponeniale, logaritmice, hiperbolice

Funcie

Prototi
p
double
(double

Returneaz e x

double
(double

Returneaz ln x , x 0

double
log10
(double x)
double
log2 (double
x)
double
sinh (double
x)
double
cosh (double
x)
double
tanh (double
x)
double
asinh
(double x)

Returneaz lg x , x 0

exp
x)
log
x)

cosh
x)

double
(double

Returneaz l o g 2 x , x 0

e x e x
2
x
e e x
Returneaz ch( x)
2
sh( x)
Returneaz th( x)
ch( x)
Returneaz
inversa
x
x
e e
sh( x)
2
Returneaz
inversa
x
x
e e
ch( x)
2
Returneaz sh( x)

funciei

funciei

197

Funcii matematice
double
Returneaz
tanh (double
sh
( x)
x)
th( x)

inversa

funciei

ch( x)

Tabel 10.5 Funcii de conversie

Prototip

Descriere

int
atoi
Conversie ir de caractere n
(const char* c)
ntreg
double atof
Conversie ir de caractere n
(const char* c)
double
long
atoll
Conversie ir de caractere n
(const char* c)
ntreg lung
Tabel 10.6 Funcii de rotunjire, trunchiere, modul

Prototi
p

Funcie

double
Returneaz cel mai mare ntreg mai
floor
mic dect x , x
(double x)
double
Returneaz cel mai mic ntreg mai
ceil (double
mare dect x , x
x)
double
Funcie de rotunjire a lui x
round
(double x)
double
Returneaz trunchierea lui x
trunc
(double x)
int
Returneaz x , x Z
abs (int x)
double
Returneaz x , x R
fabs (double
x)
Tabel 10.7 Funcii pentru generare numere aleatoare

Prototi
p
int
rand ()
srand

198

void

Descriere
Returneaz la fiecare apel un numr
natural aleatoriu
Iniializeaz valoarea de start a

Bazele programrii calculatoarelor


(unsigned s)

secvenei de numere aleatoare produse cu


rand.

10.1. Exemple
101. Programul urmtor calculeaz valorile unei funcii reale de o
singur variabil real, ntr-un interval dat. Fie funcia f : R R ,
definit astfel:
2

xe1 x ,
x , 1

2
f x 3 x 1ln 1 x
x 1,1

x 1,
sin x * sh x
Vom scrie programul care calculeaz valorile funciei f
n n 2 puncte din intervalul a , b . Folosind expresia analitic a

funciei f definim funcia f n limbajul C astfel:


double f(double x)
{
if(x<-1) return x*exp(1-pow(x,2));
if(x>=-1 && x<=1) return pow(x+1,1.0/3)*
log(1+pow(x,2));
if(x>1) return sin(x)*sinh(x);
}

Datele de intrare sunt extremitile intervalului


numrul n de puncte din intervalul

a, b

a, b

n care se calculeaz

valorile funciei. Pentru lucrul cu o alt funcie se modific n mod


corespunztor definiia funciei f.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <conio.h>
double f(double x)
{
if(x<-1) return x*exp(1-pow(x,2));
if(x>=-1 && x<=1) return pow(x+1,1.0/3)*
log(1+pow(x,2));
if(x>1) return sin(x)*sinh(x);
}

199

Funcii matematice
int main()
{
double a,b,h,x;
int n,k;
printf("Extremitatile intervalului [a,b] \n");
printf(" a = ");
scanf(%lf, &a);
printf(" b = ");
scanf(%lf, &b);
printf("Numarul de puncte din intervalul (%f,
%f) in care se calculeaza f(x)=", a, b);
scanf("%d",&n);
h=(b-a)/n;
for(k=0,x=a; k<=n+1; x=a+k*h,k++)
printf("%d. f ( %f ) = %f \n",k+1,x,f(x));
getch();
}

Ca exemplu am folosit intervalul 2, 2 i n 10 .


Extremitatile intervalului [a,b]
a = -2
b = 2
Numarul de puncte din intervalul (-2.000000,
2.000000) in care se calculeaza f(x) = 10
1. f ( -2.000000 ) = -0.099574
2. f ( -2.000000 ) = -0.099574
3. f ( -1.600000 ) = -0.336218
4. f ( -1.200000 ) = -0.772844
5. f ( -0.800000 ) = 0.289300
6. f ( -0.400000 ) = 0.125182
7. f ( 0.000000 ) = 0.000000
8. f ( 0.400000 ) = 0.166036
9. f ( 0.800000 ) = 0.601769
10. f ( 1.200000 ) = 1.406877
11. f ( 1.600000 ) = 2.374555
12. f ( 2.000000 ) = 3.297895

102. Program urmtor calculeaz valorile unei funcii reale de


dou variabile reale, ntr-un domeniu dat. Fie funcia f : R 2 R ,
f x, y arctg x y , x, y R 2 . Vom scrie programul care
calculeaz valorile funciei

200

n domeniul

a , b c, d R 2 .

Bazele programrii calculatoarelor


Folosind expresia analitic a funciei f definim funcia f n

limbajul C astfel:
double f(double x, double y)
{
return atan(x+y);
}

Datele de intrare sunt extremitile a,b,c,d ale domeniului,


numrul n de puncte din intervalul a, b i numrul m de puncte
din intervalul c, d n care se calculeaz valorile funciei. Pentru
lucrul cu o alt funcie se modific n mod corespunztor definiia
funciei f.
#include <stdio.h>
#include <math.h>
#include <stdlib.h>
#include <conio.h>
double f(double x, double y)
{
return atan(x+y);
}
int main()
{
double x,y,a,b,c,d,hx,hy;
int n,m,k,p,nrp;
printf("Extremitatile intervalului [a,b]
printf("a = ");
scanf(%lf, &a);
printf("b = ");
scanf(%lf, &b);
printf("Extremitatile intervalului [c,d]
printf("c = ");
scanf(%lf, &c);
printf("d = ");
scanf(%lf, &d);
printf("Numarul de puncte din intervalul
%f) in care se calculeaza f(x,y) = ",a,b);
scanf("%d",&n);
printf("Numarul de puncte din intervalul
%f) in care se calculeaza f(x,y) = ",c,d);
scanf("%d",&m);
hx=(b-a)/n;
hy=(d-c)/m;

\n");

\n");

(%f,
(%f,

201

Funcii matematice
for(k=0,x=a,nrp=1;k<=n;k++,x=a+k*hx)
for(p=0,y=c;p<=m;p++,y=c+p*hy,nrp++)
printf("%d. f ( %f, %f ) = %f\n", nrp,
x, y, f(x,y));
getch();
}

Ca exemplu am folosit domeniul 2,1 3, 4 , n 2 i

m2.
Extremitatile intervalului [a,b]
a = -2
b = 1
Extremitatile intervalului [c,d]
c = -3
d = 4
Numarul de puncte din intervalul (-2.000000,
1.000000) in care se calculeaza f(x) = 2
Numarul de puncte din intervalul (-3.000000,
4.000000) in care se calculeaza f(x) = 2
1. f ( -2.000000, -3.000000 ) = -1.373401
2. f ( -2.000000, 0.500000 ) = -0.982794
3. f ( -2.000000, 4.000000 ) = 1.107149
4. f ( -0.500000, -3.000000 ) = -1.292497
5. f ( -0.500000, 0.500000 ) = 0.000000
6. f ( -0.500000, 4.000000 ) = 1.292497
7. f ( 1.000000, -3.000000 ) = -1.107149
8. f ( 1.000000, 0.500000 ) = 0.982794
9. f ( 1.000000, 4.000000 ) = 1.373401

103. Urmtorul program prezint aproximarea soluiilor ecuaiilor


neliniare cu metoda lui Newton. Fie f : a, b R , f C 2 a, b ,
f x 0 ,

x a, b

i ecuaia f x 0 , care are o singur

rdcin n intervalul a , b . Metoda lui Newton (a tangentei)


const n construirea irului de aproximaii (irul lui Newton):
x0 a, b , care satisface condiia Fourier, f x0 f x0 0 ,
xn1 xn

f xn
, n N . Acest ir este convergent i tinde la
f xn

soluia exact a ecuaiei f x 0 . Dac este pragul de


202

Bazele programrii calculatoarelor

eroare, generarea termenilor irului de aproximaii se termin


xn1 xn . Ca exemplu am considerat funcia
cnd
f : 0,1 R , f x x 3 3 x 1 i ecuaia f x 0 , care are n

intervalul

0,1 o singur soluie.


f x , f x i respectiv

Funciile f, fd, fd2 codific

f x . Funcia recursiv x
funciile
calculeaz termenii irului aproximaiilor.
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
double f(double x)
{
return pow(x,3)-3*x+1;
}
double fd(double x)
{
return 3*pow(x,2)-3;
}
double fd2(double x)
{
return 6*x;
}
double x(int n, double p)
{
if(n==0) return p;
else return x(n-1,p)-f(x(n-1,p))/fd(x(n-1,p));
}
int main()
{
double p, e, eps, a, b;
int n;
printf("Intervalul [a,b]\n");
printf("a = ");
scanf("%lf",&a);
printf("b = ");
scanf("%lf",&b);
if(f(a)*fd2(a)>0) p=a;
if(f(b)*fd2(b)>0) p=b;
printf("Eroarea de aproximare eps : ");
scanf("%d",&eps);
e=eps+1;
n=0;

203

Funcii matematice
while(e>eps) {
printf("x ( %d ) = %f\n",n,x(n,p));
e=fabs(x(n+1,p)-x(n,p));
n++;
}
printf("Numar total de iteratii = %d \n",n-1);
printf("Solutia ecuatiei cu eroarea %f este
%f\n", eps, x(n,p));
getch();
}

Rezultatele rulrii programului sunt urmtoarele:


Intervalul [a,b]
a = 0
b = 1
Eroarea de aproximare eps : 0.00001
x ( 0 ) = 0.000000
x ( 1 ) = 0.333333
x ( 2 ) = 0.347222
x ( 3 ) = 0.347296
Numar total de iteratii = 3
Solutia ecuatiei cu eroarea 0.000010 este 0.347296

104. Urmtorul program prezint o metod pentru aproximarea


b

integralei

f x dx
a

cu metoda Simpson 1/3. Fie f : a, b R ,

continu pe a , b , a ,b x0 , x1,

, x2n o diviziune echidistant a

ba
, xi x0 ih ,
2n
i 1, 2,..., 2n . n aceste condiii, se poate demonstra c are loc
aproximarea
b
n 1
n
h

f
x
dx
~
f
a

f
b

2
f
x

4
f x2 k 1 ,

2k

a
3
k 1
k 1

cunoscut ca fiind formula lui Simpson 1/3, care poate fi uor


programat. Datele de intrare sunt a, b i n . Programul
intervalului

a, b ,

a x0 x1 ... x2n b , h

furnizeaz valoarea aproximativ a integralei

f x dx .
a

204

Ca

Bazele programrii calculatoarelor


1

exemplu vom aproxima

1 x

dx , care are valoarea exact

M_PI_4, adic 0.78539816339744830962. Modificnd n program


definiia funciei f, programul poate fi folosit pentru aproximarea
oricrei integrale.
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
double f(double x)
{
return 1/(x*x+1);
}
int main()
{
double a,b,h,xi,yi,sp,si,valint;
int n, i;
printf("Intervalul de integrare \n");
printf(" a = ");
scanf(%lf, &a);
printf(" b = ");
scanf(%lf, &b);
printf("Numarul nodurilor n = ");
scanf(%i, &n);
h=(b-a)/(2*n);
for(i=0,xi=a,sp=0,si=0;i<=2*n;i++) {
if(i%2==0) si=si+f(xi);
else sp=sp+f(xi);
xi=xi+h;
}
valint=(f(a)+f(b)+4*si+2*sp)*h/3;
printf("Valoarea integralei este %f\n",valint);
getch();
}

Rezultatul rulrii programului este:


Intervalul de integrare
a = 0
b = 1
Numarul nodurilor n = 1000000
Valoarea integralei este 0.785399

205

Funcii matematice

105. Programul urmtor prezint aproximarea valorilor soluiei


ecuaiei difereniale y x f x, y x , x a, b , cu condiia
iniial

y a y0 , cu metoda Euler. Fie ecuaia diferenial

y x f x, y x , x a, b , cu condiia iniial y a y0 . Fie


a ,b x0 , x1 ,..., xn o diviziune echidistant a intervalului

a, b ,

ba
yi y xi
,
xi x0 ih ,
n
i 1, 2,..., n . n aceste condiii, se poate demonstra c valorile
funciei necunoscute y , n punctele diviziunii a ,b , sunt date de
a x0 x1 ... xn b ,

termenii

irului

lui

Euler:

y0 y a ,

yi 1 yi hf xi , yi ,

i 1, 2,..., n . Valorile aproximative sunt cu att mai apropiate de


valorile exacte cu cat n este mai mare. Ca exemplu am
considerat ecuaia diferenial y x 2 xy, y 0 1 . n acest

f x, y 2 xy . Aceast ecuaie are soluia exact

exemplu

y x e x . Programul listeaz, pentru comparaie, valorile exacte


2

ale soluiei i pe cele aproximative. Pentru calculul valorilor


funciei f x, y 2 xy , am definit n program funcia f. Modificnd
corespunztor funcia f, programul poate aproxima soluia
oricrei ecuaii difereniale de acest tip.
#include <stdio.h>
#include <conio.h>
#include <math.h>
#include <stdlib.h>
double f(double x,double y)
{
return 2*x*y;
}
int main()
{
double y0,a,b,h,xi,yi,ye;
int n, i;
printf(" Intervalul [a,b] \n");
printf(" a = ");

206

Bazele programrii calculatoarelor


scanf("%lf", &a);
printf(" b = ");
scanf("%lf", &b);
printf(" Numarul de puncte n = ");
scanf("%i", &n);
printf(" Conditia initiala y0 = ");
scanf("%lf", &y0);
h=(b-a)/n;
printf("Valoare aproximativa\tValoare
exacta\n");
for(i=0,xi=a,yi=y0;i<=n;i++) {
yi=yi+h*f(xi,yi);
ye=exp(pow(xi,2.));
printf("y(%f) = %f\ty(%f) = %f \n", xi, yi,
xi, ye);
xi=xi+h;
}
getch();
}

Rezultatul rulrii programului este:


Intervalul [a,b]
a = 0
b = 1
Numarul de puncte n = 10
Conditia initiala y0 = 1
Valoare aproximativa
y(0.000000) = 1.000000
y(0.100000) = 1.020000
y(0.200000) = 1.060800
y(0.300000) = 1.124448
y(0.400000) = 1.214404
y(0.500000) = 1.335844
y(0.600000) = 1.496146
y(0.700000) = 1.705606
y(0.800000) = 1.978503
y(0.900000) = 2.334633
y(1.000000) = 2.801560

Valoare exacta
y(0.000000) = 1.000000
y(0.100000) = 1.010050
y(0.200000) = 1.040811
y(0.300000) = 1.094174
y(0.400000) = 1.173511
y(0.500000) = 1.284025
y(0.600000) = 1.433329
y(0.700000) = 1.632316
y(0.800000) = 1.896481
y(0.900000) = 2.247908
y(1.000000) = 2.718282

Deoarece am introdus pentru n o valoare mic, aproximaia


este destul de slab. Invitm cititorul s compare rezultatele
pentru n>1000.

207

Funcii matematice

106. Scriei un program C care aproximeaz numrul e folosind


n
1
formula en pentru un numr natural n.
i 0 i !
#include <stdio.h>
#include <math.h>
#include <conio.h>
int main()
{
int i;
double s = 1, ifact= 1, err;
printf("Introduceti eroarea minima: ");
scanf("%lf", &err);
printf("Calculat Corect
Eroare\n");
for(i=1; fabs(s-M_E) > err; ++i){
ifact*= i;
s += 1/ifact;
printf("%f %f %f\n", s, M_E, fabs(s-M_E));
}
printf("Minim de pasi: %d", i);
getch();
}
Introduceti eroarea minima: 0.00001
Calculat Corect
Eroare
2.000000 2.718282 0.718282
2.500000 2.718282 0.218282
2.666667 2.718282 0.051615
2.708333 2.718282 0.009948
2.716667 2.718282 0.001615
2.718056 2.718282 0.000226
2.718254 2.718282 0.000028
2.718279 2.718282 0.000003
Minim de pasi: 9

10.2. Exerciii
87. Scriei un program C care determin perimetrul i aria unui
triunghi cunoscnd lungimile laturilor.
88. Scriei un program C care citete un unghi n grade
sexagesimale i calculeaz valoarea funciei sinus, cosinus i
tangent.

208

Bazele programrii calculatoarelor

89. Scriei un program C care determin valoarea minim a


numrului natural n astfel nct eroarea numrului aproximat
n

cu formula n 6
i 1

1
s scad sub un anumit prag specificat
i2

de utilizator.
90. Scriei un program C care afieaz valoarea funciei
n

f (n) sin(i ) cos(i) , pentru un numr n citit de la tastatur.


i 1

91. Scriei un program C care afieaz valoarea funciei


n

f (n) ei i , pentru un numr n citit de la tastatur.


i 1

92. Scriei un program C care afieaz valoarea funciei


n
sin(i ) cos(i )
f ( n) i
, pentru un numr n citit de la tastatur.
i
i 1
93. Scriei un program C care afieaz valoarea funciei
n

f (n) (1) j j j , pentru un numr n citit de la tastatur.


i 1 j 1

94. Scriei un program C care determin dac un numr natural


n citit de la tastatur este numr narcisist. Un numr n ak ...a2 a1
k

este narcisist dac n aik (de exemplu, 7, 153, 1634, 54748).


i 1

95. Scriei un program C care alege aleator un numr ntre 0 i


9. Utilizatorul are trei ncercri s ghiceasc acest numr. La
fiecare tentativ, programul l anun dac valoarea aleas este
corect, prea mic sau prea mare.

209

Funcii pentru gestiunea fiierelor

1111.. FFUUNNCCIIII PPEENNTTRRUU G


GE
ES
STTIIU
UN
NE
EA
A FFII
IIE
ER
RE
ELLO
OR
R
Limbajul C nu are instruciuni definite special pentru
operaii de intrare/ieire, dar pentru astfel de operaii, exist o
gam complet de funcii oferite de biblioteca standard C.
Limbajul C ofer dou clase de funcii pentru lucrul cu fiiere,
denumite generic funcii de nivel nalt i funcii de nivel sczut.
Totui, dintre acestea doar nivelul nalt este standardizat, fiind
similar pe toate platformele. Funciile de nivel nalt pentru lucru cu
fiiere sunt declarate n biblioteca standard stdio.h, o parte
dintre ele fiind similare cu cele prezentate n capitolul 4).

11.1. Structura FILE


Majoritatea funciilor standard pentru operaii cu fiiere
necesit un parametru de tip pointer la o structur FILE. Tipul
structur FILE este definit de asemenea n biblioteca standard
stdio.h. Structura propriu-zis conine informaii despre poziia
curent de la care se citesc sau la care se scriu date n fiier,
identificatorul fiierului, modul de acces, etc. Ea este creat
automat la deschiderea fiierului i este distrus automat la
nchiderea acestuia.
Algoritmul general de lucru cu fiiere const n
deschiderea sau crearea fiierului, citirea sau scrierea datelor i,
n final, nchiderea acestuia.

11.2. Fiiere standard de intrare/ieire


Cnd un program este pornit se deschid automat trei
fiiere (adic se creeaz structurile FILE corespunztoare lor).
Aceste fiiere sunt intrarea standard, ieirea standard i ieirea
standard pentru erori. Variabilele pointeri ctre structurile FILE
ale acestor fiiere se numesc stdin, stdout i stderr (definite
in stdio.h).

210

Bazele programrii calculatoarelor

11.3. Deschiderea i nchiderea fiierelor


nainte de a se citi sau scrie date ntr-un fiier, acesta
trebuie deschis cu funcia fopen. n funcie de modul de acces
stabilit la deschidere, asupra fiierului se pot efectua doar operaii
de citire, doar operaii se scriere, sau operaii de citire i scriere.
Dup ncheierea operaiilor de citire i/sau scriere a datelor,
fiierul trebuie nchis cu funcia fclose.
Tabel 11.1 Funcii standard pentru gestiunea dinamic a memoriei

Prototi
p

Descriere

FILE*
Efect: deschide fiierul name n modul
fopen
(char de accesare mode.
*name,
char
Rezultat: returneaz un pointer la o
*mode)

structura FILE sau NULL n caz de eroare


Efect: nchide fiierul corespunztor lui
fclose
( fptr.
FILE *fptr)
Rezultat: 0 n caz de succes i diferit de
0 altfel
Al doilea argument al funcie fopen este un ir de
caractere care determin modul de acces. Acesta indic cum va
fi utilizat fiierul: citire ("r"), scriere("w") sau adugare ("a"). n
plus, exist i modurile extinse: citire cu posibilitatea de scriere
("r+"), scriere cu posibilitatea de citire ("w+") sau adugare cu
posibilitatea de citire ("a+").
Dac se deschide un fiier care nu exist pentru scriere
("w") sau adugare ("a"), el este creat. Dac se deschide un fiier
existent pentru scriere ("w"), coninutul su este ters. ncercarea
de a deschide pentru citire un fiier care nu exist produce o
eroare.
int

11.4. Funcii pentru caractere


Funciile pentru caractere au o utilizare limitat, fiind
folosite pentru citirea i scrierea informaiei caracter cu caracter,
fr nici o prelucrare n prealabil.
211

Funcii pentru gestiunea fiierelor


Tabel 11.2 Funcii standard de intrare/ieire la nivel de caracter

Prototip

Descriere

int
Efect: scrie caracterul cu codul ASCII
fputc (int c, c n fiierul fptr
FILE * fptr)

Rezultat: valoarea c sau EOF n caz


de eroare
int
Efect: citete din fiierul fptr un
fgetc (FILE * singur caracter
fptr)
Rezultat: codul ASCII al caracterului
citit sau EOF dac s-au terminat datele sau a
aprut o eroare
De exemplu:
FILE *fp = fopen("test.txt", "w");
if(fp == NULL) {
printf("Eroare la deschiderea fisierului");
}else{
int c = 'A';
fputc(c, fp);
fclose(fp);
}

Un alt exemplu:
FILE *fp = fopen("test.txt", "r");
if(fp == NULL) {
printf("Eroare la deschiderea fisierului");
}else {
int c=fgetc(fp);
if(c==EOF)
printf("Fisierul este gol.\n");
else
printf("Am citit caracterul %c", c);
fclose(fp);
}

11.5. Funcii pentru iruri de caractere


Funciile pentru iruri de caractere permit citirea i
scrierea informaiei sub form de ir de caracter, fr alte
prelucrri.

212

Bazele programrii calculatoarelor


Tabel 11.3 Funcii standard de intrare/ieire pentru iruri de caractere

Prototip

Descriere
Efect: scrie irul s n fiierul fptr
Rezultat: un numr nenegativ n caz
de succes sau EOF n caz de eroare
char*
Efect: citete un ir de maximum
fgets (char *s, cnt-1 caractere din fiierul fptr i l pune
int cnt, FILE
n memorie la adresa s
*fptr)
Rezultat: adresa irului sau NULL
daca s-au terminat datele sau a aprut o
eroare
Exemplul urmtor scrie un mesaj n fiierul test.txt.
int fputs
(char *s, FILE
*fptr)

FILE *fp = fopen("test.txt", "w");


if(fp == NULL) {
printf("Eroare la deschiderea fisierului");
}else {
char linie="Aceasta este o linie de text".;
fputs(linie, fp);
fclose(fp);
}

Exemplul urmtor citete un mesaj din fiierul test.txt.


FILE *fp = fopen("test.txt", "r");
if(fp == NULL) {
printf("Eroare la deschiderea fisierului");
}else {
char linie[100];
fgets(linie, 100, fp);
printf("Am citit linia: %s.\n", linie);
fclose(fp);
}

11.6. Funcii cu formatare


Funciile cu formatare permit citirea i scrierea informaiei
dup o prelucrare n prealabil a acesteia. Prelucrarea se
realizeaz conform codurilor de format descrise n seciunea 5.3.

213

Funcii pentru gestiunea fiierelor


Tabel 11.4 Funcii standard de intrare/ieire cu formatare

Prototi
p

Descriere

int
Efect: scrie n fiierul fptr irul fmt n
fprintf
care codurile de format sunt nlocuite cu valorile
(FILE *fptr,
char
*fmt, expresiilor marcate prin trei puncte;
Rezultat: numrul de caractere scrise
...);

sau EOF n caz de eroare


int
Efect: citete din fiierul fptr date
scanf
(FILE conform irului fmt i le pune n memorie la
*fptr,
char
adresele marcate prin trei puncte;
*fmt, ...);

Rezultat: numrul de coduri de format


prelucrate corect sau EOF n caz de eroare
De exemplu:

FILE *fp = fopen("test.txt", "w");


if(fp == NULL) {
printf("Eroare la deschiderea fisierului");
}else {
fprintf(fp, "%d|%c|%f|%s", 3, 'A', 3.14,
"Test");
fclose(fp);
}

De exemplu:
FILE *fp = fopen("test.txt", "r");
if(fp == NULL) {
printf("Eroare la deschiderea fisierului");
}else {
char cuvant[100];
fscanf(fp, "%s", cuvant);
printf("Am citit %s.\n", cuvant);
fclose(fp);
}

11.7. Funcii pentru blocuri de date


Funciile fread i fwrite permit citirea i scrierea
informaiilor binare (adic non-textuale) dintr-un fiier. n acest
caz, parametrul mod de acces al funciei fopen trebuie s conin
sufixul "b". Dac sufixul lipsete sau se folosete sufixul "t",
214

Bazele programrii calculatoarelor

modul implicit de lucru este cel textual (adic non-binar), caz n


care informaia poate fi transformat ntr-un mod nedorit n timpul
operaiilor de citire/scriere.
Tabel 11.5 Funcii standard de intrare/ieire cu blocuri de date

Prototi
p
unsign
ed
fread
(void *dest,
unsigned
size,
unsigned
cnt,
FILE
*fptr)
unsign
ed
fwrite
(void
*src,
unsigned
size,
unsigned
cnt,
FILE
*fptr)

Descriere
Efect: citete maxim cnt elemente de
dimensiune size din fiierul fptr n zona de
memorie dest.
Rezultat: numrul de elemente citite
complet
Efect: scrie maxim cnt elemente de
dimensiune size n fiierul fptr din zona de
memorie src.
Rezultat: numrul de elemente scrise
complet

De exemplu:
FILE *fp = fopen("test.txt", "wb");
if(fp == NULL) {
printf("Eroare la deschiderea fisierului");
}else {
int valori[] = {1, 2, 3, 5};
fwrite(valori, sizeof(int), 4, fp);
fclose(fp);
}

De exemplu:
FILE *fp = fopen("test.txt", "rb");
if(fp == NULL) {
printf("Eroare la deschiderea fisierului");
}else {
int valori[20];
int citite = fread(valori, sizeof(int), 20, fp);
printf("Am citit %d intregi.\n", citite);
fclose(fp);
}

215

Funcii pentru gestiunea fiierelor

11.8. Funcii pentru acces aleator n fiiere


n momentul deschiderii unui fiier n modul de citire sau
scriere, poziia curent la care se scriu date sau de la care se
citesc date este nceputul fiierului. Pentru fiierele deschise n
modul de adugare poziia curent la care se scriu date n fiier
este sfritul fiierului. Ulterior, n urma operaiilor de citire/
scriere, poziia curent avanseaz automat cu numrul de octei
corespunztor.
Tabel 11.6 Funcii standard de intrare/ieire cu blocuri de date

Prototi
p

Descriere

long
Rezultat: poziia curent n fiier sau
ftell ( FILE EOF n caz de eroare
*fptr)
int
Efect: mut poziia curent pentru
fseek
(FILE fiierul fptr cu offset octei relativ la poziia
*fptr,
long
offset,
int specificata de parametrul origin.
Rezultat: numrul de elemente scrise
origin)

complet
Parametrul origin al funciei fseek poate fi una din
constantele SEEK_CUR (denot poziia curent), SEEK_END
(denot sfritul fiierului), SEEK_SET (denot nceputul fiierului).
De exemplu:
FILE *fp = fopen("test.txt", "wb");
if(fp == NULL) {
printf("Eroare la deschiderea fisierului");
}else {
fseek(fp, 0, SEEK_END); // la sfarsitul
fisierului
printf("Fisierul are %li octeti.\n", ftell(fp));
fseek(fp, 0, SEEK_SET); // la inceputul
fisierului
fclose(fp);
}

11.9. Alte funcii pentru fiiere i directoare


Folosirea acestor funcii
includerea bibliotecii direct.h.
216

ntr-un

program

necesit

Bazele programrii calculatoarelor


Tabel 11.7 Funcii standard de intrare/ieire cu blocuri de date

Prototi
p
int
remove (char
*nume)
int
rename (char
*vechi, char
*nou)
int
chdir
(char
*nume)
char*
getcwd (char
*dest,
int
cnt)
int
mkdir
(char
*nume)
int
rmdir
(char
*nume)

Descriere
Efect: terge fiierul nume
Rezultat: 0 n caz de succes sau diferit
de zero altfel
Efect: redenumete fiierul vechi n nou
Rezultat: 0 n caz de succes sau diferit
de zero altfel
Efect: face nume directorul curent de
lucru
Rezultat: 0 n caz de succes sau diferit
de zero altfel
Efect: copiaz n zona de memorie dest
(cu dimensiune maxim de cnt octei) calea
directorului curent.
Rezultat: dest n caz de succes i NULL
altfel
Efect: creeaz directorul nume
Rezultat: 0 n caz de succes sau diferit
de zero altfel
Efect: terge directorul nume
Rezultat: 0 n caz de succes sau diferit
de zero altfel

11.10. Exemple
107. Programul urmtor copiaz coninutul unui fiier n alt fiier
folosind funciile pentru blocuri de date. Numele fiierelor sunt
citite de la tastatur.
#include <stdio.h>
#include <conio.h>
int main()
{
char sursa[256], destinatie[256];
printf("Fisierul sursa: ");
gets(sursa);
printf("Fisierul destinatie: ");

217

Funcii pentru gestiunea fiierelor


gets(destinatie);
FILE *fpin = fopen(sursa, "rb");
FILE *fpout = fopen(destinatie, "wb");
if (fpin==NULL || fpout==NULL) {
printf("Eroare la deschiderea fisierelor");
} else {
char data[80];
int cnt;
do {
cnt=fread(data, sizeof(char), 80,
fpin);
fwrite(data, sizeof(char), cnt, fpout);
}while(cnt > 0);
}
fclose(fpin);
fclose(fpout);
getch();
}

108. Programul urmtor redenumete un fiier sau un director al


crui nume a fost citit de la tastatur.
#include <stdio.h>
#include <conio.h>
int main()
{
char numeVechi[256], numeNou[256];
printf("Numele vechi: ");
gets(numeVechi);
printf("Numele nou: ");
gets(numeNou);

if(rename(numeVechi, numeNou) != 0)
printf("Redenumirea nu s-a efectuat");
else
printf("Redenumirea s-a efectuat");
getch();

109. Programul urmtor terge un fiier al crui nume a fost citit


de la tastatur.
#include <stdio.h>
#include <conio.h>
int main()
{

218

Bazele programrii calculatoarelor


char nume[256];
printf("Numele: ");
gets(nume);
if(remove(nume) != 0)
printf("Stergerea nu s-a efectuat");
else
printf("Stergerea s-a efectuat");
getch();
}

110. Programul urmtor afieaz coninutul unui fiier al crui


nume este citit de la tastatur folosind funcii pentru blocuri de
date.
#include <stdio.h>
#include <conio.h>
int main()
{
char nume[50];
printf("Nume fisier:");
gets(nume);
FILE *fp = fopen(nume, "r");
if(fp == NULL) {
printf("Eroare la deschiderea fisierului");
}else {
char data[80];
int cnt;
do {
cnt=fread(data, sizeof(char), 80, fp);
fwrite(data, sizeof(char), cnt,
stdout);
} while(cnt > 0);
fclose(fp);
}
getch();
}

111. Programul urmtor exemplific folosirea funciilor pentru


operaii cu foldere. Programul afieaz folderul n care este
pornit, schimb folderul cu unul specificat de utilizator i creeaz
n acesta un fiier cu numele "test.txt".
#include <stdio.h>
#include <direct.h>
#include <conio.h>

219

Funcii pentru gestiunea fiierelor


int main()
{
char buffer[256];
getcwd(buffer, 256);
printf("Folderul curent %s\n", buffer);

printf("Noul folder: ");


gets(buffer);
chdir(buffer);
getcwd(buffer, 256);
printf("Acum suntem in folderul %s\n", buffer);
fclose(fopen("test.txt", "w"));
getch();

112. Programul urmtor creeaz un folder nou al crui nume este


introdus de utilizator.
#include <stdio.h>
#include <direct.h>
#include <conio.h>
int main()
{
printf("Folder nou: ");
char nume[256];
gets(nume);
if(mkdir(nume) != 0)
printf("Directorul nu a fost creat.");
else
printf("Directorul a fost creat.");
getch();
}

113. Programul urmtor terge un folder al crui nume este


introdus de utilizator. Folderul trebuie s fie gol, adic s nu
conin fiiere sau alte foldere.
#include <stdio.h>
#include <direct.h>
#include <conio.h>
int main()
{
printf("Folder: ");
char nume[256];
gets(nume);
if(rmdir(nume) != 0)

220

else
}

Bazele programrii calculatoarelor


printf("Directorul nu a fost sters.");

printf("Directorul a fost sters.");


getch();

114. Programul urmtor gestioneaz o agend telefonic simpl.


Programul ofer funcii pentru creare, listare, cutare, adugare,
tergere, sortare, salvare i ncrcare din fiier.
#include
#include
#include
#include

<stdio.h>
<conio.h>
<string.h>
<ctype.h>

struct contact {
char nume[50];
char adresa[100];
char telefon[15];
}agenda[100];
int intrari;
char * numefisier = "agenda.dat";
void incarcare(void)
{
puts("Incarcare agenda");
FILE *f = fopen(numefisier,"rb");
if(f == NULL) {
printf("Fisierul %s lipseste. Incep o agenda
noua.\n", numefisier);
intrari = 0;
}else{
intrari = fread(agenda, sizeof(contact),
100, f);
fclose(f);
}
}
void salvare(void)
{
puts("Salvare agenda");
FILE *f = fopen(numefisier, "wb");
if(f == NULL) {
printf("Fisierul %s nu poate fi
modificat.\n", numefisier);
}else{

221

Funcii pentru gestiunea fiierelor


int i = fwrite(agenda, sizeof(contact),
intrari, f);
if(i != intrari)
printf("Doar %d contacte din %d au fost
salvate.", i, intrari);
fclose(f);
}
}
void afisarecontact(struct contact c) {
printf("Nume: %s\n", c.nume);
printf("Adresa: %s\n", c.adresa);
printf("Telefon: %s\n", c.telefon);
}
void citirecontact(struct contact *c) {
fflush(stdin);
printf("Nume: ");
gets(c->nume);
printf("Adresa: ");
gets(c->adresa);
printf("Telefon: ");
gets(c->telefon);
}
void cautarenume(void)
{
int i, gasite = 0;
char date[50];
fflush(stdin);
printf("Nume: ");
gets(date);
for(i = 0; i<intrari; ++i)
if(stricmp(date, agenda[i].nume)==0) {
printf("Intrarea %d:\n", i);
afisarecontact(agenda[i]);
++gasite;
}
printf("Au fost gasite %d contacte.\n", gasite);
}
void cautareadresa(void)
{
int i, gasite = 0;
char date[100];
fflush(stdin);

222

Bazele programrii calculatoarelor


printf("Adresa partiala: ");
gets(date);
for(i = 0; i<intrari; ++i)
if(strstr(agenda[i].adresa, date)!=NULL) {
printf("Intrarea %d:\n", i);
afisarecontact(agenda[i]);
++gasite;
}
printf("Au fost gasite %d contacte.\n", gasite);
}
void cautaretelefon(void)
{
int i, gasite = 0;
char date[100];
fflush(stdin);
printf("Telefon cautat: ");
gets(date);
for(i = 0; i<intrari; ++i)
if(strcmp(date, agenda[i].telefon)==0) {
printf("Intrarea %d:\n", i);
afisarecontact(agenda[i]);
++gasite;
}
printf("Au fost gasite %d contacte.\n", gasite);
}
void adaugare(void)
{
char corect;
struct contact c;
puts("Introduceti datele:");
citirecontact(&c);
puts("Ati introdus:");
afisarecontact(c);
do {
printf("Sigur doriti sa adaugati? (d/n)\n");
corect = toupper(getchar());
}while(corect !='D' && corect !='N');
if(corect == 'D')
agenda[intrari++] = c;
}
void stergere(void)
{
char corect;

223

Funcii pentru gestiunea fiierelor


int i;
struct contact c;
puts("Introduceti numarul contactului:");
scanf("%i", &i);
if(i < 0 || i>= intrari) {
puts("Valoare incorecta");
return;
}
puts("Ati selectat:");
afisarecontact(agenda[i]);
do {
printf("Sigur doriti sa stergeti? (d/n)\n");
corect = toupper(getchar());
}while(corect !='D' && corect !='N');
if(corect == 'D') {
--intrari;
for(; i<intrari; ++i)
agenda[i] = agenda[i+1];
}
}
void listare(void)
{
int i;
for(i = 0; i<intrari; ++i) {
printf("Intrarea %d:\n", i);
afisarecontact(agenda[i]);
}
printf("Au fost gasite %d contacte.\n",
intrari);
}
void sortare(void)
{
int i, j;
struct contact c;
for(i=0;i < intrari; ++i)
for(j=i+1; j < intrari; ++j)
if(stricmp(agenda[i].nume,
agenda[j].nume)>0) {
c = agenda[i];
agenda[i] = agenda[j];
agenda[j] = c;
}
}

224

Bazele programrii calculatoarelor


int main()
{
int optiune;
incarcare();
do{
puts("Functia dorita:");
puts("\t[1] Cautare in agenda dupa nume");
puts("\t[2] Cautare in agenda dupa numar");
puts("\t[3] Cautare in agenda dupa adresa");
puts("\t[4] Adaugare in agenda");
puts("\t[5] Listare agenda");
puts("\t[6] Stergere din agenda");
puts("\t[7] Sortare agenda");
puts("\t[0] Terminare");
scanf("%d", &optiune);
switch(optiune)
{
case 0: break;
case 1: cautarenume(); break;
case 2: cautaretelefon(); break;
case 3: cautareadresa(); break;
case 4: adaugare(); break;
case 5: listare(); break;
case 6: stergere(); break;
case 7: sortare(); break;
default: puts(" Functie necunoscuta");
}
}while(optiune!=0);
salvare();
getch();
}

La prima rulare programul


corespunztoare crerii unei noi agende.

afieaz

mesajele

Incarcare agenda
Fisierul agenda.dat lipseste. Incep o agenda noua.
Functia dorita:
[1] Cautare in agenda dupa nume
[2] Cautare in agenda dupa numar
[3] Cautare in agenda dupa adresa
[4] Adaugare in agenda
[5] Listare agenda
[6] Stergere din agenda
[7] Sortare agenda
[0] Terminare

225

Funcii pentru gestiunea fiierelor


5
Au fost gasite 0 contacte.
Functia dorita:
[1] Cautare in agenda dupa
[2] Cautare in agenda dupa
[3] Cautare in agenda dupa
[4] Adaugare in agenda
[5] Listare agenda
[6] Stergere din agenda
[7] Sortare agenda
[0] Terminare
4
Introduceti datele:
Nume: Andrei Bautu
Adresa: Constanta
Telefon: 123456
Ati introdus:
Nume: Andrei Bautu
Adresa: Constanta
Telefon: 123456
Sigur doriti sa adaugati? (d/n)
d
Functia dorita:
[1] Cautare in agenda dupa
[2] Cautare in agenda dupa
[3] Cautare in agenda dupa
[4] Adaugare in agenda
[5] Listare agenda
[6] Stergere din agenda
[7] Sortare agenda
[0] Terminare
4
Introduceti datele:
Nume: Paul Vasiliu
Adresa: Constanta
Telefon: 654321
Ati introdus:
Nume: Paul Vasiliu
Adresa: Constanta
Telefon: 654321
Sigur doriti sa adaugati? (d/n)
d
Functia dorita:
[1] Cautare in agenda dupa
[2] Cautare in agenda dupa
[3] Cautare in agenda dupa

226

nume
numar
adresa

nume
numar
adresa

nume
numar
adresa

[4]
[5]
[6]
[7]
[0]

Bazele programrii calculatoarelor


Adaugare in agenda
Listare agenda
Stergere din agenda
Sortare agenda
Terminare

0
Salvare agenda

La rulri succesive, programul ncarc datele salvate la


ultima rulare.
Incarcare agenda
Functia dorita:
[1] Cautare in agenda dupa
[2] Cautare in agenda dupa
[3] Cautare in agenda dupa
[4] Adaugare in agenda
[5] Listare agenda
[6] Stergere din agenda
[7] Sortare agenda
[0] Terminare
5
Intrarea 0:
Nume: Andrei Bautu
Adresa: Constanta
Telefon: 123456
Intrarea 1:
Nume: Paul Vasiliu
Adresa: Constanta
Telefon: 654321
Au fost gasite 2 contacte.
Functia dorita:
[1] Cautare in agenda dupa
[2] Cautare in agenda dupa
[3] Cautare in agenda dupa
[4] Adaugare in agenda
[5] Listare agenda
[6] Stergere din agenda
[7] Sortare agenda
[0] Terminare
4
Introduceti datele:
Nume: Elena Bautu
Adresa: Constanta
Telefon: 123654
Ati introdus:

nume
numar
adresa

nume
numar
adresa

227

Funcii pentru gestiunea fiierelor


Nume: Elena Bautu
Adresa: Constanta
Telefon: 123654
Sigur doriti sa adaugati? (d/n)
d
Functia dorita:
[1] Cautare in agenda dupa
[2] Cautare in agenda dupa
[3] Cautare in agenda dupa
[4] Adaugare in agenda
[5] Listare agenda
[6] Stergere din agenda
[7] Sortare agenda
[0] Terminare
5
Intrarea 0:
Nume: Andrei Bautu
Adresa: Constanta
Telefon: 123456
Intrarea 1:
Nume: Paul Vasiliu
Adresa: Constanta
Telefon: 654321
Intrarea 2:
Nume: Elena Bautu
Adresa: Constanta
Telefon: 123654
Au fost gasite 3 contacte.
Functia dorita:
[1] Cautare in agenda dupa
[2] Cautare in agenda dupa
[3] Cautare in agenda dupa
[4] Adaugare in agenda
[5] Listare agenda
[6] Stergere din agenda
[7] Sortare agenda
[0] Terminare
0
Salvare agenda

nume
numar
adresa

nume
numar
adresa

La urmtoarea rulare, agenda conine deja 3 contacte.


Incarcare agenda
Functia dorita:
[1] Cautare in agenda dupa nume
[2] Cautare in agenda dupa numar

228

[3]
[4]
[5]
[6]
[7]
[0]

Bazele programrii calculatoarelor


Cautare in agenda dupa adresa
Adaugare in agenda
Listare agenda
Stergere din agenda
Sortare agenda
Terminare

5
Intrarea 0:
Nume: Andrei Bautu
Adresa: Constanta
Telefon: 123456
Intrarea 1:
Nume: Paul Vasiliu
Adresa: Constanta
Telefon: 654321
Intrarea 2:
Nume: Elena Bautu
Adresa: Constanta
Telefon: 123654
Au fost gasite 3 contacte.
Functia dorita:
[1] Cautare in agenda dupa nume
[2] Cautare in agenda dupa numar
[3] Cautare in agenda dupa adresa
[4] Adaugare in agenda
[5] Listare agenda
[6] Stergere din agenda
[7] Sortare agenda
[0] Terminare
0
Salvare agenda

11.11. Exerciii
96. Scriei un program C care afieaz pe ecran doar literele i
spaiile din coninutul unui fiier al crui nume a fost citit de la
tastatur.
97. Scriei un program C care copiaz coninutul unui fiier n alt
fiier caracter cu caracter (folosind funciile fgetc i fputc),
exceptnd semnele de punctuaie care sunt nlocuite cu spaiu.
98. Scriei un program C care copiaz coninutul unui fiier n alt
fiier linie cu linie (folosind funciile fgets i fputs), transformnd
majusculele n minuscule.
229

Funcii pentru gestiunea fiierelor

99. Scriei un program C care scrie ntr-un fiier iruri de


caractere citite de la tastatur. Citirea se oprete la citirea irului
de caractere vid (cu lungime 0).
100. Scriei un program C care afieaz statistici despre
coninutul unui fiier (numr total de caractere, majuscule,
minuscule, cifre, semne de punctuaie, caractere de spaiere).
101. Scriei un program C care afieaz media numerelor citite
dintr-un fiier.
102. Scriei un program C care gestioneaz catalogul unei
discipline. Programul trebuie s permit adugarea, tergerea,
afiarea i cutarea studenilor, adugarea i afiarea notelor,
salvarea i ncrcarea datelor n fiiere diferite).

230

Bazele programrii calculatoarelor

231

Metode de programare

1122.. M
MEETTO
OD
DE
ED
DE
EP
PR
RO
OG
GR
RA
AM
MA
AR
RE
E
12.1. Metoda Divide et Impera
Metoda const n descompunerea problemei de rezolvat n dou
sau mai multe subprobleme care, la rndul lor se descompun n
dou sau mai multe subprobleme, pn cnd se obin
subprobleme a cror rezolvare este direct i nu mai necesit
alte descompuneri. Soluia problemei iniiale se obine prin
combinarea soluiilor problemelor cu rezovare direct n care a
fost descompus.
S presupunem c urmeaz procesarea irului sk , sk 1, , s p i
exist

cu proprietatea

k m p . irul

sk , sk 1,

, sp

se

descompune n subirurile sk , sk 1, , sm i sm1, sm2 , , s p . Se


proceseaz cele dou subiruri, cu eventuala lor descompunere,
i apoi se combin rezultatele procesrii tuturor subirurilor
pentru a obine rezultatul procesrii irului sk , sk 1, , s p . Astfel,
funcia care proceseaz irul sk , sk 1,
intrare
sk , sk 1,

k i
, sp .

, s p are parametrii de

i genereaz rezultatul procesrii irului

12.2. Exemple
77. Program pentru calculul sumei primelor n numere naturale
Fie suma S 1, n a1 a2

an i

a ak 1
S k, p k
ak

kp
. Evident se poate defini relaia
kp

ap

ak
kp

de recuren: S k , p k p
,
k p

S k , 2 S 2 1, p k p


232

Bazele programrii calculatoarelor

relaie care este o descompunere a lui S 1, n . Astfel, pentru

n 5 se obine:
S 1,5 S 1,3 S 4,5 S 1, 2 S 3,3 S 4, 4 S 5,5

S 1,1 S 2,2 S 3,3 S 4,4 S 5,5 a1 a2 a3 a4 a5


Problema propus este cazul particular n care ak k . Fie
S 1, n 1 2

n suma primelor n numere naturale i

k k 1
S k, p
k

p kp
. Evident se poate defini relaia
kp

k
kp

de recuren: S k , p k p
.
k p

S k , 2 S 2 1, p k p


Astfel, pentru n 5 se obine:
S 1,5 S 1,3 S 4,5 S 1, 2 S 3,3 S 4, 4 S 5,5

S 1,1 S 2,2 S 3,3 S 4,4 S 5,5 1 2 3 4 5 1


Programul afieaz soluiile subproblemelor i soluia
problemei.
// Suma primelor n numere naturale cu metoda "Divide
et Impera"
#include "stdio.h"
#include "conio.h"
int n;
int s(int k,int p)
{
if(k==p)
return k;
else
return s(k,(k+p)/2)+s((k+p)/2+1,p);
}
void afis(int k,int p)
{
if(k==p)
printf(" S(%d,%d)=%d \n",k,k,s(k,k));
else

233

Metode de programare
{
afis(k,(k+p)/2);
afis((k+p)/2+1,p);
printf(" S(%d,%d)=%d
\n",k,(k+p)/2,s(k,(k+p)/2));
printf(" S(%d,%d)=%d
\n",(k+p)/2+1,p,s((k+p)/2+1,p));
}
}
int main()
{
int k,p;
printf(" n = ");
scanf("%d",&n);
afis(1,n);
printf(" S = %d ",s(1,n));
getch();
}
n = 5
S(1,1)=1
S(2,2)=2
S(1,1)=1
S(2,2)=2
S(3,3)=3
S(1,2)=3
S(3,3)=3
S(4,4)=4
S(5,5)=5
S(4,4)=4
S(5,5)=5
S(1,3)=6
S(4,5)=9
S = 15

78. Program pentru calculul lui n !


Fie produsul P 1, n a1 a2 an i
a a
P k , p k k 1
ak

234

ap

kp
. Evident se poate defini relaia de
kp

Bazele programrii calculatoarelor

ak
kp

recuren: P k , p k p k p
,

P k , 2 P 2 1, p k p


relaie care este o descompunere a lui P 1, n . Astfel, pentru

n 5 se obine:
P 1,5 P 1,3 P 4,5 P 1, 2 P 3,3 P 4, 4 P 5,5

P 1,1 P 2,2 P 3,3 P 4,4 P 5,5 a1 a2 a3 a4 a5 a1 a2


Problema propus este cazul particular n care ak k . Fie
P 1, n 1 2

n suma primelor n numere naturale i

k k 1
P k, p
k

p k p
. Evident se poate defini relaia de
kp

k
kp

recuren: P k , p k p k p
.

P k , 2 P 2 1, p k p


Astfel, pentru n 5 se obine:
P 1,5 P 1,3 P 4,5 P 1, 2 P 3,3 P 4, 4 P 5,5

P 1,1 P 2,2 P 3,3 P 4,4 P 5,5 1 2 3 4 5 1 2 3 4 5


Programul afieaz soluiile subproblemelor i soluia problemei.
// Calculul lui n! cu metoda "Divide et Impera"
#include "stdio.h"
#include "conio.h"
int n;
int fact(int k,int p)
{
if(k==p)
return k;
else
return fact(k,(k+p)/2)*fact((k+p)/2+1,p);
}
void afis(int k,int p)
{

235

Metode de programare
if(k==p)
printf(" fact(%d,%d)=%d \n",k,k,fact(k,k));
else
{
afis(k,(k+p)/2);
afis((k+p)/2+1,p);
printf(" fact(%d,%d)=%d
\n",k,(k+p)/2,fact(k,(k+p)/2));
printf(" fact(%d,%d)=%d
\n",(k+p)/2+1,p,fact((k+p)/2+1,p));
}
}
int main()
{
int k,p;
printf(" n = ");
scanf("%d",&n);
afis(1,n);
printf(" S = %d ",fact(1,n));
getch();
}
n = 5
fact(1,1)=1
fact(2,2)=2
fact(1,1)=1
fact(2,2)=2
fact(3,3)=3
fact(1,2)=2
fact(3,3)=3
fact(4,4)=4
fact(5,5)=5
fact(4,4)=4
fact(5,5)=5
fact(1,3)=6
fact(4,5)=20
S = 120

79. Program pentru determinarea maximului dintr-un ir de


numere reale
Programul determin maximul dintre termenii irului xk , xk 1 , , x p
folosind relaia de recuren:
236

Bazele programrii calculatoarelor

max xk , xk 1,

max max xk , xk 1,
, xp

, x k p , max x k p , x k p ,
1
2
2

2 2
xk

// Determinarea maximului dintr-un sir de numere


reale cu metoda "Divide et Impera"
#include "stdio.h"
#include "conio.h"
#include "stdlib.h"
int n;
typedef float sir[100];
sir x;
float max(sir x,int k,int p)
{
float m1,m2;
if(k==p)
return x[k];
else
{
m1=max(x,k,(k+p)/2);
m2=max(x,(k+p)/2+1,p);
if(m1>=m2) return m1;
else return m2;
}
}
int main()
{
int k,p,i;
char c[10];
printf(" Numarul de termeni din sir n = ");
scanf("%d",&n);
for(i=1;i<=n;i++)
{
printf(" Termenul %d = ",i);
scanf("%f",&x[i]);
}
printf(" Maximul din sir este %4f
\n",max(x,1,n));
getch();
}

237

Metode de programare
Numarul de termeni din sir n = 5
Termenul 1 = 23
Termenul 2 = 21
Termenul 3 = 44
Termenul 4 = 55
Termenul 5 = 32
Maximul din sir este 55.000000

12.3. Metoda Backtracking


Metoda Backtracking este o metod general de elaborare a
algoritmilor. Pentru rezolvarea anumitor probleme este necesar
desfurarea unui proces de cutare a soluiei aflate ntr-o
anumit mulime, numit spaiul strilor. Pentru fiecare element
din spaiul strilor este definit o mulime de aciuni sau
alternative. Momentul iniial n rezolvarea problemei corespunde
unei stri, numit iniial, iar soluiile corespund drumurilor n
spaiul strilor, de la cea iniial pn la una final. Procesul de
rezolvare a problemei poate fi imaginat ca o secven de aciuni
care asigur deplasarea, prin intermediul unei secvene de stri,
n spaiul strilor, din starea iniial la cea final. n cazul anumitor
probleme se dorete obinerea unei singure soluii, altele solicit
determinarea tuturor soluiilor sau determinarea unei soluii
optime, dintr-un anumit punct de vedere, numit soluie optimal.
Considerm un labirint avnd una sau mai multe ieiri. Starea
iniial poate fi considerat orice camer a labirintului, problema
revenind la gsirea unui drum din camera respectiv ctre una
dintre ieiri. Desfurarea procesului de cutare a unei stri finale
presupune, la fiecare etap, alegerea opiunii pentru o alternativ
posibil a strii curente i detectarea acelor stri capcan din
care nu mai este posibil continuarea procesului, sau deja se
cunoate excluderea atingerii unei stri finale. Detectarea strii
capcan trebuie s determine revenirea la starea din care s-a
ajuns la ea i selectarea unei noi opiuni de continuare. n cazul
n care nu mai exist alternative care s nu fi fost selectate
anterior, o astfel de stare devine la rndul ei capcan i pentru ea
se aplic acelai tratament.
238

Bazele programrii calculatoarelor

Prin soluie a problemei se nelege o secven de aciuni care


determin tranziia din starea iniial ntr-o stare final, fiecare
component a unui drum soluie reprezentnd o alternativ din
mulimea de variante posibile. Cu alte cuvinte, x1 este alternativa
aleas pentru starea iniial, x2 este alternativa selectat pentru
starea n care s-a ajuns pe baza opiunii x1 , x3 este alternativa
selectat pentru starea n care s-a ajuns pe baza opiunii x2 ,,
xn este alternativa selectat pentru starea n care s-a ajuns pe
baza opiunii xn1 . Dup efectuarea aciunii corespunztoare
alegerii alternativei xn rezult o stare final.
Procesul de cutare a unui drum soluie revine la tentativa de
extindere a poriunii de drum construit, alegnd prima alternativ
disponibil pentru starea curent atins. Continuarea drumului
poate fi realizat pn la atingerea unei stri finale sau pn la
ntlnirea unei stri capcan (mulimea vid de alternative). Dac
este atins o stare capcan, atunci este necesar revenirea la
starea anterioar i selectarea urmtoarei alternative disponibile
acestei stri. Dac nu mai exist alternative disponibile, atunci se
iniiaz o nou revenire i aa mai departe. n cazul n care exist
cel puin nc o alternativ disponibil, atunci se reia procesul de
extindere a drumului rezultat. n condiiile n care revenirea poate
conduce la atingerea strii iniiale i pentru ea nu mai exist
alternative disponibile, se consider c problema nu are soluie.
Pentru implementarea cutrii este necesar reinerea
alternativei selectate pentru fiecare stare atins pn la cea
curent, astfel nct, n cazul unei reveniri s fie posibil alegerea
alternativei urmtoare. Cu alte cuvinte, procesul de cutare
revine la tentativa de extindere a drumului curent (pasul de
continuare), cu eventuala revenire n cazul atingerii unei stri
capcan (pasul de revenire - back), memornd alternativele
selectate pentru fiecare stare intermediar atins (track). De aici
i are geneza numele metodei backtracking.
Pentru determinarea unei singure soluii, metoda presupune
parcurgerea urmtorilor pai:
239

Metode de programare

Pasul 1:
starea iniial a problemei este prima alternativ
posibil pentru starea curent ; fie aceasta x1 S1 ;
Pasul 2:
dac starea curent rezultat prin alternativa x1

este final, atunci vectorul x are o singur component, x x1 ,


este vectorul soluie i stop;
Pasul 3:
altfel, este selectat prima alternativ din mulimea
de aciuni posibile pentru starea curent, x2 S2 ;
Pasul 4:
dac secvena de alternative care a condus la
starea curent este x x1 , x2 , , xk , atunci:
Pasul 5:
x x1 , x2 ,

dac starea curent este final, soluia este vectorul


, xk i stop;

Pasul 6:
dac starea curent nu este starea final atunci:
Pasul 7:
dac pentru starea curent exist alternative
disponibile, atunci se alege prima dintre ele i se continu;
Pasul 8:
altfel, se revine la starea anterioar celei curente,
soluia parial construit devine x x1 , x2 , , xk 1 i se face salt
la Pasul 7.
Pasul 9:
dac, n urma unui pas de revenire, s-a ajuns la
starea iniial i nu mai sunt alternative disponibile, atunci
problema nu are soluie i stop.
n cazul n care trebuie determinate toate soluiile problemei,
cutarea continu dup determinarea fiecrei soluii prin
efectuarea de reveniri succesive.Terminarea cutrii este decis
n momentul n care s-a revenit la starea iniial i nu mai exist
alternative disponibile.
Dac se dorete obinerea numai a soluiilor care optimizeaz o
funcie
criteriu, atunci metoda se aplic pentru determinarea tuturor
soluiilor problemei,
fiecare nou soluie rezultat fiind comparat cu cea mai bun
soluie determinat anterior. Pentru aceasta este necesar
reinerea celei mai bune soluii calculate la fiecare moment.
240

Bazele programrii calculatoarelor

Astfel, metoda se aplic problemelor a cror soluie se


poate reprezenta sub forma unui vector soluie X x1 , x2 , , xm ,
care aparine spaiului soluiilor posibile sau alternativelor
S S1 S2 Sm , xk Sk , i card S k nk , k 1, 2, , m . Pentru
fiecare problem, se dau anumite condiii interne pe care trebuie
s le satisfac componentele vectorului soluie. O soluie care
satisface condiiile interne se numete soluie rezultat. Metoda
Backtracking genereaz toate soluiile rezultat, fr generarea
tuturor soluiilor posibile. Se atribuie pe rnd valori componentelor
vectorului X astfel: se atribuie o valoare din mulimea S k
componentei xk numai dac au fost atribuite valori
componentelor x1, x2 , , xk 1 ; dac s-a atribuit o valoare
componentei xk , se verific dac componentele x1, x2 , , xk
satisfac condiiile interne de continuare; dac condiiile interne de
continuare sunt satisfcute se atribuie valoare componentei xk 1 ;
dac condiiile interne de continuare nu sunt satisfcute se
atribuie o alt valoare componentei xk sau dac mulimea S k a
fost epuizat, se decrementeaz k .

12.4. Backtracking nerecursiv


Pentru implementarea metodei definim urmtoarele funcii:
Funcia succesor testeaz dac mulimea S k mai are elemente
i care atribuie variabilei as (am succesor) valoarea 1 dac
mulimea S k mai are elemente sau valoarea 0 n caz contrar.
void succesor(sir x,int k,int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}

241

Metode de programare
Funcia validare verific dac sunt satisfcute condiiile interne
specifice problemei i care atribuie variabilei ev (este valid)

valoarea 1 dac sunt satisfcute condiiile interne sau valoarea 0


n caz contrar. Implementarea acestei funcii difer de la o
problem la alta, n funcie de condiiile de continuare.
void validare(sir x,int k, int &ev)
{
ev=1;
for(i=1;i<=k-1;i++)
if(!conditie)
ev=0;
}

Funcia afiare care afieaz o soluie rezultat:


void afisare(sir x, int k)
{
int i;
printf(" ( ");
for(i=1;i<=k-1;i++)
printf("%d, ",a[x[i]]);
printf("%d ) \n",a[x[i]]);
}

Aceste funcii sunt gestionate de secvena Backtracking care


codific mecanismul de generare a soluiilor rezultat.

k=1;x[k]=0;
while(k>0)
do
{

succesor(x,k,as);
if(as)
validare(x,k,ev);
}while(as && !ev);
if(as)
if(k==n) afisare(x,k);
else
{
k=k+1;

242

Bazele programrii calculatoarelor


x[k]=0;
}
else k=k-1;
}

12.5. Exemple
Prezentm n continuare cteva exemple clasice de aplicare a
metodei backtracking. Pentru fiecare exemplu este furnizat codul
surs i un exemplu de execuie a programului.
80. Program pentru generarea permutrilor unei mulimi de n
obiecte
// Generare permutari de n obiecte si a numarului
lor nf
#include "stdio.h"
#include "conio.h"
typedef int sir[100];
sir a,x;
int i,k,n,as,ev,nf;
void succesor(sir x,int k,int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void validare(sir x,int k, int &ev)
{
ev=1;
for(i=1;i<=k-1;i++)
if(!(x[k]!=x[i]))
ev=0;
}
void afisare(sir x, int k)
{
int i;
printf(" %d ( ",nf);

243

Metode de programare
for(i=1;i<=k-1;i++)
printf("%d, ",a[x[i]]);
printf("%d ) \n",a[x[i]]);
}
int main()
{
printf(" Generarea permutarilor de n obiecte
\n");
nf=0;
printf(" Numarul de obiecte n = ");
scanf("%d",&n);
printf(" Tastati obiectele \n");
for(i=1;i<=n;i++)
{
printf(" a [ %d ] = ",i);
scanf("%d",&a[i]);
}
k=1;x[k]=0;
while(k>0)
{
do
{
succesor(x,k,as);
if(as)
validare(x,k,ev);
}while(as && !ev);
if(as)
if(k==n) {nf++;afisare(x,k);}
else
{
k=k+1;
x[k]=0;
}
else k=k-1;
}
printf(" Numarul permutarilor de %d obiecte
este egal cu %d \n",n,nf);
getch();
}

Pentru un numr de trei obiecte programul furnizeaz rezultatele:


Generarea permutarilor de n obiecte

244

Bazele programrii calculatoarelor


Numarul de obiecte n = 3
Tastati obiectele
a [ 1 ] = 22
a [ 2 ] = 11
a [ 3 ] = 33
1 ( 22, 11, 33 )
2 ( 22, 33, 11 )
3 ( 11, 22, 33 )
4 ( 11, 33, 22 )
5 ( 33, 22, 11 )
6 ( 33, 11, 22 )
Numarul permutarilor de 3 obiecte este egal cu 6

81. Program pentru generarea combinrilor de n obiecte luate


cte p i a numrului lor
// Generare combinari de n luate cate p si a
numarului lor // cnp
#include "stdio.h"
#include "conio.h"
typedef int sir[100];
sir a,x;
int p,i,k,n,as,ev,cnp;
void succesor(sir x,int k,int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void validare(sir x,int k, int &ev)
{
ev=1;
if((k>=2) && !(a[x[k]]>a[x[k-1]]))
ev=0;
}
void afisare(sir x, int k)
{
int i;
printf(" %d ( ",cnp);
for(i=1;i<=k-1;i++)
printf("%d, ",a[x[i]]);

245

Metode de programare
printf("%d ) \n",a[x[i]]);
}
int main()
{
printf(" Generarea combinarilor de n luate cate p
\n");
cnp=0;
printf(" Numarul de obiecte n = ");
scanf("%d",&n);
printf(" Tastati obiectele \n");
for(i=1;i<=n;i++)
{
printf(" a [ %d ] = ",i);
scanf("%d",&a[i]);
}
printf(" Combinari luate cate p = ");
scanf("%d",&p);
if(p<=n)
{
k=1;x[k]=0;
while(k>0)
{
do
{
succesor(x,k,as);
if(as)
validare(x,k,ev);
}while(as && !ev);
if(as)
if(k==p) {cnp++;afisare(x,k);}
else
{
k=k+1;
x[k]=0;
}
else k=k-1;
}
printf(" Numarul combinarilor de %d obiecte
luate cate %d este egal cu %d \n",n,p,cnp);
getch();
}
else
printf(" Eroare in date: p>n \n");
getch();
}

246

Bazele programrii calculatoarelor

Generarea combinarilor de n luate cate p


Numarul de obiecte n = 4
Tastati obiectele
a [ 1 ] = 11
a [ 2 ] = 22
a [ 3 ] = 33
a [ 4 ] = 44
Combinari luate cate p = 3
1 ( 11, 22, 33 )
2 ( 11, 22, 44 )
3 ( 11, 33, 44 )
4 ( 22, 33, 44 )
Numarul combinarilor de 4 obiecte luate cate 3 este
egal cu 4

82. Program pentru generarea aranjamentelor de n obiecte luate


cte p i a numrului lor
// Generare aranjamente de n luate cate p si a
numarului // lor anp
#include "stdio.h"
#include "conio.h"
typedef int sir[100];
sir a,x;
int p,i,k,n,as,ev,anp;
void succesor(sir x,int k,int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void validare(sir x,int k, int &ev)
{
ev=1;
for(i=1;i<=k-1;i++)
if(x[k]==x[i])
ev=0;

247

Metode de programare
}
void afisare(sir x, int k)
{
int i;
printf("%d ( ",anp);
for(i=1;i<=k-1;i++)
printf("%d, ",a[x[i]]);
printf("%d ) \n",a[x[i]]);
}
int main()
{
printf(" Generarea aranjamentelor de n luate
cate p \n");
anp=0;
printf(" Numar de obiecte n = ");
scanf("%d",&n);
printf(" Tastati obiectele \n");
for(i=1;i<=n;i++)
{
printf(" a [ %d ] = ",i);
scanf("%d",&a[i]);
}
printf(" Aranjamente luate cate p = ");
scanf("%d",&p);
if(p<=n)
{
k=1;x[k]=0;
while(k>0)
{
do
{
succesor(x,k,as);
if(as)
validare(x,k,ev);
}while(as && !ev);
if(as)
if(k==p) {anp++;afisare(x,k);}
else
{
k=k+1;
x[k]=0;
}
else k=k-1;
}
printf(" Numarul de aranjamente de %d luate
cate %d este egal cu %d\n",n,p,anp);

248

Bazele programrii calculatoarelor


getch();
}
else
printf(" Eroare in date: p>n \n");
getch();
}
Generarea aranjamentelor de n luate cate p
Numar de obiecte n = 4
Tastati obiectele
a [ 1 ] = 11
a [ 2 ] = 32
a [ 3 ] = 21
a [ 4 ] = 43
Aranjamente luate cate p = 2
1 ( 11, 32 )
2 ( 11, 21 )
3 ( 11, 43 )
4 ( 32, 11 )
5 ( 32, 21 )
6 ( 32, 43 )
7 ( 21, 11 )
8 ( 21, 32 )
9 ( 21, 43 )
10 ( 43, 11 )
11 ( 43, 32 )
12 ( 43, 21 )
Numarul de aranjamente de 4 luate cate 2 este egal
cu 12

83. Program pentru generarea produsului cartezian a m mulimi


// Produsul cartezian a m multimi finite
#include "stdio.h"
#include "conio.h"
typedef int sir[100];
sir x,n;
int a[50][50],k,as,ev,i,j,m,nel;
void succesor(sir x,int k,int &as)
{
if(x[k]<n[k])
{

249

Metode de programare
as=1;
x[k]=x[k]+1;
}
else
as=0;
}
void validare(int &ev)
{
ev=1;
}
void afisare(sir x,int k)
{
printf(" %d (",nel);
for(i=1;i<=k;i++)
printf(" %d ",a[i][x[i]]);
printf(")\n");
}
int main()
{
int i;
nel=0;
printf(" Produs cartezian \n");
printf(" Numarul de multimi m = ");
scanf("%d",&m);
printf(" Tastati elementele multimilor \n");
for(i=1;i<=m;i++)
{
printf(" Numarul de elemente ale multimii %d
n[%d] = ",i,i);
scanf("%d",&n[i]);
printf(" Tastati elementele multimii %d \n",i);
for(j=1;j<=n[i];j++)
{
printf(" a%d[%d] =",i,j);
scanf("%d",&a[i][j]);
}}
printf(" Produsul cartezian a celor %d multimi are
elementele :\n",m);
k=1;x[k]=0;
while(k>0)
{
do
{
succesor(x,k,as);
if(as)
validare(ev);

250

Bazele programrii calculatoarelor


}while(as&&!ev);
if(as)
if(k==m) {nel++;afisare(x,k);}
else
{
k=k+1;
x[k]=0;
}
else
k=k-1;
}
printf(" Numarul total de elemete este egal cu %d
\n",nel);
getch();
}

Ca exemplu de control am considerat cazul a trei mulimi cu cte


dou, trei i respectiv patru elemente. Dup rulare se obin
rezultatele:
Produs cartezian
Numarul de multimi m = 3
Tastati elementele multimilor
Numarul de elemente ale multimii 1 n[1] = 2
Tastati elementele multimii 1
a1[1] =1
a1[2] =2
Numarul de elemente ale multimii 2 n[2] = 3
Tastati elementele multimii 2
a2[1] =11
a2[2] =22
a2[3] =33
Numarul de elemente ale multimii 3 n[3] = 4
Tastati elementele multimii 3
a3[1] =66
a3[2] =77
a3[3] =88
a3[4] =99
Produsul cartezian a celor 3 multimi are elementele
:
1 ( 1 11 66 )
2 ( 1 11 77 )
3 ( 1 11 88 )

251

Metode de programare
4 ( 1 11 99 )
5 ( 1 22 66 )
6 ( 1 22 77 )
7 ( 1 22 88 )
8 ( 1 22 99 )
9 ( 1 33 66 )
10 ( 1 33 77 )
11 ( 1 33 88 )
12 ( 1 33 99 )
13 ( 2 11 66 )
14 ( 2 11 77 )
15 ( 2 11 88 )
16 ( 2 11 99 )
17 ( 2 22 66 )
18 ( 2 22 77 )
19 ( 2 22 88 )
20 ( 2 22 99 )
21 ( 2 33 66 )
22 ( 2 33 77 )
23 ( 2 33 88 )
24 ( 2 33 99 )
Numarul total de elemete este egal cu 24

84. Program pentru rezolvarea problemei celor n dame


Pe o tabl de ah cu n linii i coloane se gsesc n dame.
Problema const n determinarea poziiilor celor n dame pe tabla
de ah astfel nct acestea s nu se atace, pe fiecare linie,
coloan i diagonal a tablei de ah s existe o singur dam.
Fie k i xk , k 1, 2, , n , linia i respectiv coloana pe care se
gsete dama k . Evident dou dame i i k , i k , se gsesc pe
aceeai coloan dac i numai dac xk xi , pe aceeai linie dac
i numai dac k i (condiie fals prin ipoteza i k ) i pe
aceeai diagonal dac i numai dac xk xi k i . Astfel,
condiiile interne care sunt verificate de funcia validare sunt:
xk xi (pe aceeai coloan s nu existe dou dame) i
xk xi k i (pe aceeai diagonal s nu existe dou dame),

252

Bazele programrii calculatoarelor

pentru fiecare i 1, 2, , k 1 . Programul genereaz toate soluiile


rezultat i numrul total de soluii.
// Problema celor n dame si numarul solutiilor
rezultat
#include "stdio.h"
#include "conio.h"
#include "math.h"
#include "stdlib.h"
typedef int sir[100];
sir x;
int i,n,k,as,ev;
void succesor(sir x,int k,int&as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else as=0;
}
void validare(sir x,int k,int &ev)
{
ev=1;
for(i=1;i<=k-1;i++)
if(x[k]==x[i] || (k-i==abs(x[k]-x[i])))
ev=0;
}
void afisare(sir x,int k)
{
for(i=1;i<=k;i++)
printf(" Dama %d este pe linia %d si coloana %d
\n",i,i,x[i]);
}
int main()
{
int nsol;
printf(" Problema celor n dame \n");
printf(" Numarul de dame n = ");
scanf("%d",&n);
k=1;x[k]=0;nsol=1;
while(k>0)
{
do

253

Metode de programare
{
succesor(x,k,as);
if(as)
validare(x,k,ev);
}while(as&&!ev);
if(as)
if(k==n) {
printf("
Solutia %d
\n",nsol);
nsol++;
afisare(x,k);
getch();
}
else
{
k++;
x[k]=0;
}
else k--;
}
printf(" Numarul total de solutii rezultat este %d
\n",nsol-1);
getch();
}
Problema celor n dame
Numarul de dame n = 4
Solutia 1
Dama 1 este pe linia 1 si coloana
Dama 2 este pe linia 2 si coloana
Dama 3 este pe linia 3 si coloana
Dama 4 este pe linia 4 si coloana
Solutia 2
Dama 1 este pe linia 1 si coloana
Dama 2 este pe linia 2 si coloana
Dama 3 este pe linia 3 si coloana
Dama 4 este pe linia 4 si coloana
Numarul total de solutii rezultat

2
4
1
3
3
1
4
2
este 2

12.6. Backtracking recursiv


n variant recursiv se definete funcia backtracking:
254

Bazele programrii calculatoarelor


void back(int k)
{
if(sol(k)) afisare(x,k);
else
{
init(k);
while(succesor(x,k,as))
if(validare(x,k,ev))
back(k+1);
}
}

Funcia are un singur parametru de tip ntreg, care este indice al


vectorului soluie. Funcia testeaz dac s-a generat o soluie prin
apelul funciei sol. Definiia funciei sol este:
int sol(int k)
{
return k==n+1;
}

Dac s-a obinut o soluie, aceasta este afiat de funcia


afisare, cu aceeai definiie ca n cazul nerecursiv. Dac nu sa obinut o soluie, se iniializeaz nivelul k cu valoarea aflat
naintea tuturor valorilor posibile. Iniializarea este fcut de
funcia init:
void init(int k)
{
x[k]=0;
}
Funcia init efectueaz iniializarea lui xk cu o valoare prin care

se indic faptul c, pn la acel moment, nu a fost selectat nici o


alternativ pentru poziia k a vectorului x ;
Dup iniializare, se genereaz succesiv toate valorile din
mulimea S k . Pentru generarea acestor valori se folosete funcia
succesor, modificat fa de cazul nerecursiv n sensul c
returneaz valoarea variabilei de tip ntreg as:
255

Metode de programare
int succesor(sir x,int k,int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else
as=0;
return as;
}

Pentru fiecare valoare generat se testeaz cu funcia validare


condiiile de continuare. Funcia validare este modificat fa de
cazul nerecursiv prin returnarea valorii de tip ntreg a variabilei
ev:
int validare(sir x,int k, int &ev)
{
ev=1;
for(i=1;i<=k-1;i++)
if(!conditie)
ev=0;
return ev;
}

Dac condiiile de continuare sunt ndeplinite se genereaz


urmtoarea valoare pentru componenta k prin apelul recursiv al
funciei back.
n funcia main() se apeleaz funcia back cu parametrul 1
deoarece algoritmul pleac de la componenta de indice 1.

12.7. Exemple
Relum exemplele din seciunea 12.3.2 pentru care folosim
metoda backtracking n variant recursiv.
85. Program pentru generarea permutrilor unei mulimi de n
obiecte. n acest caz, S1 S 2 S n a1 , a2 , an . Alternativele
256

Bazele programrii calculatoarelor

posibile pentru starea iniial corespund alegerilor pentru prima


poziie dintr-un vector soluie.
Funcia init(k) realizeaz iniializarea elementului xk cu
valoarea 0, pentru a marca faptul c, pn la momentul curent,
nu a fost selectat nici o alternativ pentru xk . Funcia succesor
returneaz valoarea 1 a variabilei as dac elementul xk are
succesor n mulimea a1 , a2 ,
are succesor n mulimea

an , sau 0 dac elementul xk nu

a1, a2 ,

an .

Funcia validare

returneaz valoarea 1 a variabilei ev dac i numai dac vectorul


x x1 , x2 , , xk calculat pn la momentul curent satisface
condiia intern a problemei, adic are componentele distincte.
// Generare permutari de n obiecte si a numarului
lor nf
#include "stdio.h"
#include "conio.h"
typedef int sir[100];
sir a,x;
int i,k,n,as,ev,nf;
void init(int k)
{
x[k]=0;
}
int sol(int k)
{
return k==n+1;
}
int succesor(sir x,int k,int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else
as=0;
return as;
}
int validare(sir x,int k, int &ev)

257

Metode de programare
{
ev=1;
for(i=1;i<=k-1;i++)
if(!(x[k]!=x[i]))
ev=0;
return ev;
}
void afisare(sir x, int k)
{
int i;
printf(" %d ( ",nf);
for(i=1;i<=k-2;i++)
printf("%d, ",a[x[i]]);
printf("%d ) \n",a[x[i]]);
}
void back(int k)
{
if(sol(k)) {nf++;afisare(x,k);}
else
{
init(k);
while(succesor(x,k,as))
if(validare(x,k,ev))
back(k+1);
}
}
int main()
{
printf(" Generarea permutarilor de n obiecte
\n");
nf=0;
printf(" Numarul de obiecte n = ");
scanf("%d",&n);
printf(" Tastati obiectele \n");
for(i=1;i<=n;i++)
{
printf(" a [ %d ] = ",i);
scanf("%d",&a[i]);
}
back(1);
printf(" Numarul permutarilor de %d obiecte este
egal cu %d \n",n,nf);
getch();
}

258

Bazele programrii calculatoarelor

Pentru trei obiecte programul furnizeaz rezultatele:


Generarea permutarilor de n obiecte
Numarul de obiecte n = 3
Tastati obiectele
a [ 1 ] = 1
a [ 2 ] = 2
a [ 3 ] = 3
1 ( 1, 2, 3 )
2 ( 1, 3, 2 )
3 ( 2, 1, 3 )
4 ( 2, 3, 1 )
5 ( 3, 1, 2 )
6 ( 3, 2, 1 )
Numarul permutarilor de 3 obiecte este egal cu 6

86. Program pentru generarea combinrilor de n obiecte luate


cte p i a numrului lor
// Generare combinari de n luate cate p si a
numarului lor // cnp
#include "stdio.h"
#include "conio.h"
typedef int sir[100];
sir a,x;
int p,i,k,n,as,ev,cnp;
void init(int k)
{
x[k]=0;
}
int sol(int k)
{
return k==p+1;
}
int succesor(sir x,int k,int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else
as=0;

259

Metode de programare
return as;
}
int validare(sir x,int k, int &ev)
{
ev=1;
for(i=1;i<=k-1;i++)
if((k>=2) && !(a[x[k]]>a[x[k-1]]))
ev=0;
return ev;
}
void afisare(sir x, int k)
{
int i;
printf(" %d ( ",cnp);
for(i=1;i<=k-2;i++)
printf("%d, ",a[x[i]]);
printf("%d ) \n",a[x[i]]);
}
void back(int k)
{
if(sol(k)) {cnp++;afisare(x,k);}
else
{
init(k);
while(succesor(x,k,as))
if(validare(x,k,ev))
back(k+1);
}
}
int main()
{
printf(" Generarea combinarilor de n luate cate
p \n");
cnp=0;
printf(" Numarul de obiecte n = ");
scanf("%d",&n);
printf(" Tastati obiectele \n");
for(i=1;i<=n;i++)
{
printf(" a [ %d ] = ",i);
scanf("%d",&a[i]);
}
printf(" Combinari luate cate p = ");
scanf("%d",&p);
if(p<=n)
{

260

Bazele programrii calculatoarelor


back(1);
printf(" Numarul combinarilor de %d obiecte
luate cate %d este egal cu %d \n",n,p,cnp);
}
else printf(" Eroare %d > %d \n ",p,n);
getch();
}

Pentru exemplificare am generat toate combinrile de patru


obiecte luate cte dou.
Generarea combinarilor de n luate cate p
Numarul de obiecte n = 4
Tastati obiectele
a [ 1 ] = 1
a [ 2 ] = 2
a [ 3 ] = 3
a [ 4 ] = 4
Combinari luate cate p = 2
1 ( 1, 2 )
2 ( 1, 3 )
3 ( 1, 4 )
4 ( 2, 3 )
5 ( 2, 4 )
6 ( 3, 4 )
Numarul combinarilor de 4 obiecte luate cate 2 este
egal cu 6

87. Program pentru generarea aranjamentelor de n obiecte luate


cte p i a numrului lor
// Generare aranjamente de n luate cate p si a
numarului // lor anp
#include "stdio.h"
#include "conio.h"
typedef int sir[100];
sir a,x;
int p,i,k,n,as,ev,anp;
void init(int k)
{
x[k]=0;

261

Metode de programare
}
int sol(int k)
{
return k==p+1;
}
int succesor(sir x,int k,int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else
as=0;
return as;
}
int validare(sir x,int k, int &ev)
{
ev=1;
for(i=1;i<=k-1;i++)
if(x[k]==x[i])
ev=0;
return ev;
}
void afisare(sir x, int k)
{
int i;
printf(" %d ( ",anp);
for(i=1;i<=k-2;i++)
printf("%d, ",a[x[i]]);
printf("%d ) \n",a[x[i]]);
}
void back(int k)
{
if(sol(k)) {anp++;afisare(x,k);}
else
{
init(k);
while(succesor(x,k,as))
if(validare(x,k,ev))
back(k+1);
}
}
int main()
{

262

Bazele programrii calculatoarelor


printf(" Generarea aranjamentelor de n luate
cate p \n");
anp=0;
printf(" Numarul de obiecte n = ");
scanf("%d",&n);
printf(" Tastati obiectele \n");
for(i=1;i<=n;i++)
{
printf(" a [ %d ] = ",i);
scanf("%d",&a[i]);
}
printf(" Aranjamente luate cate p = ");
scanf("%d",&p);
if(p<=n)
{
back(1);
printf(" Numarul de aranjamente de %d luate cate
%d este egal cu %d\n",n,p,anp);
}
else
printf(" Eroare %d > %d \n ",p,n);
getch();
}

Pentru n=4 i p=2 se obtin rezultatele:


Generarea aranjamentelor de n luate cate p
Numarul de obiecte n = 4
Tastati obiectele
a [ 1 ] = 1
a [ 2 ] = 2
a [ 3 ] = 3
a [ 4 ] = 4
Aranjamente luate cate p = 2
1 ( 1, 2 )
2 ( 1, 3 )
3 ( 1, 4 )
4 ( 2, 1 )
5 ( 2, 3 )
6 ( 2, 4 )
7 ( 3, 1 )
8 ( 3, 2 )
9 ( 3, 4 )
10 ( 4, 1 )

263

Metode de programare
11 ( 4, 2 )
12 ( 4, 3 )
Numarul de aranjamente de 4 luate cate 2 este egal
cu 12

88. Program pentru generarea produsului cartezian a m mulimi


// Produsula cartezian a m multimi finite
#include "stdio.h"
#include "conio.h"
typedef int sir[100];
sir x,n;
int a[50][50],k,as,ev,i,j,m,nel;
void init(int k)
{
x[k]=0;
}
int sol(int k)
{
return k==m+1;
}
int succesor(sir x,int k,int &as)
{
if(x[k]<n[k])
{
as=1;
x[k]=x[k]+1;
}
else
as=0;
return as;
}
int validare(int &ev)
{
ev=1;
return ev;
}
void afisare(sir x, int k)
{
printf(" %d
(",nel);
for(i=1;i<=k-1;i++)
printf(" %d ",a[i][x[i]]);
printf(")\n");
}

264

Bazele programrii calculatoarelor


void back(int k)
{
if(sol(k)) {nel++;afisare(x,k);}
else
{
init(k);
while(succesor(x,k,as))
if(validare(ev))
back(k+1);
}
}
int main()
{
int i;
nel=0;
printf(" Produs cartezian \n");
printf(" Numarul de multimi m = ");
scanf("%d",&m);
printf(" Tastati elementele multimilor \n");
for(i=1;i<=m;i++)
{
printf(" Numarul de elemente ale multimii %d
n[%d] = ",i,i);
scanf("%d",&n[i]);
printf(" Tastati elementele multimii %d \n",i);
for(j=1;j<=n[i];j++)
{
printf(" a%d[%d] =",i,j);
scanf("%d",&a[i][j]);
}}
printf(" Produsul cartezian a celor %d multimi are
elementele :\n",m);
back(1);
printf(" Numarul total de elemete este egal cu %d
\n",nel);
getch();
}

Ca exemplu de control am considerat cazul a trei mulimi cu cte


dou, trei i respectiv patru elemente. Dup rulare se obin
rezultatele:
Produs cartezian

265

Metode de programare
Numarul de multimi m = 3
Tastati elementele multimilor
Numarul de elemente ale multimii 1 n[1] = 2
Tastati elementele multimii 1
a1[1] =11
a1[2] =22
Numarul de elemente ale multimii 2 n[2] = 3
Tastati elementele multimii 2
a2[1] =1
a2[2] =2
a2[3] =3
Numarul de elemente ale multimii 3 n[3] = 4
Tastati elementele multimii 3
a3[1] =6
a3[2] =7
a3[3] =8
a3[4] =9
Produsul cartezian a celor 3 multimi are elementele
:
1
( 11 1 6 )
2
( 11 1 7 )
3
( 11 1 8 )
4
( 11 1 9 )
5
( 11 2 6 )
6
( 11 2 7 )
7
( 11 2 8 )
8
( 11 2 9 )
9
( 11 3 6 )
10
( 11 3 7 )
11
( 11 3 8 )
12
( 11 3 9 )
13
( 22 1 6 )
14
( 22 1 7 )
15
( 22 1 8 )
16
( 22 1 9 )
17
( 22 2 6 )
18
( 22 2 7 )
19
( 22 2 8 )
20
( 22 2 9 )
21
( 22 3 6 )
22
( 22 3 7 )
23
( 22 3 8 )
24
( 22 3 9 )
Numarul total de elemete este egal cu 24

266

Bazele programrii calculatoarelor

89. Program pentru rezolvarea problemei celor n dame


// Problema celor n dame si numarul solutiilor
rezultat
#include "stdio.h"
#include "conio.h"
// Problema celor n dame
#include "math.h"
#include "stdlib.h"
typedef int sir[100];
sir x;
int i,n,k,as,ev,nsol;
void init(int k)
{
x[k]=0;
}
int sol(int k)
{
return k==n+1;
}
int succesor(sir x,int k,int &as)
{
if(x[k]<n)
{
as=1;
x[k]=x[k]+1;
}
else
as=0;
return as;
}
int validare(sir x,int k, int &ev)
{
ev=1;
for(i=1;i<=k-1;i++)
if(x[k]==x[i] || (k-i==abs(x[k]-x[i])))
ev=0;
return ev;
}
void afisare(sir x, int k)
{
for(i=1;i<=k-1;i++)
printf(" Dama %d este pe linia %d si coloana %d
\n",i,i,x[i]);
}

267

Metode de programare
void back(int k)
{
if(sol(k))
{
printf("
Solutia %d
\n",nsol);
nsol++;
afisare(x,k);
}
else
{
init(k);
while(succesor(x,k,as))
if(validare(x,k,ev))
back(k+1);
}
}
int main()
{
nsol=1;
printf(" Problema celor n dame \n");
printf(" Numarul de dame n = ");
scanf("%d",&n);
back(1);
printf(" Numarul total de solutii rezultat este %d
\n",nsol-1);
getch();
}

Soluiile pentru cazul a patru dame sunt:


Problema celor n dame
Numarul de dame n = 4
Solutia 1
Dama 1 este pe linia 1 si coloana
Dama 2 este pe linia 2 si coloana
Dama 3 este pe linia 3 si coloana
Dama 4 este pe linia 4 si coloana
Solutia 2
Dama 1 este pe linia 1 si coloana
Dama 2 este pe linia 2 si coloana
Dama 3 este pe linia 3 si coloana
Dama 4 este pe linia 4 si coloana
Numarul total de solutii rezultat

268

2
4
1
3
3
1
4
2
este 2

Bazele programrii calculatoarelor

12.8. Metoda Greedy


Algoritmii de tip greedy se caracterizeaz prin luarea unor decizii
rapide care duc la gsirea unei soluii a problemei. Nu
ntotdeauna asemenea decizii rapide duc la o soluie optim, dar
vom vedea c exist anumite tipuri de probleme unde se pot
obine soluii optime sau foarte apropiate de optim. n traducere
din limba englez cuvntul greedy nseamn lacom. Algoritmii
de tip greedy vor s construiasc ntr-un mod ct mai rapid
soluia problemei.
Algoritmii de tip Greedy se aplic problemelor ale cror date de
intrare sunt organizate sub forma unei mulimi A i pentru care
se cere determinarea unei submulimi B A care s
ndeplineasc anumite condiii astfel nct submulimea B s fie
acceptat ca soluie posibil.
n general pot s existe mai multe submulimi B A care s
reprezinte soluii posibile ale problemei. Dintre toate aceste
submulimi B se pot selecta, conform unui anumit criteriu,
anumite submulimi B* care reprezint soluii optime ale
problemei. Scopul este de a gsi, dac este posibil, una din
submulimile B* . Dac acest lucru nu este posibil, atunci scopul
este gsirea unei mulimi B care s fie ct mai aproape de
submulimile B* , conform criteriului de optimalitate impus.
Construirea submulimii B se face printr-un ir de decizii. Iniial
se pornete cu mulimea vid, B . Fiecare decizie const n
alegerea unui element din mulimea A , analiza lui i eventual
introducerea lui n submulimea B . n funcie de modul n care se
iau aceste decizii, submulimea B se va apropia mai mult sau
mai puin de soluia optim B* . n cazul ideal vom avea B B* .
Algoritmii de tip greedy nu urmresc s determine toate soluiile
posibile i s aleag dintre ele, conform criteriului de optimalitate
impus, soluiile optime. Dup cum spune i numele, algoritmii de
tip greedy sunt caracterizai prin lcomie i nu au rbdarea s
investigheze toate variantele posibile de alegere a soluiei. Ei
ncep construirea unei soluii pornind de la mulimea vid. La
fiecare pas se ia cte o decizie i se extinde soluia cu cte un
element. La fiecare pas se analizeaz cte un element din
269

Metode de programare

mulimea A i se decide dac s fie sau nu inclus n


submulimea B care se construiete. Astfel se progreseaz de la
mulimea vid cu un ir de submulimi intermediare
cu proprietatea B1 B2 Bk A ,
, B1, B2 , , Bk ,
pn cnd se obine o soluie final B .
Nu exist un standard de implementare a metodei greedy, care
s fie general valabil pentru toate problemele care pot fi rezolvate
cu aceast metod. Implementarea metodei difer de la o
problem la alta. Exist dou variante de principiu pentru
implementarea algoritmilor de tip greedy. Prima variant folosete
funciile: sel, test, adaug i afis. Funcia sel este are rolul de
a selecta urmtorul element x din mulimea A care s fie
prelucrat. Funcia test verific dac elementul x poate fi
adugat soluiei intermediare Bi astfel nct noua soluie Bi1 care
s-ar obine s fie o soluie valid. Funcia adaug adaug
elementul testat x mulimii Bi1 . Funcia afis listeaz soluia
optim, elementele mulimii B* . Prezentm n continuare
pseudocodul pentru aceast variant greedy. Se consider c
numrul de elemente al mulimii A este egal cu n.
greedy ( A, B)

B
pentru i 0; i n; i
repeta
x sel ( A)

if (test ( B, x))

adaug ( B, x)
afis ( B)
Dificultatea n aceast variant const n scrierea funciei sel.
Dac funcia sel este bine conceput, atunci putem fi siguri c
soluia B gsit este o soluie optim. Dac funcia sel nu este
foarte bine conceput, atunci soluia B va fi doar o soluie
posibil i nu va fi optim. Ea se poate apropia ns mai mult sau
270

Bazele programrii calculatoarelor

mai puin de soluia optim B , n funcie de criteriul de selecie


implementat.
n a doua variant de implementare a algoritmului greedy se face
mai nti o prelucrare a mulimii A de funcia prel. Practic se
face o sortare a elementelor mulimii A , conform unui anumit
criteriu. Dup sortare, elementele vor fi prelucrate direct n
ordinea rezultat. Dac prelucrarea mulimii A este bine fcut,
atunci se va ajunge n mod sigur la o soluie optim. Altfel se va
obine doar o soluie posibil, mai mult sau mai puin apropiat de
optim. Prezentm n continuare descrirea n limbajul pseudocod
pentru aceast a doua variant a algoritmului greedy.
greedy ( A, B)
*

B
prel A
pentru i 0; i n; i
repeta
x A[i ]

if (test ( B, x))

adaug ( B, x)
afis ( B)
Funciile test, adaug i afis joac acelai rol ca n prima
variant de implementare a metodei greedy.
Prezentm n continuare exemple de probleme rezolvate cu
metoda greedy.
90. Fie A o mulime cu n elemente numere reale. S se
determine mulimea B cu numr maxim de elemente a cror
sum s fie maxim.
Este evident c pentru ca numrul elementelor mulimii B
s fie maxim i suma lor s fie maxim, trebuie ca B s conin
numai elemente pozitive i nule. Funcia alege selecteaz
elemetele mulimii A. Funcia posibil returneaz o valaore
nenul (1) dac a fost selectat un element pozitiv sau nul din
271

Metode de programare

mulimea A, sau valoarea zero n cazul seleciei unei valori


negative. Funcia adauga construiete mulimea B cu elementele
selectate din mulimea A care satisfac codiia de nenegativitate.
Funcia afiseaza tiparete elementele mulimii B, numrul i
suma lor. Programul este un exemplu a primei metode de
implementare a algoritmului greedy.

12.9. Exemple
// Problema sumei maxime
#include "stdio.h"
#include "conio.h"
int n,m,i;
float sel(float a[])
{
return a[i];
}
int test(float b[],float x)
{
if(x>=0)
return 1;
else return 0;
}
void adaug(float b[],float x)
{
b[m]=x;
m++;
}
void afis(float b[])
{
float s;
if(m)
{
printf(" Multimea B are %d elemente \n",m);
for(i=0,s=0;i<m;s+=b[i],i++)
printf(" B [ %d ]= %f \n",i,b[i]);
s+=b[i];
printf(" Suma elementelor multimii B este %f \n",s);
}
else
printf(" Multimea B este vida \n");
}
void greedy(float a[],float b[])

272

Bazele programrii calculatoarelor


{

float x;
for(i=0;i<n;i++)
{
x=sel(a);
if(test(b,x))
adaug(b,x);
}
afis(b);

}
int main()
{
float a[50],b[50];
printf(" Numarul de elemente ale multimii n =
");
scanf("%d",&n);
printf(" Elementele multimii A : \n");
for(i=0;i<n;i++)
{
printf(" A [ %d ] = ",i);
scanf("%f",&a[i]);
}
greedy(a,b);
getch();
}

Un exemplu de rulare este:


Numarul de elemente ale multimii n = 5
Elementele multimii A :
A [ 0 ] = 2.
A [ 1 ] = 3.
A [ 2 ] = -9.
A [ 3 ] = -5.
A [ 4 ] = 7.
Multimea B are 3 elemente
B [ 0 ]= 2.000000
B [ 1 ]= 3.000000
B [ 2 ]= 7.000000
Suma elementelor multimii B este 12.000000

Pentru cazul n care mulimea A are numai elemente negative, B


este vid.
273

Metode de programare
Numarul de elemente ale multimii n = 3
Elementele multimii A :
A [ 0 ] = -9.
A [ 1 ] = -1.
A [ 2 ] = -2.
Multimea B este vida

91. Program pentru determinarea multiplilor de k dintr-o mulime


de numere naturale cu metoda greedy.
// Multipli de k dintr-o multime de numere naturale
#include "stdio.h"
#include "conio.h"
int n,m,i;
float sel(int a[])
{
return a[i];
}
int test(int b[],int x, int k)
{
if(x%k==0)
return 1;
else return 0;
}
void adaug(int b[],int x)
{
b[m]=x;
m++;
}
void afis(int b[],int k)
{
if(m)
{
printf(" Multimea A are %d multipli de %d \n",m,k);
for(i=0;i<m;i++)
printf(" B [ %d ]= %d \n",i,b[i]);
}
else
printf(" Submultimea multiplilor de %d este vida
\n",k);
}
void greedy(int a[],int b[], int k)
{
int x;

274

Bazele programrii calculatoarelor


for(i=0;i<n;i++)
{
x=sel(a);
if(test(b,x,k))
adaug(b,x);
}
afis(b,k);

}
int main()
{
int a[50],b[50],k;
printf(" Numarul de elemente ale multimii n =
");
scanf("%d",&n);
printf(" Elementele multimii A : \n");
for(i=0;i<n;i++)
{
printf(" A [ %d ] = ",i);
scanf("%d",&a[i]);
}
printf(" Divizorul comun k = ");
scanf("%d",&k);
greedy(a,b,k);
getch();
}

Pentru n=6 i k=5 se obine:


Numarul de elemente ale multimii n = 6
Elementele multimii A :
A [ 0 ] = 2
A [ 1 ] = 0
A [ 2 ] = 1
A [ 3 ] = 5
A [ 4 ] = 4
A [ 5 ] = 15
Divizorul comun k = 5
Multimea A are 3 multipli de 5
B [ 0 ]= 0
B [ 1 ]= 5
B [ 2 ]= 15

Pentru o mulime fr multipli de k se obine:


275

Metode de programare
Numarul de elemente ale multimii n = 6
Elementele multimii A :
A [ 0 ] = 2
A [ 1 ] = 3
A [ 2 ] = 4
A [ 3 ] = 1
A [ 4 ] = 12
A [ 5 ] = 22
Divizorul comun k = 5
Submultimea multiplilor de 5 este vida

92. Problema continu a rucsacului. Presupunem c avem la


dispoziie un rucsac n care se poate transporta o greutate
maxim fixat G. Cu acest rucsac urmeaz a fi transportate n
obiecte de greuti cunoscute. Pentru fiecare obiect se cunoate
beneficiul transportrii lui la destinaie. Problema const n
determinarea obiectelor care vor fi transportate la destinaie astfel
nct beneficiul total al transportului s fie maxim. Dac un obiect
nu poate fi divizat, problema se numete continu. Dac
obiectele pot fi divizate problema se numeste discret.
Rezolvarea problemei continue a rucsacului se poate face cu un
algoritm de tip greedy. Se calculeaz pentru fiecare obiect
raportul dintre beneficiu i greutatea lui. Se sorteaz descresctor
vectorul acestor rapoarte. Ct timp nu a fost completat greutatea
total a rucsacului i mai exist obiecte n afara lui se selecteaz
obiectul cu raportul maxim dintre beneficiu i greutate. Dac
obiectul nu ncape n ntregime n rucsac se determin fraciunea
din obiect care se poate transporta. Programul afiseaz ordinea
introducerii obiectelor n rucsac, informaiile referitoare la
obiectele introduse si beneficiul total al transportului. Programul
este un exemplu a celei de a doua metode de implementare a
algoritmului greedy.
// Problema continua a rucsacului
#include "stdio.h"
#include "conio.h"
int n,m,i,j;

276

Bazele programrii calculatoarelor


float G,grcurent,dif,benef,f;
struct ob
{
int nr;
float g;
float benef;
float raport;
}obiect[50];
struct r
{
int nr;
float g;
float benef;
float raport;
float f;
}rucsac[50];
void prel(void)
{
int auxx;
float aux;
for(i=0;i<n;i++)
for(j=i+1;j<n;j++)
if(obiect[i].raport<=obiect[j].raport)
{
aux=obiect[j].raport;
obiect[j].raport=obiect[i].raport;
obiect[i].raport=aux;
aux=obiect[j].benef;
obiect[j].benef=obiect[i].benef;
obiect[i].benef=aux;
aux=obiect[j].g;
obiect[j].g=obiect[i].g;
obiect[i].g=aux;
auxx=obiect[j].nr;
obiect[j].nr=obiect[i].nr;
obiect[i].nr=auxx;
}
}
int test()
{
dif=G-grcurent;
if(dif)
return 1;
else return 0;
}
void adaug()

277

Metode de programare
{
if(obiect[i].g<=dif)
{
rucsac[m].nr=obiect[i].nr;
rucsac[m].g=obiect[i].g;
rucsac[m].benef=obiect[i].benef;
rucsac[m].raport=obiect[i].raport;
grcurent+=rucsac[m].g;
benef+=rucsac[m].benef;
rucsac[m].f=1.;
m++;
}
else
{
rucsac[m].nr=obiect[i].nr;
rucsac[m].g=dif;
rucsac[m].benef=(obiect[i].benef/obiect[i].g)*dif;
rucsac[m].raport=rucsac[m].benef/rucsac[m].g;
benef+=rucsac[m].benef;
rucsac[m].f=rucsac[m].g/obiect[i].g;
m++;
}
}
void afis(void)
{
if(m)
{
printf(" Rucsacul contine %d obiecte \n",m);
for(i=0;i<m;i++)
{
printf(" Obiectul %d \n",rucsac[i].nr);
printf("\t\t Greutate %f \n",rucsac[i].g);
printf("\t\t Fractiunea de greutate %f
\n",rucsac[i].f);
printf("\t\t Beneficiu %f \n",rucsac[i].benef);
printf("\t\t Raport beneficiu/greutate %f
\n",rucsac[i].raport);
}
printf(" Beneficiul total este %f \n",benef);
}
else
printf(" Rucsacul este gol \n");
}
void greedy(void)
{
prel();

278

Bazele programrii calculatoarelor


for(i=0;i<n;i++)
{
if(test())
adaug();
}
afis();
}
int main()
{
printf(" Numarul de obiecte n = ");
scanf("%d",&n);
printf(" Greutatea si beneficiul: \n");
for(i=0;i<n;i++)
{
printf(" Greutatea obiectului %d = ",i);
scanf("%f",&obiect[i].g);
printf(" Beneficiul adus de obiectul %d =
",i);
scanf("%f",&obiect[i].benef);
obiect[i].raport=obiect[i].benef/obiect[i].g;
obiect[i].nr=i;
}
printf(" Greutatea maxima admisa : ");
scanf("%f",&G);
greedy();
getch();
}

Pentru exemplul de mai jos suma tuturor greutilor obiectelor


este mai mic dect capacitatea rucsacului.
Numarul de obiecte n = 3
Greutatea si beneficiul:
Greutatea obiectului 0 = 4
Beneficiul adus de obiectul 0 = 8
Greutatea obiectului 1 = 2
Beneficiul adus de obiectul 1 = 6
Greutatea obiectului 2 = 5
Beneficiul adus de obiectul 2 = 20
Greutatea maxima admisa : 100
Rucsacul contine 3 obiecte
Obiectul 2
Greutate 5.000000
Fractiunea de greutate 1.000000

279

Metode de programare
Obiectul 1

Beneficiu 20.000000
Raport beneficiu/greutate 4.000000
Greutate 2.000000
Fractiunea de greutate 1.000000
Beneficiu 6.000000
Raport beneficiu/greutate 3.000000

Obiectul 0

Greutate 4.000000
Fractiunea de greutate 1.000000
Beneficiu 8.000000
Raport beneficiu/greutate 2.000000
Beneficiul total este 34.000000
Beneficiul total este 34.000000

Pentru exemplul de mai jos suma tuturor greutilor obiectelor


este mai mare dect capacitatea rucsacului. Repartiia obiectelor
n rucsac este:
Numarul de obiecte n = 3
Greutatea si beneficiul:
Greutatea obiectului 0 = 4
Beneficiul adus de obiectul 0 = 8
Greutatea obiectului 1 = 2
Beneficiul adus de obiectul 1 = 6
Greutatea obiectului 2 = 5
Beneficiul adus de obiectul 2 = 20
Greutatea maxima admisa : 8
Rucsacul contine 3 obiecte
Obiectul 2
Greutate 5.000000
Fractiunea de greutate 1.000000
Beneficiu 20.000000
Raport beneficiu/greutate 4.000000
Obiectul 1
Greutate 2.000000
Fractiunea de greutate 1.000000
Beneficiu 6.000000
Raport beneficiu/greutate 3.000000
Obiectul 0
Greutate 1.000000
Fractiunea de greutate 0.250000

280

Bazele programrii calculatoarelor


Beneficiu 2.000000
Raport beneficiu/greutate 2.000000
Beneficiul total este 28.000000

12.10. Metoda programrii dinamice


Metoda programrii dinamice se utilizeaz la rezolvarea unor
probleme de optimizare care se refer la un proces. Procesul
parcurge strile s0 , s1, , sn , s0 este starea iniial, sn este starea
final. La fiecare trecere din starea si n starea si 1 se ia decizia
di1 , i 0,1, , n 1 pentru a se realiza acest lucru. La fiecare pas
i , decizia di1 poate fi aleas din mai multe decizii posibile, cea
care se ia trebuie s fie optim. n general deciziile di care
conduc la soluia problemei, trebuie s fie optime satisfcnd
principiul optimalitii al lui R.Bellmann. Acest principiu spune c,
dac strilor s0 , s1, , sn le corespund deciziile d1, d2 , , dn optime,
atunci, oricare ar fi i , la irul de stri s0 , s1, , si le corespund
aceleai decizii optime d1 , d 2 , , di iar la irul de stri si , si1, , sn
corespund aceleai decizii optime di1, di2 , , dn .
Dac principiul optimalitii este satisfcut, metoda programrii
dinamice presupune scrierea unei relaii de recuren pentru
decizia de la pasul i . n general, relaiile de recuren sunt de
dou tipuri:
d i f d1 , d 2 , , d i 1
cunoscut sub numele de relaia
retrospectiv sau metoda napoi, n care funcia f determin
decizia de la pasul i 1 innd cont de deciziile luate anterior;
d i f d i 1 , d i 2 , , d n cunoscut sub numele de relaia
prospectiv sau metoda nainte, n care funcia f determin
decizia de la pasul i 1 innd cont de viitorul procesului.
Nu exist criterii pe baza crora s se poat decide aplicarea
metodei programrii dinamice unei probleme date. putem formula
dou proprieti care sugereaz o soluie prin programare
281

Metode de programare

dinamic. Exist dou proprieti ale problemei de rezolvat care


recomand aplicarea metodei programrii dinamice. Problema de
rezolvat se poate descompune n subprobleme i soluia optim a
problemei deriv din soluiile optime ale subproblemelor sale.
Aceast proprietate poate s conduc fie la metoda metoda
Divide et Impera, fie la metoda Greedy. A doua proprietate a
problemei de rezolvat const n posibilitatea suprapunerii
subproblemelor, ceea ce elimin ideea metodei Divide et Impera
datorit creterii timpului de execuie al programului, prin execuia
repetat a codului asociat unor subprobleme. Prin metoda
programrii dinamice fiecare subproblem se rezolv o singur
dat.
Rezolvarea unei probleme cu metoda programrii dinamice
presupune parcurgerea urmtoarelor etape:
identificarea subproblemele problemei date;
definirea unei structuri de date, care s memoreze soluiile
subproblemelor;
definirea unei relaii de recuren care s caracterizeze
substructura optimal a problemei;
-

implementarea relaiei de recuren.

12.11. Exemple
Vom exemplifica aplicarea metodei programrii dinamice unor
probleme clasice.
93. Problema nmulirii optime a matricilor. Fie n matrici
Ap0 p1 , Ap1 p2 , , Apn1 pn . Deoarece nmulirea matricilor este
asociativ, produsul Ap0 p1 Ap1 p2 Apn1 pn poate fi calculat n mai
multe moduri. Se pune problema determinrii acelei asocieri a
factorilor pentru care produsul celor n matrici se poate efectua cu
un numr minim de nmuliri elementare. Este cunoscut faptul c
numrul de nmuiri necesare efectrii produsului a dou matrice
M pq M qr este egal cu p q r . De exemplu, pentru matricele
282

Bazele programrii calculatoarelor

A22 , A23 , A34 , produsul A22 A23 A34 se poate calcula folosind
asocierea

A22 A23 A34 ,

care

2 2 3 2 3 4 36

necesit

nmuliri elementare. Folosind asocierea A22 A23 A34 sunt


necesare 2 3 4 2 2 4 40 nmuliri elementare. Calculul
produsului Ap0 p1 Ap1 p2 Apn1 pn , se reduce la calculul unui produs
de forma

p0 p1

Ap1 p2

Apk 1 pk Apk pk 1 Apk 1 pk 2

Apn1 pn , ceea

ce este adevrat i pentru produsele din cele dou paranteze.


Astfel, rezolvarea problemei se reduce la rezolvarea
subproblemelor de forma Api pi1 Ap j p j 1 cu 1 i j n .
Subproblemele nu sunt independente deoarece produsele
Api pi1 Ap j p j 1 i Api1 pi2 Ap j1 p j2 au n comun produsul
Api1 pi2

Ap j p j1 . Vom defini matricea soluie sol , cu elementele

sol[i ][ j ], 1 i j n n care sol[i ][ j ] este numrul minim de


nmuliri
elementare
necesare
calculului
produsului
Api1 pi Ap j1 p j . Evident sol[1][n] reprezint numrul minim de

nmuliri
elementare
necesare
calculului
produsului
Ap0 p1 , Ap1 p2 , , Apn1 pn . Pentru ca asocierea factorilor produsului
Ap0 p1 Ap1 p2

factorilor
Ap0 p1 Ap1 p2

Ap0 p1 Ap1 p2

Apn1 pn s fie optim este necesar ca asocierea

Apk 1 pk Apk pk 1 Apk 1 pk 2

Apn1 pn

produselor

i Apk pk 1 Apk 1 pk 2 Apn1 pn s fie optim.


Pentru a determina numrul minim de nmuliri elementare pentru
calculul produsului Api1 pi Ap j1 p j se fixeaz poziia parantezei k
Apk 1 pk

n toate modurile, i k j 1 i se alege varianta care conduce la


numrul minim de nmuliri. Pentru k fixat, numrul de nmuliri
este egal cu numrul de nmuliri necesare efecturii produsului
Api1 pi Apk 1 pk , egal cu sol[i ][k ] , adunat cu numrul de nmuliri
necesare

efecturii

produsului

Apk pk 1

Ap j1 p j ,

egal

cu

sol[k 1][ j ] , la care trebuie adunat numrul de nmuliri necesare

283

Metode de programare

efecturii produsului celor dou matrice rezultate, egal cu


pi1 pk p j . Rezult c elementele matricei sol trebuie s
satisfac relaia de recuren:
i
sol[i][ j ] min sol[i][k ] sol[k 1][ j ] p[i 1]* p[k ]* p[ j ]
ik j

sol[i ][i ] 0 i 1, 2,

,n .

n program sunt definite funciile prodopt care rezolv relaia de


recuren i funcia afis care afieaz asocierea optim a
factorilor produsului Ap1 p2 , Ap2 p3 , , Apn pn1 . n funcia main se
tiprete numrul minim de nmuliri elementare. Programul
primete la intrare numrul de matrici i pentru fiecare matrice
numrul de linii i coloane. Dac condiia de nlnuire nu este
satisfcut se semnaleaz eroare. Programul afieaz asocierea
optim a factorilor produsului i numrul minim de nmuliri
elementare.
// Inmultirea optima a unui sir de matrice
#include "stdio.h"
#include "conio.h"
#include "limits.h"
long int sol[100][100];
int n,p[100],lc;
void prodopt()
{
int nm, i, j, k, kminim;
long int min;
for (nm=2; nm<=n; nm++)
for (i=1; i<=n-nm+1; i++)
{
j=i+nm-1;
min=INT_MAX;
for (k=i; k<j; k++)
if (min>sol[i][k]+sol[k+1][j]+p[i-1]*p[k]*p[j])
{
min=sol[i][k]+sol[k+1][j]+p[i-1]*p[k]*p[j];
kminim=k;
}
sol[i][j]=min;
sol[j][i]=kminim;
}

284

Bazele programrii calculatoarelor


}
void afis(int i, int j)
{
if (i==sol[j][i])
printf("A%d * ",i);
else
{
printf("(");
afis(i,sol[j][i]);
printf(") * ");
}
getch();
if (j==sol[j][i]+1)
printf("A%d",j);
else
{
printf("(");
afis(sol[j][i]+1,j);
printf(")");
}
}
int main()
{
int m,sw;
int lin[100],col[100];
printf(" Numar de matrici : ");
scanf("%d",&n);
for(m=1;m<=n;m++)
{
sw=1;
while(sw)
{
printf(" Matricea %d \n\n",m);
printf(" Numrul de linii ale matricei %d : ",m);
scanf("%d",&lin[m]);
if(col[m-1]!=lin[m] && m>1)
printf(" Conditia de inlantuire nu este satisfacuta
\n");
else
{
sw=0;
printf(" Numrul de coloane ale matricei %d : ",m);
scanf("%d",&col[m]);
}}}
for(m=1,p[0]=lin[1];m<=n;p[m]=col[m],m++);
prodopt();

285

Metode de programare
printf("\n\n Asocierea optima a factorilor
produsului este: \n\n");
afis(1,n);
printf("\n\n Numarul minim de inmultiri este egal cu
%d \n",sol[1][n]);
getch();
}

Un prim exemplu de rulare este pentru exemplul tratat mai sus:


determinarea asocierii optime a factorilor produsului
A22 A23 A34 . Pentru asocierea A22 A23 A34 am obinut
numrul minim de nmuliri elementare egal cu 36.
Numar de matrici : 3
Matricea 1
Numrul de linii ale matricei 1 : 2
Numrul de coloane ale matricei 1 : 2
Matricea 2
Numrul de linii ale matricei 2 : 2
Numrul de coloane ale matricei 2 : 3
Matricea 3
Numrul de linii ale matricei 3 : 5
Conditia de inlantuire nu este satisfacuta
Matricea 3
Numrul de linii ale matricei 3 : 3
Numrul de coloane ale matricei 3 : 4
Asocierea optima a factorilor produsului este:
(A1 * A2) * A3
Numarul minim de inmultiri este egal cu 36

Urmtorul exemplu de rulare este pentru determinarea asocierii


optime a factorilor produsului a 5 matrici A34 A45 A52 A23 A35 .
286

Bazele programrii calculatoarelor


Numar de matrici : 5
Matricea 1
Numrul de linii ale matricei 1 : 3
Numrul de coloane ale matricei 1 : 4
Matricea 2
Numrul de linii ale matricei 2 : 1
Conditia de inlantuire nu este satisfacuta
Matricea 2
Numrul de linii ale matricei 2 : 4
Numrul de coloane ale matricei 2 : 5
Matricea 3
Numrul de linii ale matricei 3 : 2
Conditia de inlantuire nu este satisfacuta
Matricea 3
Numrul de linii ale matricei 3 : 5
Numrul de coloane ale matricei 3 : 2
Matricea 4
Numrul de linii ale matricei 4 : 2
Numrul de coloane ale matricei 4 : 3
Matricea 5
Numrul de linii ale matricei 5 : 3
Numrul de coloane ale matricei 5 : 5
Asocierea optima a factorilor produsului este:
(A1 * (A2 * A3)) * (A4 * A5)
Numarul minim de inmultiri este egal cu 124

94. Problema determinrii celui mai lung subir comun a dou


iruri. Un subir al unui ir dat se obine din irul dat prin
eliminarea unor termeni sau a nici unui termen. Fiind dat irul
X x1 , x2 , , xn , irul Z z1 , z2 , , zk este subir al irului X
dac exist un ir strict cresctor de indici din X , i1 , i2 ,

, ik ,

287

Metode de programare

astfel nct, pentru orice j 1, 2,

, k , are loc egalitatea xi j z j .

Considerm irurile de numere reale X xi 1in i Y y j

1 j m

Problema const n determinarea celui mai lung subir comun al


celor
dou
iruri.
De
exemplu
pentru
irurile
X 1.1, 2.3, 2.5,8., 7.,3.2
i
Y 9.8, 5.6,1.1, 2.3, 2.5, 8., 7.,3.2 exist subirurile comune

1.1, 2.3, 2.5 , 2.3, 2.5, 7.,3.2 , 1.1, 2.3, 2.5, 7.,3.2 , 7.,3.2 .
Cel mai lung subir comun este 1.1, 2.3, 2.5, 7.,3.2 i are
lungimea 5. Fie X k x1 , x2 , , xk subirul primilor k termeni al
lui X , numit prefixul de ordin k al lui X , Yp y1, y2 ,

, yp

prefixul de ordinul p al irului Y . Determinarea subirului comun


de lungime maxim al prefixelor X k i Y p este o subproblem.
Fie l X k , Yp lungimea maxim a subirurilor comune prefixelor

X k i Y p . Problema iniial se reduce la determinarea valorii


l X n , Ym i a subirului comun corespunztor. Evident are loc

egalitatea:

l X k 1 , Yp1

l X k , Yp
max l X k 1, Yp , l X k , Yp1

daca

X k Yp

daca

X k Yp

Definim matricea l n1 m1 , n care l[ k ][ p ] este lungimea celui mai


lung subir comun al prefixelor X k i Y p . Elementele matricei l
verific relaiile:
l[k ][0] 0 k 1, 2, , n , l[0][ p ] 0 p 1, 2, , m ,
1 l[k 1][ p 1]
daca x[k ] y[ p ]

l[k ][ p ]
. Programul
max l[k ][ p 1], l[k 1][ p ] daca x[k ] y[ p ]
primete la intrare dimensiunile i termenii celor dou iruri. Se
afieaz, dac exist, lungimea i termenii subirului comun

288

Bazele programrii calculatoarelor


maximal al celor dou iruri. Funcia sir implementeaz relaiile

de recuren.
// Cel mai lung subsir comun si lungimea lui
#include "stdio.h"
#include "conio.h"
float x[50],y[50],l[50][50],subsir[50];
int k,p;
void sir(int n,int m)
{
for(k=1;k<=n;l[k][0]=0,k++);
for(p=1;p<=m;l[0][p]=0,p++);
for (k=1; k<=n; k++)
for (p=1; p<=m; p++)
if (x[k]==y[p])
l[k][p]=1+l[k-1][p-1];
else
l[k][p]=(l[k-1][p]>l[k][p-1]) ? l[k-1][p] : l[k][p1];
}
int main()
{
int n,m,i;
printf(" Numarul de termeni ai sirului X : ");
scanf("%d",&n);
printf(" Termenii sirului X \n");
for(i=1;i<=n;i++)
{
printf(" x [ %d ] = ",i);
scanf("%f",&x[i]);
}
printf(" Numarul de termeni ai sirului Y : ");
scanf("%d",&m);
printf(" Termenii sirului Y \n");
for(i=1;i<=m;i++)
{
printf(" y [ %d ] = ",i);
scanf("%f",&y[i]);
}
sir(n,m);
printf(" Lungimea subsirului comun maximal este %d
\n",(int)l[n][m]);
if(l[n][m])
{
printf(" Cel mai lung subsir comun este: \n");

289

Metode de programare
for (i=0,k=n,p=m;l[k][p];)
if (x[k]==y[p])
{
subsir[i++]=x[k];
k--;
p--;
}
else
if (l[k][p]==l[k-1][p])
k--;
else
p--;
for (k=0;k<=i-1; k++)
printf(" %f ",subsir[k]);
}
else
printf(" Nu exista subsiruri comune \n");
getch();
}

Pentru irurile X 1.1, 2.3, 2.5,8., 7.,3.2 i


Y 9.8, 5.6,1.1, 2.3, 2.5, 8., 7.,3.2 programul furnizeaz:
Numarul de termeni ai sirului X : 6
Termenii sirului X
x [ 1 ] = 1.1
x [ 2 ] = -2.3
x [ 3 ] = 2.5
x [ 4 ] = 8.
x [ 5 ] = -7.
x [ 6 ] = 3.2
Numarul de termeni ai sirului Y : 8
Termenii sirului Y
y [ 1 ] = 9.8
y [ 2 ] = -5.6
y [ 3 ] = 1.1
y [ 4 ] = -2.3
y [ 5 ] = 2.5
y [ 6 ] = -8.
y [ 7 ] = -7.
y [ 8 ] = 3.2
Lungimea subsirului comun maximal este 5
Cel mai lung subsir comun este:

290

3.200000

-7.000000

Bazele programrii calculatoarelor


2.500000 -2.300000 1.100000

Pentru dou iruri disjuncte, care nu au subiruri comune,


programul furnizeaz rezultatele:
Numarul de termeni ai sirului X : 3
Termenii sirului X
x [ 1 ] = 1.
x [ 2 ] = 2.
x [ 3 ] = 3.
Numarul de termeni ai sirului Y : 4
Termenii sirului Y
y [ 1 ] = 5.
y [ 2 ] = 6.
y [ 3 ] = 7.
y [ 4 ] = 8.
Lungimea subsirului comun maximal este 0
Nu exista subsiruri comune

95. Rezolvm problema 94 pentru cazul irurilor de caractere. Cu


mici modificri care se impun, referitoare la lucrul cu caractere,
programul este:
// Cel mai lung subsir comun si lungimea lui
#include "stdio.h"
#include "conio.h"
int l[50][50];
char x[50],y[50],subsir[50];
int k,p;
void sir(int n,int m)
{
for(k=1;k<=n;l[k][0]=0,k++);
for(p=1;p<=m;l[0][p]=0,p++);
for (k=1; k<=n; k++)
for (p=1; p<=m; p++)
if (x[k]==y[p])
l[k][p]=1+l[k-1][p-1];
else
l[k][p]=(l[k-1][p]>l[k][p-1]) ? l[k-1][p] : l[k][p1];
}

291

Metode de programare
int main()
{
int n,m,i;
printf(" Numarul de termeni ai sirului X : ");
scanf("%d",&n);
printf(" Termenii sirului X \n");
for(i=1;i<=n;i++)
{
printf(" x [ %d ] = ",i);
x[i]=getche();
printf("\n");
}
printf(" Numarul de termeni ai sirului Y : ");
scanf("%d",&m);
printf(" Termenii sirului Y \n");
for(i=1;i<=m;i++)
{
printf(" y [ %d ] = ",i);
y[i]=getche();
printf("\n");
}
sir(n,m);
printf(" Lungimea subsirului comun maximal este %d
\n",(int)l[n][m]);
if(l[n][m])
{
printf(" Cel mai lung subsir comun este: \n");
for (i=0,k=n,p=m;l[k][p];)
if (x[k]==y[p])
{
subsir[i++]=x[k];
k--;
p--;
}
else
if (l[k][p]==l[k-1][p])
k--;
else
p--;
for (k=0;k<=i-1; k++)
printf(" %c ",subsir[k]);
}
else
printf(" Nu exista subsiruri comune \n");
getch();
}

292

Bazele programrii calculatoarelor

Rezultatele pentru cazul n care X a, b, c, d i Y w, a, s, c, d


sunt:
Numarul de termeni ai sirului X : 4
Termenii sirului X
x [ 1 ] = a
x [ 2 ] = b
x [ 3 ] = c
x [ 4 ] = d
Numarul de termeni ai sirului Y : 5
Termenii sirului Y
y [ 1 ] = w
y [ 2 ] = a
y [ 3 ] = s
y [ 4 ] = c
y [ 5 ] = d
Lungimea subsirului comun maximal este 3
Cel mai lung subsir comun este:
d c a

293

ntrebri de autoevaluare

1133.. NNTTRREEBBRRII DDEE AAUUTTO


OE
EV
VA
ALLU
UA
AR
RE
E
13.1. Uniti lexicale
1. Care comentariu nu este corect?
a. // un comentariu
b. /* un comentariu */
c. // un comentariu //
d. /* un comentariu
e. //* un comentariu
2. Care element nu este un tip de dat primar n limbajul C?
a. int
b. float
c. real
d. char
e. double
3. Care element nu este un cuvnt cheie al limbajului C?
a. while
b. for
c. if
d. main
e. short
4. Care element nu poate fi identificator ntr-un program C?
a. flota
b. Float
c. _float
d. float
e. float_

13.2. Expresii. Operanzi. Operatori


5. Indicai valoarea lui x in urma instruciunilor:
short int a=10, x;
x = sizeof(25.-a);

294

Bazele programrii calculatoarelor

a. 15 (adic 25 -10)
b. 25 (adic valoarea cea mai mare)
c. 4 sau 8 (depinde de implementarea tipului double)
d. 2 (adic sizeof(a), a fiind singura variabila din expresie)
e. eroare (operatorul sizeof nu se aplica unei expresii)
6. Care este valoarea lui a dup secvena urmtoare?
int a = 4;
a==-5+2;

a. secvena conine o eroare


b. a are valoarea 4
c. a are valoarea -3
d. a are valoarea 7
e. a are valoarea -7
7. Indicai valoarea lui x in urma instruciunilor:
x=0; z=1;
x=x==(y=!z);

a. 0
b. eroare deoarece operatorul de inegalitate (!=) este scris invers
c. 1
d. alta valoare
e. rezultatul depinde de valoarea lui y
8. Indicai ce afieaz urmtoarele instruciuni:
int a=3, b=5;
printf (a=b ? "egale" : "diferite");

a. diferite
b. egale
c. instruciunile conin erori de sintaxa
d. true
e. false
9. Indicai valoarea lui x in urma instruciunilor:
int x=0, y=1, z=0;
x=x||!y&&z;

a. expresie eronata neadmis n limbaj


295

ntrebri de autoevaluare

b. 0
c. 1
d. 2
e. nici una din variante
10. Indicai valoarea lui x in urma instruciunilor:
int x=2, y=1, z;
x=x&&y||z;

a. depinde de valoarea iniial a lui z


b. 1
c. 0
d. false
e. alta valoare
11. Care este valoarea expresiei 6 & 8?
a. 4
b. 5
c. 1
d. 3
e. 0
12. Indicai valorile lui t, x si y in urma instruciunilor:
int t, x=2, y=3;
t=++x<y++?++x:y++;

a. 1, 2, 2
b. 2, 2, 2
c. 1, 2, 3
d. 2, 2, 3
e. 4, 3, 5
13. Indicai ce afieaz urmtoarele instruciuni:
int a=3, b=7%4;
printf(a==b ? "egale" : "diferite");

a. instruciunile conin erori de sintaxa


b. true
c. egale
d. diferite
296

Bazele programrii calculatoarelor

e. false

13.3. Instruciuni
14. Ce afieaz secvena de cod urmtoare?
int i, j;
for(i=1,j=1;i<4; j=++i) {
int k=1;
printf("%d%d%d", i, j, k);
k++;
}

a. 111222333
b. 111122133
c. 111221331
d. 111211311
e. 111111111
15. Ce afieaz secvena de cod urmtoare?
int i, j;
for(i=1,j=1;i<4; i++) {
int k=1;
printf("%d%d%d", i, j, k);
j++;k++;
}

a. 111221331
b. 111222333
c. 111111111
d. 111211311
e. 111122133
16. Ce afieaz secvena de cod urmtoare?
int i=3;
while(--i);
printf("%d",i);

a. 2 1 0
b. 3 2 1
c. 0
32
21
297

ntrebri de autoevaluare

17. Ce afieaz secvena de cod urmtoare?


int i;
for(i=19;i>0;i%7)
printf("%d", i);

a. 191919191919... (19 la infinit)


b. 195
c. 197
d. 19
e. altceva

13.4. Funcii standard de intrare/ieire


18. n ce bibliotec se gsesc funciile standard de intrare/ieire?
a. conio.h
b. stdlib.h
c. math.h
d. stdio.h
e. string.h
19. Ce afieaz urmtoarea secven de program?
printf("%03c %#x %o %.0s", '9', 9, 9, "9");

a. 009 0x9 9
b. 009 0x9 11
c. 009 0x9 11 9
d. 009 0x9 9 9
e. 9 9 9 9
20. Ce afieaz urmtoarea secven de program dac datele
introduse de la tastatur sunt Decembrie 2006:
int a; char x[10];
scanf("%s%2d", x, &a);
printf("%d, %.3s", a, x);

a. 20, Dec
b. 2006, Dec
c. 2006, Decembrie
d. 2006 Decembrie
e. nimic
298

Bazele programrii calculatoarelor

13.5. Tipuri de date compuse


21. Care afirmaie este corecta referitor la iniializarea:
char mesaj[]={'G', 'r', 'e', 's', 'i', 't', 0};

a. iniializarea este corecta


b. iniializarea nu este permisa in cazul vectorilor de caractere
c. iniializarea este eronata (lipsete dimensiunea vectorului)
d. iniializarea este eronata (0 nu este scris intre apostrofi)
e. iniializarea este eronata (trebuiau scrise ghilimele in loc de
apostrofi)
22. Cte elemente are vectorul declarat n secvena urmtoare:
double v[30] = {1, 5, 18};

a. 30 de elemente
b. 3 elemente
c. 4 elemente
d. 0 elemente
e. secvena nu este corect
23. Care instruciunea afieaz numele coloanei a 3-a din linia a
6-lea?
struct {
struct {
char nume[20];
int latime;
} coloane[5];
} linii[10];

a. printf("Nume: %s", linii[5].coloane[2].nume);


b. printf("Nume: %s", linii[6].coloane[3].nume);
c. printf("Nume: %s", linii[5].coloane[3].nume);
d. printf("Nume: %s", linii[6].coloane[2].nume);
e. printf("Nume linii[6].coloane[3].nume");

13.6. Funcii
24. Care este valoarea expresiei f(21)?
int f(int n) {
if (n<3) return n;

299

ntrebri de autoevaluare
else return f(n/2);
}

a. 1
b. 2
c. 3
d. 0
e. 5
25. Care este valoarea expresiei f(5)?:
int f(int n) {
if (n<2) return 1;
else return n * f(n-1);
}

a. 120
b. 5
c. 1
d. 6
e. 12345
26. Care este valoarea expresiei f(2,5)?
int f(int n, int m) {
if (m<1) return 1;
else return n * f(n, m-1);
}

a. 2
b. 5
c. 32
d. 1
e. 0
27. Care este valoarea expresiei f(5)?
int f(int n) {
if (n<2) return 1;
else return n / f(n-1);
}

a. 1
b. 5
c. 0
300

Bazele programrii calculatoarelor

d. 1.2
e. 15
28. Care este valoarea expresiei f(5,0)?
int f(int n, int m) {
if (n<0) return f(n+1, m+n);
else if (n>0) return f(n-1, m+n);
else return m;
}

a.15
b. 5
c. 0
d. -5
e. 12345
29. Care este valoarea expresiei f(6)?
int f(int n) {
if (n<2) return 1;
else return n / f(n-1);
}

a. 1
b. 5
c. 0
d. 1.2
e. 6

13.7. Pointeri i gestiunea dinamic a memoriei


30. n ce bibliotec se gsete funcia realloc?
a. conio.h
b. realloc.h
c. malloc.h
d. stdio.h
e. string.h
31. Care instruciune afieaz numele coloanei a 3-a din linia
indicat prin pointerul linie?
struct {
struct {

301

ntrebri de autoevaluare
char nume[20];
int latime;
} coloane[5];
} *linie;

a. printf("Nume: %s", linie->coloane[2].nume);


b. printf("Nume: %s", linie.coloane[3].nume);
c. printf("Nume: %s", linie->coloane->nume);
d. printf("Nume: %s", linie.coloane->nume);
e. printf("Nume linie->coloane->nume");
32. Care sunt valorile din vectorul v dup secvena de program:
int v[] = {3, 4, 5}, *p;
p = v+1; *p = 6;
*p++ = 2;

a. 3 6 2
b. 3 2 5
c. 6 5 5
d. 3 7 5
e. 3 7 2

13.8. Funcii pentru iruri de caractere


33. Precizai valoarea expresiei strlen(test) dac variabila test
este declarata astfel:
char test[]="";

a. 1, deoarece se numr caracterele i terminatorul de sir


b. 0, deoarece se numr caracterele fr terminatorul de sir
c. -1, deoarece nu e precizata dimensiunea irului de caractere
d. 2 sau 4, deoarece variabila test este un pointer
e. alta valoare dect cele de la celelalte rspunsuri
34. Ce afieaz secvena de program:
char s[] = "out.txt";
printf("%s", strrchr(s,'t'));

a. out.txt
b. txt
c. out.
302

Bazele programrii calculatoarelor

d. t
e. fiierul este gol
35. Precizai valoarea expresiei strlen(test) dac variabila test
este declarata astfel:
char test[100]="Examen";

a. 7, deoarece se numr caracterele i terminatorul de sir


b. 6, deoarece se numr caracterele fr terminatorul de sir
c. 100, deoarece aceasta este dimensiunea vectorului
d. 2 sau 4, deoarece variabila test este un pointer
e. alta valoare dect cele de la celelalte rspunsuri
36. Care afirmaie este corect referitor la secvena de program:
char s1[100]="daca", s2[50]="inveti",
s3[]="raspunzi";
strcat(s2, s3);
strcat(s1, s2);
puts(s1);

a. afieaz daca nvei rspunzi


b. afieaz rspunzi daca nvei
c. este greit (prin concatenare se suprascriu zone de memorie
nealocate)
d. este greit (vectorii de caractere nu pot fi folosii ca iruri de
caractere)
e. afieaz daca rspunzi nvei
37. Indicai valoarea returnat in urma apelului:
strcmp("ghicitoare", "ghici");

a. o valoare pozitiva
b. o valoare negativa
c. zero
d. apel eronat deoarece compara doua constante
e. apel eronat deoarece compara doua adrese

13.9. Funcii matematice


38. Ce funcie nu face parte din biblioteca math.h?
a. sin
303

ntrebri de autoevaluare

b. fabs
c. strlen
d. pow
e. sqrt
39. Ce constant predefinit are valoarea numrului ?
a. PI
b. M_PI
c. pi
d. m_pi
e. Pi

13.10. Funcii pentru gestiunea fiierelor


40. Ce conine fiierul out.txt dup execuia secvenei de cod:
char s[] = "out.txt";
FILE *fout = fopen(s, "wt");
fprintf(fout, "", strlen(s));
fclose(fout);

a. 7
b. 5
c. 123
d. 0
e. fiierul este gol
41. Ce conine fiierul out.txt dup execuia secvenei de cod:
char s[] = "out.txt";
FILE *fout = fopen(s, "wt");
fprintf(fout, "%d", strlen(s));
fclose(fout);

a. 7
b. 5
c. 123
d. 0
e. fiierul este gol
42. Ce conine fiierul out.txt dup execuia secvenei de cod:
char s[] = "out.txt";
FILE *fout = fopen(s, "wt");

304

Bazele programrii calculatoarelor


fprintf(fout, s);
fclose(fout);

a. out.txt
b. t.txt
c. txt.tuo
d. t
e. fiierul este gol
43. In ce biblioteca este declarata fprintf?
a. file.h
b. stdio.h
c. strlib.h
d. math.h
e. string.h
44. Care instruciune nchide fiierul asociat variabilei fis?
a. fclose(fis);
b. close(fis)
c. fclose fis;
d. close fis;
e. *fis = fclose;
Tabel 13.1 Rspunsuri la ntrebri

1
6

R
d
b

2
7

R
c
c

3
8

R
d
b

4
9

e
2
c
7
a
2
c
7
a
2
a

e
3
a
8
a
3
a
8
b
3
a

c
4
d
9
a
4
a
9
b
4
c

R
d
b

5
1

R
c
b

0
1
1
6
2
1
2
6
3
1
3

1
2
2
3
3

1
2
2
3
3

5
1
0
2
5
2
0
3
5
3

305

ntrebri de autoevaluare

6
4
1

306

7
a
2

8
a
3

9
b
4

0
4

Bazele programrii calculatoarelor

1144.. A
ANNEEXXAA 11 M
MEEDDIIUULL DDEE PPRRO
OG
GR
RA
AM
MA
AR
RE
ED
DEEVV--C
C++++
Dev-C++, realizat de Bloodshed Software, este un mediu
integrat de dezvoltare pentru limbajul C/C++ pentru Windows,
gratuit i complet. Un mediu integrat de dezvoltare este un pachet
de programe care permit editare, compilarea, executarea i
verificarea programelor direct din programul principal.
Dev-C++ folosete varianta Mingw a compilatorului GCC
(GNU Compiler Collection), recunoscut pentru calitile sale.
Printre calitile mediului Dev-C++ se numr:
funcii avansate de editare, cutare i nlocuire, tiprire,
CVS (Concurrent Versioning System), list To Do, etc;
interfa n diverse limbi (printre care i limba romn);
colorarea i completarea codului;
depanator de programe integrat;
crearea rapid a programelor Windows (cu sau fr
interfa grafic) i a bibliotecilor (statice i dinamice);
manager de instrumente (pentru integrarea altor unelte de
dezvoltare n mediul Dev-C++);
manager de proiecte (pentru gestionarea uoar a
proiectelor medii i mari);
manager pe pachete (pentru instalarea uoara a unor
module suplimentare).

14.1. Instalare
Programul de instalare poate fi descrcat gratuit de pe
situl Bloodshed (la adresa http://www.bloodshed.net) sau de pe
SourceForge (la adresa http://sourceforge.net/projects/dev-cpp).
V recomandm s descrcai programul de instalare care
include compilatorul Mingw, instalarea fiind mai simpl.
Dup descrcare pornii programul de instalare i urmai
paii indicai de acesta. Noi vom discuta etapele necesare pentru
Dev-C++ versiunea 4.9.9.2. La pornirea programului de instalare,
acesta v cere s dezinstalai eventuale versiuni mai vechi ale
307

Anexa 1 Mediul de programare Dev-C++

sale, dup care v cere s selectai limba n care se va desfura


procesul de instalare. Selectai limba romn.

Urmtoarea fereastr v afieaz contractul de licen


GNU, care v d dreptul s folosii i s distribuii gratis
programul. Apsai butonul De acord. Urmeaz etapa de
selectare a componentelor. Setrile implicite sunt corecte, aa c
putei apsa pe butonul nainte >.

n continuare, trebuie s selectai folderul unde va fi


instalat programul. n majoritatea cazurilor, valoarea implicit este
bun, deci apsai butonul Instalare. Urmtoarea fereastr
afieaz operaiile efectuate n timpul instalrii. Dac apar erori,
308

Bazele programrii calculatoarelor

pornii din nou instalarea i selectai un alt folder la pasul anterior.


Dac nu apar erori, programul de instalare v ntreab dac dorii
ca programul s fie accesibil tuturor utilizatorilor calculatorului.
Rspunsul depinde de dumneavoastr.
Ultima fereastr v informeaz c instalarea s-a ncheiat
cu succes i v ofer posibilitatea de a porni programul.

14.2. Configurare
14.2.1. Prima pornire
La prima pornire, programul trebuie configurat pentru a
satisface preferinele dumneavoastr. Vom folosi limba englez,
deoarece opiunile mediului Dev-C++ seamn cu opiunile din
alte medii de programare. Valorile pentru restul opiunilor depind
de dumneavoastr. Apsai pe Next.

Urmtoarea fereastr v ofer posibilitatea s activai


funcia de completare a codului. Aceast funcie poate fi util
deoarece Dev-C++ afieaz prototipul funciilor atunci cnd
consider necesar, dar consum memorie suplimentar i
necesit timp de ncrcare suplimentar. V recomandm s nu o
activai.
309

Anexa 1 Mediul de programare Dev-C++

Ultima fereastr v anun c Dev-C++ a fost configurat


corect i este gata de lucru. Apsai pe butonul Ok.

14.2.2. Editorul
n mod implicit, la pornire Dev-C++ afieaz fereastra Tip
of the day cu sfaturi utile pentru utilizatorii nceptori. Dac
observai c v-ai nsuit aceste sfaturile, putei bifa opiunea
Dont display tips at startup, nainte de a nchide fereastra.
Pentru a configura editorul, selectai din meniul Tools
opiunea Editor options. n seciunea General, efectuai
urmtoarele verificri/modificri:
bifai Auto indent, astfel programele vor fi mai uor de
urmrit, deoarece instruciunile vor fi deplasate automat la
stnga, n funcie de context;
bifai Use Tab Character, astfel apsarea tastei Tab
introduce n fiier un caracter tab, n loc de spaii; setai
valoarea Tab size la 4;
debifai Smart tabs, altfel programele vor fi greu de
urmrit, datorit indentrii inegale a liniilor;
debifai Keep Trailing Spaces, astfel fiierele nu vor
conine spaii inutile;
310

Bazele programrii calculatoarelor

bifai Enhanced Home Key, astfel prima apsare a tastei


Home, deplaseaz cursorul la primul caracter afiabil din
rnd, iar a doua apsare la nceputul rndului.

n seciunea Display, putei modifica tipul i mrimea


fontului n funcie de preferinele dumneavoastr. Indiferent de
mrime, v recomandm folosirea unui font proporional precum
Courier New, Lucida Console sau Terminal. De asemenea, bifai
opiunea Line Numbers.

14.2.3. Tastele rapide


Pentru a configura tastele rapide, selectai din meniul
Tools opiunea Configure Shortcuts. Selectai comanda creia
vrei s-i asociai o combinaie de taste i apsai tastele
respective. De exemplu, pentru comanda Edit::Date/Time setai
combinaia de taste Ctrl+T. Astfel, cnd vei edita un program,
apsnd Ctrl+T se va introduce automat data i ora curent.
Pentru a anula o combinaie de taste apsai tasta ESC.
311

Anexa 1 Mediul de programare Dev-C++

14.2.4. Alte instrumente


Dev-C++ conine un manager de instrumente care
permite integrarea altor programe n mediul Dev-C++. Acesta
este accesibil din meniul Tools opiunea Configure Tools. De
exemplu, pentru a cuta pe Google informaii despre cuvnt din
program pe care este plasat cursorul, executai urmtorii pai:
apsai pe butonul Add;
introducei setrile din imaginea urmtoare.

apsai pe butonul Ok, apoi pe butonul Close


n meniul Tools, apare opiunea Cauta pe Google.

14.3. Utilizare
14.3.1. Scrierea unui program C
Realizarea unui program ncepe cu transcrierea
algoritmului acelui program n limbajul de programare dorit
(limbajul C n cazul nostru). n mediul Dev-C++, aceast activitate
ncepe cu deschiderea unui fiier surs: din meniul File,
selectai opiunea New, apoi opiunea Source File.
n zona de editare se deschide un fiier nou, denumit
Untitled1. n acest fiier trebuie scrise instruciunile C care
312

Bazele programrii calculatoarelor

formeaz programul
urmtorul program:

nostru.

Pentru

exemplificare,

scriei

#include <stdio.h>
#include <conio.h>
int main() {
printf("Un mic exemplu");
getch();
}

Funcia getch, definit n biblioteca conio.h, suspend


execuia programului pn cnd utilizatorul apas o tast.
Dac aceast instruciune lipsete, programul se termin
imediat dup execuia ultimei instruciuni, iar fereastra cu
rezultatele dispare.
Instruciunea getch() poate fi nlocuit cu instruciunea
system("pause"). n acest caz, biblioteca conio.h trebuie
nlocuit cu biblioteca stdlib.h.

14.3.2. Compilarea codului surs


La fiecare modificare a programului, acesta trebuie
compilat. Compilarea se realizeaz cu ajutorul opiunii Compile
din meniul Execute. Pentru programele noi, nainte de prima
compilare, Dev-C++ cere utilizatorului s salveze fiierul pe disc.
n faza de compilare, programul este verificat din punct
de vedere sintactic. Dac sunt detectate erori, atunci acestea
sunt afiate n partea inferioar a ferestrei. n caz, contrar pe
ecran este afiat o fereastr cu statistici despre program.
Apsai butonul Close.

14.3.3. Rularea programului


Programul poate fi rulat cu ajutorul opiunii Run din
meniul Execute. La pornire programul afieaz pe ecran o
fereastr (dac fereastra apare i dispare imediat, verificai
existena instruciunii getch() sau system("pause") la sfrit).
Mediul Dev-C++ nu permite pornirea simultan a dou programe.
Dac opiunile din meniul Execute sunt dezactivate, nchidei
programul care ruleaz deja.
313

Anexa 1 Mediul de programare Dev-C++

Compilarea i rularea programului se pot realiza ntr-un


singur pas folosind opiunea Compile & Run din meniul
Execute.

14.3.4. Depanarea
Chiar dac un program nu conine erori de sintax (deci a
fost compilat cu succes), el poate s conin erori de programare.
Acestea se manifest prin furnizarea de rezultate incorecte
pentru toate sau doar anumite cazuri de test. n aceast situaie
funcia de depanare (debugging) a mediului Dev-C++ faciliteaz
detectarea i eliminarea erorilor.
Pentru depanarea unui program se folosesc opiunile din
meniul Debug dup etapa de compilare. Programatorul poate
selecta opiunea Run to cursor pentru a executa programul
pn ajunge la linia unde este cursorul editorului. Odat ajuns pe
aceast linie, execuia programului se suspend. n acest
moment, opiunea Next step execut urmtoarea instruciune,
opiunea Step into execut prima instruciune din funcia care
urmeaz, iar opiunea Continue reia execuia programului.
n timpul depanrii, opiunea Add Watch permite
monitorizarea i modificarea valorilor variabilelor. Astfel
programatorul poate s vad unde apar nepotriviri ntre program
i algoritm.
Opiunea Toogle breakpoint permite adugarea i
anularea punctelor de oprire, adic linii din program n care
execuia programului se suspend, controlul fiind redat din nou
programatorului.
n orice moment, depanarea poate fi oprit folosind
opiunea Stop debugging.

314

Bazele programrii calculatoarelor

1155.. A
ANNEEXXAA 22 S
SEETTUULL DDEE CCAARRAACCTTEERREE A
AS
SC
CIIII

Caracterele din setul ASCII cu codurile ntre 0 i 31, i codul


127 (n baza 10) nu au o reprezentare grafic pe calculator.
Ele sun denumire caractere de control, fiind folosite iniial
pentru a controla comunicaia ntre calculator i periferice, i
modul de afiare al informaiei.
Tabel 15.1 Tabela codurilor ASCII

Cod n baza
1
8
6
0
0
00
x00
1
0
01
x01
2
0
02
x02
3
0
03
x03
4
0
04
x04
5
0
05
x05
6
0
06
x06
7
0
07
x07
8
0
10
x08
9
0
11
x09
1
0
12
x0A
1
0

Caracter (semnificaie)
1
0

NUL (Nul character)

SOH (Start of Header)

STX (Start of Text)

ETX (End of Text)

EOT (End of Transmission)

ENQ (Enquiry)

ACK (Acknowledgment)

BEL (Bell)

BS (Backspace)

HT (Horizontal Tab)

LF (Line Feed)

VT (Vertical Tab)
315

Anexa 2 Setul de caractere ASCII

0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6
7
316

Cod n baza
1
8
6
13
x0B
1
0
14
x0C
1
0
15
x0D
1
0
16
x0E
1
0
17
x0F
1
0
20
x10
1
0
21
x11
1
0
22
x12
1
0
23
x13
2
0
24
x14
2
0
25
x15
2
0
26
x16
2
0
27
x17
2
0
30
x18
2
0
31
x19
2
0
32
x1A
2
0
33
x1B

Caracter (semnificaie)
1

FF (Form Feed)

CR (Carriage Return)

SO (Shift Out)

SI (Shift In)

DLE (Data Link Escape)

DC1 (XON) (Device Control 1)

DC2 (Device Control 2)

DC3 (XOFF) (Device Control 3)

DC4 (Device Control 4)

0
NAK
(Negative
Acknowledgement)
0
SYN (Synchronous Idle)
0

ETB (End of Trans. Block)

CAN (Cancel)

EM (End of Medium)

SUB (Substitute)

ESC (Escape)

Bazele programrii calculatoarelor

0
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3

Cod n baza
1
8
6
2
0
34
x1C
2
0
35
x1D
3
0
36
x1E
3
0
37
x1F
3
0
40
x20
3
0
41
x21
3
0
42
x22
3
0
43
x23
3
0
44
x24
3
0
45
x25
3
0
46
x26
3
0
47
x27
4
0
50
x28
4
0
51
x29
4
0
52
x2A
4
0
53
x2B
4
0

Caracter (semnificaie)
1
0

FS (File Separator)

GS (Group Separator)

0
RS (Request to Send) (Record
Separator)
0
US (Unit Separator)
0

SP (spaiu)

"

# (diez)

$ (dollar)

% (procent)

& (ampersand)

' (apostof)

* (asterisk)

,
317

Anexa 2 Setul de caractere ASCII

0
4
5
6
7
8
9
0
1
2
3
4
5
6
7
8
9
0
318

Cod n baza
1
8
6
54
x2C
4
0
55
x2D
4
0
56
x2E
4
0
57
x2F
4
0
60
x30
4
0
61
x31
5
0
62
x32
5
0
63
x33
5
0
64
x34
5
0
65
x35
5
0
66
x36
5
0
67
x37
5
0
70
x38
5
0
71
x39
5
0
72
x3A
5
0
73
x3B
6
0
74
x3C

Caracter (semnificaie)
1

/ (slash)

<

Bazele programrii calculatoarelor

0
1
2
3
4
5
6
7
8
9
0
1
2
3
4
5
6

Cod n baza
1
8
6
6
0
75
x3D
6
0
76
x3E
6
0
77
x3F
6
0
100
x40
6
0
101
x41
6
0
102
x42
6
0
103
x43
6
0
104
x44
6
0
105
x45
7
0
106
x46
7
0
107
x47
7
0
110
x48
7
0
111
x49
7
0
112
x4A
7
0
113
x4B
7
0
114
x4C
7
0

Caracter (semnificaie)
1
0

>

@ (simbol AT)

M
319

Anexa 2 Setul de caractere ASCII

0
7
8
9
0
1
2
3
4
5
6
7
8
9
0
1
2
3
320

Cod n baza
1
8
6
115
x4D
7
0
116
x4E
7
0
117
x4F
8
0
120
x50
8
0
121
x51
8
0
122
x52
8
0
123
x53
8
0
124
x54
8
0
125
x55
8
0
126
x56
8
0
127
x57
8
0
130
x58
8
0
131
x59
9
0
132
x5A
9
0
133
x5B
9
0
134
x5C
9
0
135
x5D

Caracter (semnificaie)
1

\ (backslash)

Bazele programrii calculatoarelor

0
4
5
6
7
8
9
00
01
02
03
04
05
06
07
08
09

Cod n baza
1
8
6
9
0
136
x5E
9
0
137
x5F
9
0
140
x60
9
0
141
x61
9
0
142
x62
9
0
143
x63
1
0
144
x64
1
0
145
x65
1
0
146
x66
1
0
147
x67
1
0
150
x68
1
0
151
x69
1
0
152
x6A
1
0
153
x6B
1
0
154
x6C
1
0
155
x6D
1
0

Caracter (semnificaie)
1
0

^ (circumflex)

_ (underscore)

` (apostrof invers)

n
321

Anexa 2 Setul de caractere ASCII

0
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
322

Cod n baza
1
8
6
156
x6E
1
0
157
x6F
1
0
160
x70
1
0
161
x71
1
0
162
x72
1
0
163
x73
1
0
164
x74
1
0
165
x75
1
0
166
x76
1
0
167
x77
1
0
170
x78
1
0
171
x79
1
0
172
x7A
1
0
173
x7B
1
0
174
x7C
1
0
175
x7D
1
0
176
x7E

Caracter (semnificaie)
1

| (bar vertical)

~ (tild)

Bazele programrii calculatoarelor

0
27

Cod n baza
1
8
6
1
0
177
x7F

Caracter (semnificaie)
1
0

DEL (delete)

323

Anexa 2 Setul de caractere ASCII

B
BIIBBLLIIO
OG
GR
RA
AFFIIE
E
[1] Chiorean L., Chiorean M. PC Iniiere Hard i Soft, Editura
Microinformatic, Cluj-Napoca,1999.
[2] Cormen T.H., Leiserson C.E., Rivest R.R.. Introducere n
algoritmi, Editura Computer Libris Agora, Cluj Napoca, 2000
[3] Cristea V. Limbajul C Standard, Editura Teora, Bucureti,
1992
[4] Gheorghe M., Popoviciu I., Chiru C., Vasiliu P., Lupei T.
Limbajul C. Programare prin exemple, Editura Academia Naval
Mircea cel Btrn, Constana, 2001
[5] Vasiliu P., Butu A. Programarea calculatoarelor n
limbajul C, Editura Europolis, Constana, 2006.
[6] Ivan I. Limbajul C, Editura Academiei de Studii
Economice, Bucureti, 1992
[7] Kernigham B., Ritchie D. The C programming language,
Practice Hall, 1975
[8] Knuth D.E. Tratat de programarea calculatoarelor, vol.I-II,
Editura Tehnic, Bucureti,1974
[9] Livovschi L., Georgescu H. Sinteza i analiza algoritmilor,
Editura tiinific i Enciclopedic, Bucureti, 1992
[10] Negrescu L. Limbajul Turbo C, Editura Libris, ClujNapoca, 1992
[11] Negrescu L. Limbajele C i C++ pentru nceptori, Editura
Albastr, Cluj-Napoca, 1998
[12] Petrovici V., Goicea F. Programarea n limbajul C, Editura
Tehnic, Bucureti, 1993
[13] Schildt H. C++ manual complet, Editura Teora, 1997

324

Bazele programrii calculatoarelor

[14] Vlada M. Informatic, Editura Ars Docendi, Bucureti,


1999

325

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