You are on page 1of 88

PROGRAMARE PROCEDURAL

PROCEDURAL PROGRAMMING

Disciplin obligatorie; sem 1, ore sptmnal nvmnt de zi: 2 curs, 2 laborator, total
ore semestru 56; 6 credite; colocviu

I. CONINUTUL TEMATIC AL DISCIPLINEI

Algoritmi: Caracteristici. Descriere. Complexitate. Corectitudine.
Limbaje de programare. Caracteristici.
Limbajul de programare C: Entiti sintactice. Operatori.. Expresii. Instruciuni.
Funcii. Directive de preprocesare. Tablouri i Pointeri. Comunicare inter-
modular. Funcia main cu argumente. Pachetele: stdio.h, math.h, string.h
Alocare static Alocare dinamic. Structuri de date dinamice (liste i arbori).
Aplicaii ale utilizrii tipurilor de date structurate (struct, union, typedef) cu
ajutorul pointerilor: crearea i explorarea structurilor de date. Pachetele: stdlib.h,
alloc.h
Operaii de intrare-ieire. Fiiere n C i aplicaii.
Corectitudinea programelor C. Metoda aseriunilor (assert.h).
Complexitatea programelor (time.h). Metrici software.
Testarea programelor C.
Utilizarea bibliotecilor statice (.LIB) i dinamice (.DLL).
Metode de proiectare a programelor.

II. BIBLIOGRAFIE MINIMAL OBLIGATORIE

1. G. Albeanu, Algoritmi i limbaje de programare, Editura Fundaiei Romnia de
mine, Bucureti, 2000.
2. G. Albeanu, Programare procedural, Note de curs (Avizierul virtual /
Blackboard)
3. G. Albeanu (coord.), Tehnici de programare. Lucrri practice de programarea
calculatoarelor, Editura Fundaiei Romnia de mine, Bucureti, 2003.
4. Popa M., Popa M., Programare procedural (Aplicaii C i C++ n structuri de
date i grafic), Editura Fundaiei Romnia de mine, Bucureti, 2006.


UNIVERSITATEA SPIRU HARET file:///C:/ACTIV/Proc/FINAL/IDD-USH.htm
1 of 1 12/9/2007 7:18 PM
UNIVERSITATEA SPIRU HARET
FACULTATEA DE MATEMATICA-INFORMATICA


Suport de curs elaborat de
Prof. Univ. Dr. Grigore ALBEANU
pentru disciplina:
PROGRAMARE PROCEDURALA
2C + 2L; Ciclul I; semestrul I
Evaluare: Examen
CUPRINS
INTRODUCERE
Ce este informatica ?
Ce este un program ? Notiunea de algoritm.
Cum rezolvam probleme cu ajutorul calculatorului ?
ALGORITMI: DESCRIERE, COMPLEXITATE, CORECTITUDINE
Notiuni de teoria grafurilor
Scheme logice structurate
Notiuni introductive privind organizarea datelor
Limbaj algoritmic
Analiza complexitatii
Elemente privind corectitudinea algoritmilor
LIMBAJE DE PROGRAMARE
Vocabularul si sintaxa limbajelor de programare
Tipuri de date. Constante. Variabile. Expresii
Programare in C
Bibliografie

G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM
1 of 6 12/9/2007 7:19 PM
1. Introducere
1.1. Ce este informatica?
1.2. Ce este un program? Notiunea de algoritm
1.3. Cum rezolvam probleme cu ajutorul calculatorului?
1.1. Ce este informatica?
n anul 1642, matematicianul si fizicianul Blaise Pascal (1623-1662) a inventat prima masina mecanic, cu
roti dintate, capabil s realizeze operatii de adunare si scdere a numerelor naturale. Totusi, de abia
dup aparitia masinilor electromecanice, n 1944, John von Neumann a formulat principiul programului
nregistrat si a sugerat constructorilor de calculatoare trei principii care trebuie avute n vedere pentru
realizarea unui calculator:
programele si datele trebuie s fie codificate sub form binar;
programele si datele trebuie stocate ntr-o memorie a masinii de calcul;
trebuie s existe o component (unitate central de prelucrare, procesor) special care stie att s
execute operatii de calcul, ct si s extrag, s decodifice si s execute instructiunile programului.
Astfel, aproape toate tipurile de sisteme de calcul ce au aprut mai trziu sunt calculatoare de tip von
Neumann.
Aparitia sistemelor de calcul a dus la aparitia si dezvoltarea unei noi stiinte: informatica (Informatique,
Informatics, Informatik n Europa, respectiv Computer Science n SUA). Informatica reprezint un
complex de discipline prin care se asigur prelucrarea informatiilor cu ajutorul sistemelor de calcul.
Astzi, informatica este prezent n industrie, bnci, ferme, art, medicin, stiinte sociale etc. si este
structurat n mai multe domenii precum:
arhitectura sistemelor de calcul: studiaz modul de organizare a sistemului fizic (hardware) pentru a
se obtine o mai mare eficient, sigurant si utilitate.
sisteme de operare: studiaz modalittile de gestiune eficient a resurselor fizice si a programelor.
algoritmi si structuri de date: studiaz metodele de rezolvare a problemelor si modurile de organizare
a datelor pentru a obtine programe eficiente.
limbaje de programare: studiaz modalittile prin care algoritmii si structurile de date sunt
prezentate calculatorului pentru a fi prelucrate.
ingineria programrii: studiaz metodele de automatizare a proceselor de proiectare, analiz, testare
si reutilizare a programelor.
calcule numerice si simbolice: studiaz modalittile de reprezentare a informatiei numerice pentru
implementarea unor algoritmi numerici robusti, eficienti si de mare precizie.
sisteme de gestiune a bazelor de date: studiaz modalittile de structurare si organizare eficient a
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM
2 of 6 12/9/2007 7:19 PM
colectiilor mari de date ce vor fi supuse diverselor prelucrri.
inteligenta artificial: studiaz modalittile de reprezentare si manipulare a cunostintelor n vederea
obtinerii de noi cunostinte.
animatia si robotica: studiaz modalittile de reprezentare, prelucrare si analiz a informatiei
audio-vizuale.
n sfera sa de preocupri, Informatica a atras si dezvoltat o mare varietate de discipline precum: logica
matematic, teoria automatelor, limbaje formale, cercetri operationale, teoria grafurilor si retelelor,
calcul numeric, teoria fiabilittii, geometrie computational, teoria calculabilittii, baze de date, baze de
cunostinte, sisteme expert etc.
1.2. Ce este un program? Notiunea de algoritm
Solutia unei probleme, din punct de vedere informatic, este dat printr-o multime de comenzi
(instructiuni) explicite si neambigue, exprimate ntr-un limbaj de programare. Aceast multime de
instructiuni prezentat conform anumitor reguli sintactice formeaz un program. Un program poate fi
privit si ca un algoritm exprimat ntr-un limbaj de programare. Totusi, un algoritm descrie solutia
problemei independent de limbajul de programare n care este redactat programul.
Exist mai multe definitii ale notiunii de algoritm. A. A. Markov, a considerat algoritmul ca fiind o notiune
matematic primar si a descris-o astfel: Un algoritm este o retet care descrie precis si clar un proces de
calcul.
El a descris un mecanism formal pentru a specifica o clas larg de activitti si anume: algoritmii normali.
Alte modalitti de descriere a algoritmilor ce au mai fost propuse sunt: masina Turing, sistemele Post,
functiile recursive etc. n aceast lucrare, prin algoritm vom ntelege o secvent finit de comenzi explicite
si neambigue care, executate pentru o multime de date (ce satisfac anumite conditii initiale), conduce n
timp finit la rezultatul corespunztor. Observm c se face distinctie ntre algoritm (care se termin n
timp) si procedur (care poate continua nedefinit).
Conform lui D. Knuth (The art of computer programming, Vol. I, 1997) un algoritm posed cinci
caracteristici importante:
Un algoritm are caracter finit. El este descris printr-o secvent finit de etape si trebuie ca, ori de cte
ori sunt parcurse etapele algoritmului pentru anumite date, procesul s se ncheie n timp finit.
Un algoritm are caracter determinist. Actiunile specificate de pasii algoritmului sunt clare, fiind
riguros prezentate.
Un algoritm are date de intrare. Se poate admite c ntotdeauna un algoritm lucreaz asupra unor
date de intrare. Acestea pot fi evidentiate din contextul n care este formulat problema a crei
solutie o reprezint algoritmul.
Un algoritm furnizeaz cel putin o valoare de iesire ce se afl ntr-o relatie specific cu datele de
intrare.
Un algoritm este eficace.
Trebuie spus c nu orice problem admite solutie descris algoritmic. Problemele pentru care exist un
algoritm de rezolvare se numesc probleme decidabile. Problemele pentru care s-a demonstrat (matematic)
c nu admit un algoritm de rezolvare se numesc probleme nedecidabile. Nu este suficient ca o anumit
problem (clas de probleme) s admit solutii (chiar si o singur solutie). Din punctul de vedere al
informaticii, intereseaz dac exist solutie ce poate fi descris algoritmic, deci dac solutia problemei
poate fi construit efectiv. De asemenea, pentru rezolvarea anumitor probleme pot exista mai multi
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM
3 of 6 12/9/2007 7:19 PM
algoritmi. Stabilirea celui mai bun dintre acestia se realizeaz n urma unui proces de analiz prin care se
determin performantele fiecruia dintre algoritmi.
n finalul acestei sectiuni vom descrie ctiva algoritmi elementari. Acestia vor contribui la realizarea unui
prim contact cu solutiile algoritmice. Mai nti prezentm cteva conventii. Datele supuse prelucrrilor
sunt manipulate cu ajutorul variabilelor. Acestea sunt entitti ce pot referi elemente ale unei anumite
multimi. Putem vorbi de variabile ntregi (respectiv reale, caracter etc.) atunci cnd acestea se refer la
valori ntregi (respectiv reale, caracter etc.). Actiunile realizate n cadrul unui algoritm vor fi descrise prin
verbe: execut, citeste, scrie
etc. Notatiile matematice consacrate vor fi utilizate fr explicatii suplimentare. Vom utiliza constructii
precum: dac, atunci, altfel, ct timp, repet, pn cnd, pentru, de la, pn la etc., a cror semnificatie
este cea uzual. O operatie important este aceea prin intermediul creia o variabil "va primi" o anumit
valoare. Aceast actiune se mai numeste operatie de atribuire si, n continuare, se va nota prin ":="
Valoarea ce se atribuie unei variabile este rezultatul evalurii unei expresii. Expresia poate fi de tip
numeric sau de tip logic. ntr-o expresie numeric apar numere (ntregi, reale etc.) si operatori aritmetici
precum: + (adunare), - (scdere), * (nmultire), / (mprtire) etc. Expresiile logice (numite si expresii
booleene) contin operatori logici: and (si logic), or (sau logic), not (negatie) si operatori relationali (<, >, <=
(mai mic sau egal), >= (mai mare sau egal), != sau <> (diferit), = (egalitate)) folositi ntre elemente pentru
care aceste operatii au sens. Rezultatul evalurii unei expresii logice poate fi: true (adevrat) sau false
(fals). n descrierea unei expresii pot fi folosite si alte simboluri dac acestea sunt cunoscute sau explicate.
Utilizarea parantezelor: "(" si ")" pentru indicarea modului de evaluare este, de asemenea, permis.
Am vzut c algoritmii accept date de intrare si furnizeaz rezultate (date de iesire). Introducerea un
valori sau a unui sir de valori se va descrie folosind verbul citeste. Afisarea unei valori sau a unui sir de
valori va fi descris prin verbul scrie. Vom conveni s numerotm pasii (etapele) unui algoritm.
numerotare va fi utilizat eventual n alti pasi. Acest mod de prezentare a algoritmilor se numeste
descriere n limbaj conventional. n unele lucrri, limbajul conventional mai este numit si limbaj
pseudocod.
Exemplul 1.1.
Fie a si b dou variabile ntregi. Dorim s schimbm ntre ele valorile celor dou variabile. Mai precis, dac a
= 640 si b = 480, dorim s obtinem a = 480 si b = 640.
Un mod de a realiza aceast schimbare presupune utilizarea unei variabile suplimentare, cu rol de
intermediar. Folosind trei operatii de atribuire, algoritmul are urmtorii pasi:
1. citeste a, b
2. t := a
3. a := b
4. b := t
5. scrie a,b
Lsm ca exercitiu realizarea urmtoarelor transformri:
i) a --> b --> c --> a
ii) a --> b --> c --> d --> a
Atunci cnd va fi necesar, ne vom referii la pasii 2, 3 si 4 prin constructia interschimb(a,b).
Exemplul 1.2.
Se cere generarea primilor n termeni (n>1) ai sirului lui Fibonacci. Primii ctiva termeni sunt: 0, 1, 1, 2, 3, 5,
8, 13, ... Mai precis, termenul curent este suma celor doi termeni anteriori.
Vom prezenta dou metode. Prima metod descrie schema de generare c := a + b, unde a, b desemneaz
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM
4 of 6 12/9/2007 7:19 PM
ultimii doi termeni generati, iar c va fi termenul curent. Deoarece se cer n termeni, este necesar un
mecanism de numrare (incrementarea unei variabile de contorizare). Valorile contorului vor fi referite
prin variabila k. Algoritmul de generare, n prima variant, este:
Varianta 1:
1. citeste n
2. k := 2
3. a := 0; scrie a
4. b := 1; scrie b
5. repet
5.i) c := a + b; scrie c
5.ii) a := b
5.iii) b := c
5.iv) k := k+1
pn cnd k = n.
Prin a doua metod se vor genera termenii doi cte doi. Aceasta nseamn ca uneori este generat unul n
plus. Descrierea ce urmeaz foloseste numai variabilele a si b pentru a indica termenii sirului.
Varianta 2:
1. citeste n
2. a := 0
3. b :=1
4. k :=2
5. ct timp k < n execut
5.i) scrie a, b
5.ii) a := a + b
5.iii) b := a + b
5.iv) k := k+2
6. dac k = n atunci scrie a, b altfel scrie a.
Exemplul 1.3. Se consider o secvent cu n numere ntregi. Se cere afisarea numerelor n ordine cresctoare.
Vom descrie sirul de numere prin x
1
, x
2
, ..., x
n
.
Cea mai simpl metod presupune interschimbarea a cte dou elemente, pn cnd nu mai sunt necesare
interschimbri. Pasii algoritmului sunt:
1. citeste n
2. citeste x
1
, x
2
, ..., x
n

3. k:=1;
4. repet
4.i) ordonat := true
4.ii) pentru i de la 1 pn la n-k execut
dac x
i
> x
i+1
atunci
a) interschimb(x
i
, x
i+1
)
b) ordonat := false
4. iii) k:=k+1;
pn cnd (ordonat = true) or (k = n)
5. scrie x
1
, x
2
, ..., x
n.
Justificarea metodei este simpl. Trebuie s observm c la prima parcurgere, elementul maxim va ajunge
pe ultima pozitie. La a doua parcurgere, elementul imediat mai mic (dect maximul recent obtinut), va
ocupa penultima pozitie. Cnd nu sunt necesare interschimbri sirul este deja ordonat.
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM
5 of 6 12/9/2007 7:19 PM
1.3. Cum rezolvm probleme cu ajutorul calculatorului?
Am vzut c exist probleme pentru care nu poate fi dat un algoritm de rezolvare. Totusi cele mai multe
probleme cu care se confrunt informatica sunt probleme decidabile. Toate temele tratate n aceast
lucrare formuleaz probleme decidabile.
Se stie c nu nvtarea unui limbaj de programare este o sarcin dificil, ci rezolvarea algoritmic a
problemelor decidabile. Este clar c, nainte de a ncepe scrierea unui program trebuie, mai nti, s gsim
(sau s cunoastem deja) solutia algoritmic a problemei puse. Cum se gseste solutia? Etapele descrise de
G. Plya (Cum rezolvm o problem? Editura Stiintific, Bucuresti, 1965), pentru rezolvarea unei probleme
de matematic, sunt valabile si n informatic.
nainte de a ncepe s vedem cum se face, trebuie s ntelegem att ipotezele problemei ct si ceea ce se
cere. Deci, ntelegerea problemei, ocup primul loc n procesul cutrii unei metode de rezolvare a acesteia
cu ajutorul calculatorului. Trebuie evidentiate datele de intrare si conditiile pe care acestea trebuie s le
ndeplineasc. Este important s identificm esentialul. De multe ori un enunt al unei probleme contine
foarte multe elemente descriptive privind importanta problemei, consideratii de natur istoric, exemple,
uneori chiar si etape distincte pentru obtinerea solutiei. Cerinta problemei furnizeaz, de multe ori, chiar
idei privind modul de a ajunge la solutie. Considerarea unor configuratii particulare pentru datele de
intrare si ncercarea de a lucra asupra lor, pentru a gsi solutia, va contribui ntotdeauna la o ntelegere
mai bun a enuntului.
Dac n enunt se sugereaz etapele rezolvrii, acestea implicnd rezolvarea unor subprobleme, atunci
trebuie s aflm solutia algoritmic corespunztoare fiecrei etape. Dac nu se specific etape, dar putem
descompune problema n subprobleme mai simple atunci solutia algoritmic a problemei initiale se va
obtine prin "compunerea" solutiilor subproblemelor. Deci este foarte important s stim s rezolvm
probleme simple, eventual probleme reprezentative pentru anumite clase de aplicatii si s stim s
descompunem (respectiv, s reducem) problema initial n (la) subprobleme usor de rezolvat si apoi s
construim solutia final. Abordarea prin descompuneri repetate, cu detaliere pas cu pas se numeste
abordare top-down sau rafinare iterativ.
Abordarea prin care pornind de la solutii algoritmice ale unor probleme cunoscute, construim solutii ale
altor probleme care au ns legtur cu problema de rezolvat, iar n final, urmnd aceeasi modalitate
construim solutia problemei a crei solutie se cere, se numeste abordare bottom-up. Aceast metod
permite reutilizarea programelor existente si este tot mai important odat cu aparitia tehnicilor orientate
obiect. De asemenea, pentru a obtine o solutie a unei probleme este util s privim problema si comparativ
cu alte probleme ntlnite. Numai dup investigarea acestor variante putem trece la stabilirea metodei de
abordare.
Pentru probleme de complexitate ridicat, oricare din metodele de abordare top-down sau bottom-up,
conduc la o solutie modular, bazat pe subprograme sau, mai nou, la o solutie orientat obiect.
Multe din problemele de programare pot fi rezolvate usor dac solutia verific anumite principii. Dac
solutia problemei este o multime de elemente care se poate obtine pas cu pas, pornind de la multimea vid,
prin adugarea celui mai bun element neconsiderat nc (si ales conform anui anumit criteriu) spunem c
avem de-a face cu o abordare de tip greedy. Pentru probleme n care se cere o solutie optim care satisface
principiul optimalittii (principiul lui Bellman) se va aplica metoda programrii dinamice. Alte strategii
pentru elaborarea algoritmilor sunt: metoda divide et impera, metoda backtracking, euristica etc.
Vreau sa vad nceputul capitolului
Vreau sa vad Cuprinsul documentului.
G. Albeanu - PROGRAMARE PROCEDURALA - Introducere file:///C:/ACTIV/Proc/FINAL/C1.HTM
6 of 6 12/9/2007 7:19 PM
Versiune prescurtat a capitolului 1 din: G. Albeanu. Algoritmi si limbaje de programare. Editura Fundatiei
"Romnia de Mine", 2000.
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
1 of 16 12/9/2007 7:20 PM
2. Algoritmi: Descriere, Complexitate,
Corectitudine
2.1. Notiuni de teoria grafurilor
2.2. Scheme logice structurate
2.3. Notiuni introductive privind organizarea datelor
2.4. Limbaj algoritmic
2.5. Analiza complexitatii
2.6. Elemente privind corectitudinea algoritmilor
2.1. Notiuni de teoria grafurilor
Un graf neorientat G este definit prin perechea G = (V, E), unde V este o multime nevid de elemente
numite vrfuri (vertex), iar E este o multime (posibil vid) de perechi neordonate cu componente
distincte ale lui V care se numesc muchii (edges). Dac E este multimea vid spunem c G este trivial. n
cazul n care multimea V este finit spunem c avem un graf finit. Numrul elementelor multimii V
determin ordinul grafului finit. O muchie cu vrfurile x si y (numite extremitti) se noteaz prin [x, y]
sau [y, x]. Spunem c vrfurile x si y sunt incidente muchiei [x,y].
Un digraf este definit printr-o pereche G=(V, E), unde V este o multime nevid de vrfuri, iar E este o
parte a produsului cartezian V x V ale crei elemente le numim arce. Un arc este notat prin (x,y) cu x
diferit de y, unde x se numeste surs sau extremitate initial, iar y se numeste destinatie sau extremitate
final. Atributele : trivial, respectiv finit, pentru un digraf se definesc similar.
Un graf (digraf) partial al unui graf (digraf) G = (V, E) este un graf (digraf) G
1
= (V, E
1
), unde E este
submultime a multimii E, deci este graful (digraful) G nsusi sau se obtine din G prin suprimarea
anumitor muchii (arce).
Un subgraf (subdigraf) al unui graf (digraf) G este un graf (digraf) H = (U, E'), unde U este submultime
a multimii V, E' este submultime a multimii E, iar muchiile (arcele) din E' sunt toate muchiile (arcele)
din E, care au ambele extremitti n multimea de vrfuri U.
Uneori, arcele (muchiile) sunt etichetate. Dac etichetele sunt numere reale pozitive se spune c digraful
(graful) este ponderat.
n continuare vom considera numai grafuri (digrafuri) finite. De obicei un graf se reprezint prin
indicarea unor puncte din plan (ce corespund vrfurilor) si a unor segmente de curb (sau de dreapt)
pentru indicarea muchiilor (vezi figura 2.1a). n cazul digrafurilor arcele sunt segmente de curb
orientate, sensul fiind de la surs spre destinatie (vezi figura 2.1b).
Definitia 2.1.1.
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
2 of 16 12/9/2007 7:20 PM
Fie G = (V,E) un digraf, iar x si y dou vrfuri. Numim x-y drum (de lungime n) o secvent de vrfuri D:
v
0
, v
1
, ..., v
n
dac v
0
= x, v
n
= y , iar (v
i
, v
i+1
) apartine multimii E pentru toti i, i n-1. Vrfurile x si y se
numesc extremittile drumului D. Un drum fr nici un arc este un drum trivial. Un x-y drum se numeste
circuit (sau drum nchis) dac x=y; dac x diferit de y, se spune c drumul este unul deschis. Circuitul este
elementar dac toate vrfurile circuitului, cu exceptia primului si a ultimului vrf care coincid, sunt
distincte dou cte dou.
Definitia 2.1.2. Fie G = (V, E) un graf neorientat, iar x si y dou vrfuri. Secventa de vrfuri L: v
0
, v
1
, ..., v
n
este un x-y lant (de lungime n) dac [ v
i
, v
i+1
] apartine multimii E, pentru toti i, 0 i n-1, iar x=v
0
si y=v
n
.
L este ciclu dac x=y. Atributul elementar, pentru un lant, poate fi introdus similar.
Uneori, chiar pentru un digraf, putem folosi notiunea de lant, dac se verific proprietatea c oricare
dou arce vecine au o extremitate comun.
Definitia 2.1.3.
Numim lant (drum) hamiltonian un lant (drum) elementar al unui graf care contine toate vrfuri le
grafului.
Definitia 2.1.4.
Fie G = (V, E) un graf netrivial. Spunem c x, y din V sunt conectate n G dac exist un x-y lant n G.
Graful G este un graf conex dac oricare dou vrfuri din V sunt conectate n G. Dac G este un graf trivial
(E multime vid) se accept c este graf conex. Dac G nu este conex atunci exist cel putin dou
componente conexe (subgrafuri conexe maximale, disjuncte dou cte dou relativ la vrfuri). Un digraf G
cu proprietatea c pentru oricare dou vrfuri x si y exist att un x-y drum ct si un y-x drum n G se
numeste graf tare conex.
n sectiunea urmtoare prezentm o metod de reprezentare a algoritmilor folosind schemele logice.
Acestea sunt introduse folosind terminologia teoriei grafurilor.
2.2. Scheme logice structurate
O transcriere grafic a etapelor (pasilor) unui algoritm este numit organigram. De cele mai multe ori
este folosit denumirea de "schem logic". Fiecrui pas, al algoritmului, i se asociaz un bloc ce
constituie eticheta unui arc. Blocurile folosite ntr-o schem logic descriu instructiuni (comenzi) sau
predicate (expresii logice). Predicatele apar n cadrul instructiunii de ramificare. Celelalte instructiuni
sunt:
Instructiunea START: eticheteaz arcul initial (acel arc n a crui extremitate initial nu pot sosi
alte arce). Orice schem logic are un unic arc initial. Acesta va indica punctul de unde ncepe
executia unui program.
1.
Instructiunea STOP: eticheteaz un arc final (acel arc din a crui extremitate final nu pot pleca
alte arce). O schem logic poate avea mai multe arce finale. Acestea indic oprirea executiei
programului descris prin intermediul schemei logice.
2.
Instructiunea CITESTE: eticheteaz un arc ce indic introducerea de la mediul de intrare
(tastatur, disc etc.) a unei secvente de valori (numite date de intrare). Cuvntul CITESTE este
nsotit de variabilele ce descriu datele de intrare.
3.
Instructiunea SCRIE: eticheteaz un arc ce indic nregistrarea la mediul de iesire (display, disc
etc.) a rezultatelor (datelor de iesire). Cuvntul SCRIE este nsotit de variabilele sau constantele ce
desemneaz datele de iesire.
4.
Instructiunea de atribuire: eticheteaz un arc cu eticheta v := e, unde v este o variabil, iar e este o
expresie de acelasi tip (numeric sau logic) cu variabila v.
5.
Instructiunea de ramificare: este caracterizat prin n arce ce pleac din acelasi punct, arce 6.
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
3 of 16 12/9/2007 7:20 PM
etichetate cu predicatele p
1
, p
2
, ..., p
n
definite astfel nct:
p
1
or p
2
or ... or p
n
= TRUE (adevrat) si
p
i
and p
j
= FALSE (fals) pentru oricare i si j diferiti.
Definitia 2.2.1. Se numeste schem logic (sau program sub form de schem logic) un graf orientat, n
care:
exist o unic instructiune START si cel putin o instructiune STOP;
Orice vrf (diferit de extremitatea final a unei instructiuni STOP) este extremitatea initial a unei
unice instructiuni;
Orice arc este etichetat cu una dintre instructiunile: START, STOP, CITESTE, SCRIE, atribuire sau
cu un predicat. In ultimul caz, extremitatea initial a arcului trebuie s coincid cu extremitatea
initial a unei instructiuni de ramificare.
pentru orice arc exist cel putin un drum care ncepe cu instructiunea START, se termin cu o
instructiune STOP si contine arcul considerat.
Schemele logice sunt folosite pentru descrierea algoritmilor. Se pot pune n evident structuri
fundamentale precum:
structura secvential
- format din arce conectate etichetate cu instructiuni distincte de cea de ramificare. O structur
secvential format din dou arce etichetate prin a, respectiv b se va nota prin SEQ(a,b) si are
semnificatia " execut a urmat de b".
1.
structuri decizionale
(alternative) - contin, obligatoriu, cel putin un predicat si cel putin un bloc functional (instructiune
alta dect START sau ramificativ). Structurile decizionale sunt de urmtoarele forme:
IF(p; a, b) - Dac p este adevrat, atunci execut a altfel execut b (vezi figura 2.2a).
IF0(p; a) - Dac p este verificat, atunci a (vezi figura 2.2b).
CASE(p
1
,p
2
,...,p
n
; a
1
, a
2
, ..., a
n
) - Dac p
1
atunci a
1
, dac p
2
atunci a
2
, ..., dac p
n
atunci a
n
(vezi figura 2.2c).
2.
Structuri repetitive
(structuri de tip ciclu, structuri iterative) - contin obligatoriu un bloc predicativ si un bloc
functional care se execut de un numr finit de ori pn cnd predicatul si schimb valoarea.
Sunt posibile trei situatii:
WHILE(p; a) - Ct timp conditia p este adevrat se execut a, apoi se continu cu
urmtoarea instructiune ( vezi figura 2.3a: ciclu cu test initial).
REPEAT(p; a) - Repet a pn cnd conditia p este adevrat, apoi execut instructiunea
urmtoare ( vezi figura 2.3b: ciclu cu test final).
FOR(p; a, b, c) - Este echivalent cu SEQ(a, WHILE(p; SEQ(b, c))). Blocul a este un bloc
functional de initializare. Blocul b descrie instructiunea ce se va executa cnd conditia p este
adevrat. Blocul c (prezentat explicit n aceast structur) va descrie actualizarea strilor
variabilelor programului cu rol deosebit n evaluarea conditiei p ( vezi figura 2.3c: ciclu cu
contor).
3.
Exemplul 2.2.1. Urmtoarea descriere reprezint o secvent. Uneori secventele se pot eticheta (* vezi
figura 2.4).
ET1 SEQ
write('Introduceti 3 numere:');
read(x,y,z);
media:=(x+y+z)/3;
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
4 of 16 12/9/2007 7:20 PM
writeln('Media = ',media);
ET1 END
Eticheta secventei de mai sus este ET1, iar componentele secventei sunt instructiuni Pascal. Secventa
descrie citirea a trei numere, calculul mediei aritmetice si afisarea rezultatului.
Exemplul 2.2.2. Urmtoarele secvente ilustreaz structurile decizionale.
a)(* vezi figura 2.5a *)
ET2 SEQ
read(x);>
if (x>0) or (x=0) then write('Numar nenegativ')
else write('Numar negativ');
ET2 END
b)(* vezi figura 2.5b *)
ET3 SEQ
read(titlu);
cod:=0;
if nume='algebra' then cod:=1;
write(cod);
ET3 END
c)(* exercitiu *)
ET4 SEQ
zar:=1+random(6);
case zar of
1, 3, 5 : impar:=impar+1;
2, 4, 6 : par:=par+1;
end
ET4 END
Secventa ET2 descrie citirea unei valori (se presupune c x este un numr) si afisarea unui mesaj n
functie de semnul numrului x. Secventa ET3, citeste un titlu, iar dac se introduce 'algebra' atunci
codul asociat este 1, n rest codul este 0. n final se scrie codul. Prin secventa ET4 se genereaz un numr
aleator ntre 1 si 6. Apoi se analizeaz paritatea numrului. Dac secventa ET4 s-ar repeta, atunci
variabila impar ar contine numrul de aparitii ale numerelor impare. Similar, variabila par va
reprezenta numrul numerelor pare generate.
Exemplul 2.2.3. Prin urmtoarele secvente exemplificm structurile repetitive: While, Repeat si For
(Elaborarea schemelor logice este lsat ca exercitiu).
a)ET5 SEQ
read(x);i:=1; cod:=0;
while ((i<n) or (i=n)) and (cod=0) do
if x = a[i]; then cod:=1 else i:=i+1;
write(cod,i);
ET5 END
b)ET6 SEQ
repeat
zar:=1+random(6)
until zar=6;
writeln('A aparut Numarul 6!');
ET6 END
c)ET7 SEQ
read(n); suma:=0;
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
5 of 16 12/9/2007 7:20 PM
for i:=1 to n do
begin read(x); suma:=suma+x end;
writeln('Suma =', suma);
ET7 END
Secventa ET5 descrie citirea unui element x si verificarea ipotezei: "Elementul x se afl printre cele n
elemente din tabloul a". n secventa ET6 se descrie generarea repetat de numere pn la aparitia
valorii 6. Secventa ET7, folosind variabila de contorizare i, citeste n numere, le calculeaz suma si apoi o
afiseaz. Observati prezenta predicatului la iteratiile de tip While si Repeat.
Definitia 2.2.2.
Un algoritm exprimat n functie de structurile SEQ, IF si WHILE se numeste structurat, schema logic
asociat se numeste schem logic structurat, iar programul corespunztor se numeste program
structurat.
Evident, familia algoritmilor structurati este nevid. Un rezultat foarte important afirm: Orice algoritm
poate fi transformat ntr-un algoritm structurat. Aceast afirmatie are la baz teorema Bohm-Jacopini.
Pentru a transforma o schem logic (nestructurat) ntr-o schem logic structurat se poate folosi
regula variabilei booleene (ce rezult din demonstratia teoremei Bohm-Jacopini). Cititorul interesat de
detalii poate consulta lucrarea: Corrado Bohm, Giuseppe Jacopini - Flow-diagrams, Turing Machines and
languages with only two formation rules. Comm. ACM. 9 (May, 1966), 366-371. Una din consecintele
importante ale programrii structurate este eliminarea instructiunii de salt neconditionat (goto) din
programe. Totusi, exist situatii cnd instructiunea goto este util. Lungimea programelor nu va creste,
iar claritatea algoritmului nu va avea de suferit. Important este ca numrul instructiunilor goto folosite
s fie foarte mic, iar salturile s fie locale.
2.3. Notiuni introductive privind organizarea datelor
Organizarea datelor, n vederea prelucrrii acestora, este un proces complex, dar de o deosebit
important. De modul n care sunt structurate datele, depinde eficienta algoritmilor de prelucrare.
Unele date sunt de tip simplu: data apare ca o entitate indivizibil att din punct de vedere a informatiei
pe care o reprezint ct si n raport cu unitatea central de prelucrare. Alte date sunt descrise prin
componente, cu acelasi tip sau cu tipuri diferite. O colectie de date pe care s-a evidentiat un anumit mod
de structurare si s-au stabilit procedeele de nregistrare/identificare a componentelor se va numi
structur de date. Componentele unei structuri de date pot fi de tip elementar sau pot fi, la rndul lor,
structuri. Identificarea unei componente se poate face prin pozitia pe care o ocup n structur sau prin
nume.
Pentru o dat elementar trebuie specificate: un identificator, atribute (domeniul de valori, modul de
reprezentare n sistemul de calcul, precizia reprezentrii) si valorile datei (pot fi enumerate sau indicate
printr-o proprietate comun). Din punct de vedere al domeniului de valori asociat unei date se disting
urmtoarele clase:
date de tip integer (numere ntregi);
date de tip real sau float (cu elemente din multimea numerelor rationale);
date de tip boolean (se refer la valorile de adevr true (adevrat), false (fals));
date de tip char (cu elemente ale multimilor ASCII sau Unicode);
date de tip string (obtinute prin concatenarea datelor de tip caracter);
date de tip array
(structur cu componente de acelasi tip ce ocup locatii succesive din memoria sistemului de
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
6 of 16 12/9/2007 7:20 PM
calcul, identificate prin pozitie);
date de tip record (structur cu componente oarecari, identificate prin nume).
Un mod special de organizare a datelor este ntlnit cnd avem de prelucrat liste. O list liniar este o
structur de date omogen, secvential, format din elemente apartinnd unei multimi date. O list
poate fi vid (nu are nici un element) sau plin (nu mai exist spatiu pentru stocarea unor componente
suplimentare). Este foarte important s putem accesa un element al listei, s inserm sau s stergem un
element etc.
Listele pot fi stocate n memoria unui sistem de calcul n dou moduri: secvential si nlntuit. Modul
secvential presupune stocarea elementelor listei n locatii succesive de memorie conform ordinii
elementelor din list si retinerea adresei primului element al listei (adresa de baz). Modul nlntuit
presupune c fiecare element al listei este nlocuit cu o celul format dintr-o parte de informatie
(corespunztoare elementului listei) si o parte de legtur ce contine adresa celulei urmtorului element
din list. Se va retine adresa de baz a listei, iar ultima celul va indica, n partea de legtur, o valoare
special (ce nu poate desemna o legtur).
Structura de date elementar adecvat reprezentrii secventiale a listelor este tabloul unidimensional.
Orice list liniar are un nceput si un sfrsit pe care le numim baz, respectiv vrf. O list liniar la
care inserarea si extragerea elementelor se face prin vrful listei se numeste stiv (stack). O list liniar
n care inserrile se efectueaz la baza listei, iar extragerile prin vrful listei se numeste coad (queue).
Listele liniare pot fi transformate n liste circulare considernd c legtura ultimului element indic
adresa bazei listei.
2.4. Limbaj algoritmic
O alt modalitate de reprezentare a algoritmilor o constituie utilizarea limbajului algoritmic. Limbajul
algoritmic foloseste o scriere similar limbajelor de programare moderne. El permite att descrierea
instructiunilor algoritmului ct si descrierea exact a tipului datelor cu care lucreaz algoritmul. Un
algoritm descris folosind limbajul algoritmic este o succesiune finit de declarri si instructiuni.
Declarrile precizeaz tipul si organizarea datelor. Ele apar naintea instructiunilor ce descriu pasii
algoritmului. Din punct de vedere al scrierii instructiunilor, o instructiune poate ocupa mai multe
rnduri sau pe un rnd pot fi scrise mai multe instructiuni. Instructiunile vor fi separate, ntre ele,
folosind caracterul ';'.
Cuvintele care identific un tip de date sau o instructiune, numite n continuare cuvinte cheie, apar
evidentiate pentru a fi deosebite de numele variabilelor. O declarare utilizeaz unul dintre cuvintele
cheie integer, real, boolean, char, string, array, record, stack, queue, urmat de o list de nume de
variabile. Declarrile sunt separate, ntre ele, folosind caracterul ';'. Variabilele prezente ntr-o list au
tipul si organizarea precizat prin cuvntul cheie respectiv. De exemplu, declarrile:
integer array a(10);
record (integer cod; string nume; real media) x, y;
stack S; queue Q; char ch; boolean ind;
indic faptul c a este un tablou cu maxim 10 elemente ntregi; x si y sunt nregistrri (cu trei
componente: cod - o valoare ntreag, nume - un sir de caractere, media - un numr real), S este o stiv,
Q este o coad, ch este un caracter, iar ind este o variabil logic.
O important deosebit o au declarrile de subprograme. n rezolvarea multor probleme apare
necesitatea executrii repetate a acelorasi calcule pentru date diferite. Subprogramele permit descrierea
acestor calcule o singur dat. Subprogramul poate fi apelat ori de cte ori este necesar efectuarea
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
7 of 16 12/9/2007 7:20 PM
acestor operatii. Un subprogram este identificat printr-un nume si o list de parametri. Subprogramele
se mpart n proceduri si functii. Delararea unei proceduri const n specificarea cuvntului procedure,
a unui identificator al procedurii si a unei liste de declarri (ntre paranteze rotunde) ce indic
informatiile ce fac obiectul transferului ntre apelant si apelat. Pentru declararea unei functii se foloseste
cuvntul cheie function. Spre deosebire de proceduri, functiile ntorc obligatoriu un rezultat. De aceea,
n declaratii, declararea unei functii ncepe cu specificarea multimii de valori ce corespunde rezultatului,
a cuvntului function, a identificatorului functiei si a listei parametrilor (similar ca la o procedur).
Un algoritm este complet cunoscut dac este descris si definitia subprogramelor folosite. Definitia unui
subprogram presupune descrierea (prin instructiuni) modului n care se efectueaz calculele si se
transmit rezultatele. Mai multe detalii prezentm n finalul acestei sectiuni.
Instructiunile limbajului algoritmic sunt urmtoarele:
Instructiunea de atribuire. Aceast instructiune are forma: v := E (atribuire simpl) sau (v
1
, v
2
, ...,
v
n
) := (E
1
, E
2
, ..., E
n
) ce realizeaz simultan atribuirile v
i
:=E
i
, pentru oricare i = 1, 2, ..., n.
Operatia de atribuire este permis cnd variabila v (variabilele v
1
, v
2
, ..., v
n
) din membru stng si
expresia E (expresiile E
1
, E
2
, ..., E
n
) sunt compatibile (se refer la aceeasi aclas de obiecte). O
expresie contine paranteze (optional), operanzi (inclusiv apeluri de functii) si operatori adecvati.
1.
Instructiuni de intrare/iesire.
Vom presupune c citirea datelor (de intrare) se face de la un mediu de intrare (de exemplu:
tastatura sistemului de calcul), iar scrierea rezultatelor (de iesire) se face la un mediu de iesire (de
exemplu: ecranul, imprimanta, plotterul etc.). Forma instructiunilor de intrare/iesire este:
read v
1
, v
2
, ..., v
n
write v
1
, v
2
, ..., v
n
unde v
1
, v
2
, ..., v
n
sunt variabile de tip elementar.
2.
Instructiunea repetitiv While. Aceast instructiune are forma: while p do S, unde p este un
predicat, iar S este o secvent de instructiui. Deoarece instructiunile sunt separate ntre ele,
folosind ';' va trebui s delimitm secventa S. Pentru aceasta se utilizeaz constructia SEQ..END
prezentat mai sus. Semnificatia acestei instructiuni este aceeasi ca pentru sub-schema logic
While(p; S).
3.
Instructiunea If_then_else. Aceast instructiune are forma: if p then S1 [elseS2 ], unde p este un
predicat, iar S1 si S2 sunt secvente de instructiuni. Dac nendeplinirea predicatului p nu indic
vreo actiune, portiunea else
S2 poate lipsi, fapt reprezentat prin includerea ntre paranteze drepte, exprimarea fiind
echivalent cu IF0(p; S1). Atunci cnd att S1 ct si S2 sunt actiuni prevzute, instructiunea este
echivalent cu sub-schema logic IF(p; S1, S2).
4.
Instructiunile insert si extract. Aceste instructiuni sunt necesare pentru lucrul cu liste. Acestea
sunt o prelungire a instructiunii de atribuire. Dac se specific o list L atunci insert i, L (sau L:=i)
exprim introducerea elementului specificat prin i n lista L, iar instructiunea extract i, L (sau
i:=L) specific extragerea elementului curent din lista L si depunerea acestuia n i.
5.
Instructiunea apel de procedur. Apelarea unei proceduri se face prin instructiunea apel de
procedur care are una din formele:
identificator_procedura
sau
identificator_procedura(lista de argumente)
unde identificator_procedura specific o procedur declarat, iar argumentele sunt expresii
separate prin virgul.
Se presupune c atunci cnd se ajunge la un apel de procedur se stabileste corespondenta ntre
argumente si parametri, si se execut toate instructiunile specificate n definitia procedurii. Dup
ultima instructiune a procedurii se continu cu instructiunea urmtoare apelului de procedur.
6.
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
8 of 16 12/9/2007 7:20 PM
Un apel de procedur este corect atunci cnd ntre argumente si parametri exist o concordant ca
numr, tip si mod de organizare. Convenim ca atunci cnd referim o variabil (ntr-o procedur)
de fapt, facem o referire la locatia de memorie corespunztoare argumentului respectiv. Spunem
c se realizeaz un transfer prin referint. Sunt posibile si alte moduri de transfer, dar acestea nu
sunt considerate momentan.
Instructiunea return. Aceast instructiune provoac prsirea corpului unui subprogram. n cazul
n care cuvntul return
este urmat de o expresie, valoarea expresiei este folosit ca valoare de retur a subprogramului.
Instructiunea return
fr valoare de retur este folosit pentru a prsi executia unei proceduri si a reveni n unitatea de
program din care a avut loc apelul; si anume la instructiunea ce urmeaz imediat acestui apel.
7.
Pentru a usura descrierea algoritmilor admitem prezenta, ca instructiuni ale limbajului
algoritmic, a instructiunilor Repeat si For. Instructiunea Repeat este modelat de structura
repetitiv REPEAT (p; S). Ea are forma:
Repeat S until p;
unde S este o secvent (eventual vid) de instructiuni, iar p modeleaz o expresie logic.
Instructiunea For este modelat de structura iterativ FOR(p; a,b,c) si are forma simplificat
For v := e
1
, e
2
, e
3
do S
unde: S este o secvent de instructiuni, iar expresiile e
1
, e
2
si e
3
au acelasi domeniu de valori ca
variabila v. n forma prezentat, instructiunea determin executarea secventei S pentru v lund
succesiv valorile e
1
, e
1
+e
3
, e
1
+2e
3
, ..., fr a trece dincolo de e
2
. Formei de mai sus i corespunde
structura iterativ:
FOR((v-v
2
)*v
3
0; SEQ v:= e
1
; v
1
:=e
2
; v
3
:=e
3
END, S, v := v +v
3
).
8.
2.5. Analiza complexittii
Existenta unui algoritm de rezolvare a unei probleme genereaz, imediat, ntrebri ca: Mai exist un alt
algoritm de rezolvare? Este algoritmul gsit "cel mai rapid"? Acest paragraf introduce notiunile
fundamentale privind complexitatea algoritmilor si prezint exemple simple de algoritmi pentru care se
determin complexitatea.
Analiza complexittii unui algoritm presupune determinarea resurselor de care acesta are nevoie pentru
a produce datele de iesire. Prin resurs ntelegem timpul de executare, dar uneori este necesar s
analizm si alte resurse precum: memoria intern, memoria extern etc. Modelul masinii pe care va fi
executat algoritmul nu presupune existenta operatiilor paralele; operatiile se execut secvential.
Timpul de executare al unui algoritm reprezint numrul de operatii primitive executate. Trebuie,
pentru fiecare algoritm, s definim notiunea de operatie primitiv, independent de masina secvential pe
care se va executa algoritmul.
n analiza complexittii unui algoritm avem n vedere cazul cel mai defavorabil din mai multe motive:
Timpul de executare n cazul cel mai defavorabil ofer o limit superioar a timpului de executare
(avem certitudinea c executarea algoritmului nu va dura mai mult).
1.
Situatia cea mai defavorabil este ntlnit des. 2.
Timpul mediu de executare este, uneori, apropiat de timpul de executare n cazul cel mai
defavorabil, dar dificil de estimat.
3.
Analiza exact a complexittii unui algoritm conduce la formule extrem de complicate. De aceea se
folosesc notatii asimptotice, care evidentiaz doar termenul preponderent al formulei.
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
9 of 16 12/9/2007 7:20 PM
Fie f si g dou functii reale. Atunci:
f(x) = o(g(x)) dac exist si este egal cu 0 (zero) limita:
f(x) = O(g(x)) dac exist c si x
0
astfel nct
f(x) = theta(g(x)) dac exist constantele C
1
si C
2
pozitive, si x
0
astfel nct pentru orice x x
0
:
f(x) ~ g(x) dac
f(x) = Omega(g(x)) dac exist M>0 si un sir x
1
, x
2
, ..., x
n
, ... Inf astfel nct pentru oricare j>0 are
loc inegalitatea
n general, se consider c un algoritm este mai rapid dect altul dac are un ordin de mrime pentru
timpul de executare mai mic. Pentru o dimensiune mic a datelor de prelucrat, aceste comparatii pot fi
(ns) eronate.
Notatia theta este utilizat pentru a specifica faptul c o functie este mrginit (inferior si superior).
Semnificatia notatiei O este de limit superioar, n timp ce semnificatia notatiei Omega este de limit
inferioar.
Exemple: x
3
= o (x
5
); sin(x) = o (x); (x+1)
2
= theta (2x
2
); x
2
+3x ~ x
2
.
Definitia 2.5.1.
Fie A un algoritm, n dimensiunea datelor de intrare si T(n) timpul de executare estimat pentru
algoritmul A. Se spune c algoritmul A are comportare polinomial (apartine clasei P) dac exist p>0
astfel nct T(n) = O(n
p
).
Definitia 2.5.2. O functie care creste mai rapid dect functia putere x
p
, dar mai lent dect functia
exponential a
x
cu a>1 se spune c este cu crestere exponential moderat. Mai precis: f este cu crestere exponential
moderat dac pentru oricare p>0 avem f(x) = Omega(x
p
) si oricare M>0 avem f(x) = o((1+ M)
x
).
Definitia 2.5.3. O functie f are crestere exponential dac exist a>1 astfel nct f(x) = Omega(a
x
) si
exist b>1 astfel nct f(x) = O(b
x
).
Printre functiile n -> f(n), nemrginite, functiile ce cresc cel mai lent sunt, de exemplu, de forma log log n
sau (log log n)
1,02
. Pentru n = 1000000, log log n ~ 2,6. Deci un algoritm a crui complexitate este log log
n este preferabil unui algoritm (elaborat pentru rezolvarea aceleiasi probleme) de complexitate log n.
Algoritmii de tip polinomial sunt mai lenti (cresterea functiei T(n) este mai rapid) dect algoritmii de
tip logaritmic. Urmeaz apoi algoritmii moderati (cu T(n) de forma n
logn
etc.) si cei cu crestere
exponential (2
n
, n
3
3
n
etc.). Algoritmii cei mai lenti sunt cei pentru care functia T(n) este foarte rapid cresctoare (de exemplu:
T(n) = n!).
n informatic sunt interesanti numai algoritmii care conduc la un timp de calcul cel mult moderat.
Dac un algoritm necesit timp de calcul exponential sau factorial, acesta va fi utilizat numai n cazuri
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
10 of 16 12/9/2007 7:20 PM
exceptionale. Tabelul urmtor ilustreaz cele de mai sus.
n 10 100 1000 10000
n
2
100 10000 1000000 100000000
n
3
1000 1000000 1000000000 1000000000000
log n 1 2 3 4
log log n 0 0.30103 0.47712 0.60206
Exemplul 2.5.1. (Produsul a dou numere complexe). Considerm numerele complexe a+bi si c+di (i
2
=
-1; a, b, c, d numere reale). Un algoritm pentru calculul produsului (a+bi)(c+di) este urmtorul:
real a,b,c,d,p,q;
real t1,t2;
P1 SEQ
Read a, b, c, d;
t1:=a*c; t2:=b*d; p:=t1-t2;
t1:=a*d; t2:=b*c; q:=t1+t2;
write p,q;
P1 END
Acest algoritm (notat P1) necesit 4 nmultiri, o adunare si o scdere. n final p reprezint partea real,
iar q furnizeaz partea imaginar a produsului celor 2 numere complexe. Urmtorul algoritm (notat P2)
calculeaz acelasi produs folosind 3 nmultiri, 3 adunri si 2 scderi:
real a,b,c,d,p,q;
real t1,t2,t3,t4;
P2 SEQ
Read a, b, c, d;
t1:=a+b; t2:=t1*c; t1:=d-c; t3:=a*t1;
q:=t2+t3;
t1:=d+c; t4:=b*t1;
p:=t2-t4;
write p,q;
P2 END
Algoritmul P1 necesit 2 locatii temporare, n timp ce algoritmul P2 necesit 4 locatii suplimentare. n
plus, necesarul de memorie depinde de metoda de reprezentare a numerelor reale ntr-un sistem de
calcul.
(Determinarea valorii maxime si a indicelui corespunzator, dintr-un sir (tablou)). Fie X un tablou cu n
elemente apartinnd unei multimi total ordonate Q: X = (x
1
, x
2
, ..., x
n
) cu x
i
din Q pentru i = 1, 2, ..., n.
Fie y o variabil de tipul Q. Se caut un indice k, ntre 1 si n astfel ca
y := max{x
i
: i=1, 2, ..., n | = x
k
,
iar k este cel mai mic numr cu aceast proprietate.
Pentru rezolvarea acestei probleme putem utiliza urmtorul algoritm, denumit n continuare MAXIM,
pentru Q = real.
procedure maxim(x,n,y,k)
integer n;real array x(n);
real y; integer i,k;
SEQ
k:=1; y:=x[1];
for i = 2, n, 1 do if y < x[i] then SEQ y := x[i]; k:=i END;
return
END
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
11 of 16 12/9/2007 7:20 PM
Observm c T(n) = n-1. Necesarul de memorie pentru stocarea datelor de prelucrat se exprim n
functie de metoda de reprezentare a informatiei n calculator.
Propozitia 2.5.1.
Pentru determinarea maximului dintre n elemente ale unei multimi total ordonate sunt necesare cel
putin n-1 comparri (T(n) = n-1).
Exemplul 2.5.3. (Determinarea celui mai mare divizor comun). Fie m si n dou numere ntregi pozitive si,
q si r ctul, respectiv restul mprtirii lui n la m, adic n = qm+r (0 r < m). Spunem c m divide n dac
restul mprtirii lui n la m este zero.
Pentru determinarea celui mai mare divizor comun (cmmdc) a dou numere se poate utiliza algoritmul
lui Euclid. Dac d este un divizor oarecare al numerelor n si m, atunci d divide restul r. Reciproc, dac d
este un divizor al numerelor m si r, relatia n = mq + r arat c d este divizor al numrului n. Deci:
cmmdc(n, m) = cmmdc(m, r).
Dac r = 0 atunci n = qm. Deci cmmdc(n, m) = m. Folosind notatia n mod m pentru r, putem scrie:
cmmdc(n, m) = cmmdc(m, n mod m).
Necesarul de memorie pentru stocarea numerelor n si m se poate exprima prin
theta(log m) + theta(log n) ~ theta(log (mn)) biti.
Timpul necesar executrii algoritmului este dat de urmtorul rezultat.
Propozitia 2.5.2.
Fie n si m dou numere ntregi pozitive. Algoritmul lui Euclid pentru a determina cmmdc(m, n)
efectueaz cel mult [2log
2
M]+1 operatii de mprtire ntreag, unde M = max (m, n).
Exemplul 2.5.4. (Sortare prin insertie). Fiind dat o secvent de elemente caracterizate de valorile x
1
, x
2
,
..., x
n
apartinnd unei multimi total ordonate T, s se determine o permutare x
i(1)
, x
i(2)
, .., x
i(n)
a
secventei date, astfel nct x
i(j)
x
i(k)
pentru i(j) i(k), unde " " este relatia de ordine pe multimea T. Metoda ce va fi prezentat n
continuare se mai numeste si "metoda juctorului de crti", si este una dintre cele mai cunoscute metode
de sortare.
Sortarea prin insertie se bazeaz pe urmtoarea procedur: Fie un tablou x cu n elemente (x[i] este al
i-lea element din secventa de intrare). Pornim cu subtabloul x[1] si la primul pas cutm pozitia n care
ar trebui s se gseasc elementul x[2]. Dac x[2] < x[1], atunci x[2] trebuie s fie mutat n locul
elementului x[1]. La un pas i (pentru i ntre 1 si n), avem subtabloul x[1..i-1] ordonat si ncercm s-l
plasm pe x[i] astfel nct s obtinem un tablou sortat ntre pozitiile 1 si i. Pentru aceasta, se compar
succesiv x[i] cu elementele tabloului x[1..i-1] pentru a se determina acea pozitie j pentru care x[i] x[j],
indexul de plasare fiind j+1.
Algoritmul prezentat n continuare utilizeaz insertia direct:
procedure insert_sort(n,x);
integer n;
integer array x(n);
integer i,j,temp;
SEQ
for i = 2, n, 1 do
SEQ
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
12 of 16 12/9/2007 7:20 PM
temp :=x[i];
j:=i-1;
while (j>=1) and (x[j] > temp) do
SEQ
x[j+1] :=x[j];
j:=j-1
END
x[j+1]:=temp
END;
return
END
Este clar c, timpul de executie nu depinde doar de n, numrul de elemente de sortat, ci si de pozitia
initial a elementelor din secvent.
Fie F(n) - numrul de comparri necesare, iar G(n) numrul de mutri necesare algoritmului insert_sort
pentru sortarea unui tablou cu n elemente.
Propozitia 2.5.3.
Complexitatea metodei de sortare prin insertie direct este caracterizat prin: F(n) = O(n
2
), G(n) =
O(n
2
).
2.6. Elemente privind corectitudinea algoritmilor
A verifica corectitudinea unui algoritm nseamn a verifica dac algoritmul conduce ntr-un interval
finit de timp la obtinerea solutiei corecte a problemei pentru care a fost elaborat. Vom vedea n capitolul
5 cteva metode de rezolvare a problemelor, deci de a elabora algoritmi. Metodele descrise n acest
capitol se vor exemplifica pentru algoritmi simpli. Pentru aspecte suplimentare legate de corectitudinea
algoritmilor se poate folosi lucrarea: Tudor Blnescu. Corectitudinea algoritmilor. Editura Tehnic,
Bucuresti, 1995.
Notatie. Constructia {P}A{Q}, numit si formul de corectitudine total contine urmtoarele elemente:
P - comentariu care descrie propriettile datelor de intrare (preconditia);
A - algoritmul (secventa de instructiuni) supus analizei;
Q - comentariu care descrie propriet{tile datelor de iesire (postconditia).
Definitia 2.6.1. Un algoritm {P}A{Q} este corect cnd propozitia urmtoare este valid:
Dac
datele de intrare satisfac preconditia P
Atunci
1) executarea lui A se termin (ntr-un interval finit de timp) si
2) datele de iesire satisfac postconditia Q.
Folosind elementele fundamentale ale logicii matematice rezult c urmtoarele observatii sunt
adevrate:
Algoritmul {false}A {Q} este corect, oricare ar fi A si Q. 1.
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
13 of 16 12/9/2007 7:20 PM
Algoritmul {P}A{true} este corect dac si numai dac executarea lui A se termin atunci cnd
datele initiale satisfac proprietatea P.
2.
Dac{P}A{Q} si {R}A{Q} sunt formule corecte, atunci {P v R}A {Q} este formul corect. 3.
Pentru a stabili corectitudinea algoritmilor complecsi se procedeaz la descompunerea acestora
elemente simple a cror corectitudine se analizeaz. n continuare vor fi prezentate reguli pentru a
analiza corectitudinea unor astfel de algoritmi. Pentru o formalizarea avansat a acestor reguli, cititorul
interesat poate parcurge lucrarea: C. A. R. Hoare et al. Laws of Programming. Comm. ACM. 30(8), 1987,
672-687.
Regula compunerii secventiale (CS):
Dac A este de forma SEQ B; C END atunci a verifica formula {P}A{Q}, revine la a verifica form
{P}B{R} si {R}C{Q}, unde R este un predicat asupra datelor intermediare.
Este evident c regula CS poate fi aplicat iterativ. Mai precis, dac A este de forma SEQ A
1
; A
2
; ..., A
n
END atunci obtinem regula compunerii secventiale generale:
&t9;CSG: Dac {P
0
} A
1
{P
1
}, {P
1
} A
2
{P
2
}, ...., {P
n-2
}A
n-1
{P
n-1
} si
{P
n-1
}A
n
{P
n
} sunt algoritmi corecti,
atunci{P
0
}A{P
n
} este algoritm corect.
Exemplul 2.6.1.
Este usor de verificat c urmtorul algoritm este corect (presupunem c x si y sunt variabile ntregi, iar
a si b constante ntregi):
{ x = a si y = b}
SEQ
x:=x+y;
y:=x-y;
x:=x-y
END
{ x = b si y = a }
Regula implicatiei (I):
Aceast regul este util n cazul algoritmilor ce urmeaz a fi aplicati n conditii mai tari dect pentru
cele care au fost deja verificati.
O proprietate P este mai tare dect proprietatea Q dac este adevrat propozitia compus: P -> Q.
Regula implicatiei are urmtoarea form:
I: Dac{P} A {Q} este algoritm corect, P
1
-> P si Q -> Q
1
,
atunci {P
1
} A {Q
1
} este algoritm corect.
Regula instructiunii de atribuire (A):
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
14 of 16 12/9/2007 7:20 PM
Fie notatiile:
x Variabil simpl
e Expresie;
Def(e) Proprietatea satisfcut de acele elemente pentru care evaluarea
expresiei e este corect (Exemplu: pentru integer array b(10),
Def(b(i)):= (i=1, 2, ..., 10));
P(x) Formul n care apare variabila x;
P(x/e) Formula obtinut din P(x) prin substituirea variabilei simple x cu
expresia e, ori de cte ori x este variabil liber n P, iar dac e
contine o variabil y care apare legat n P, nainte de substitutie
variabila y se nlocuieste printr-o nou variabil (care nu mai apare
n e).
Valoarea de adevr a propozitiei P -> Q(x/e) nu se schimb dac n Q(x/e) se efectueaz substitutia
descris de atribuirea x := e. Regula atribuirii este deci:
A: Dac P -> (Def(e) and Q(x/e)) atunci algoritmul {P} x:=e {Q} este corect.
Exemple de instructiuni corecte:
a){x = n!} n:=n+1; x:=x*n {x = n!}
b){(x = a) and (y = b)} t:=x; x:=y; y:=t {(x = b) and (y = a)}
c){(1<=i < n-1) and (s = SUM{b[k]: k=1, ..., i-1})}
s:=s+b[i]; i:=i+1
{(1< i < n) and (s = SUM{b[k]: k=1, ..., i-1})}
dac b este declarat prin integer array b(n).
Regula instructiunii if (IF si IFR):
Dac c este o expresie boolean si A si B sunt algoritmi, pentru cele dou forme ale instructiunii if
valabile regulile de corectitudine:
IF: Dac
{P and c} A {Q}, {P and not c} B {Q} sunt corecte, iar P -> Def(c) este adevrat
Atunci formula
{P} if c then A else B {Q} este corect.
IFR: Dac
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
15 of 16 12/9/2007 7:20 PM
{P and c} A {Q} este corect, iar P and (not c) -> Q si P -> Def(c) sunt adevrate
Atunci
{P} if c then {Q} este formul corect.
Se poate observa c aplicarea regulilor instructiunii de decizie nu este n sine dificil corectitudinea
acestei instructiuni se reduce la corectitudinea instructiunilor componente.
Exemple de instructiuni corecte:
a){true} if x>y then SEQ t:=x; x:=y; y:=t END {x <= y}
b){(x=a) and (y=b)} if x>=y then m:=x else m:=y {m = max(a,b)}
c){x=a} if x<0 then x := -x {x = |a|}
Regula instructiunii while (W):
Regula instructiunii while trebuie s precizeze dac nu apare fenomenul de ciclare, iar prelucrrile
corecte (n paranteze rotunde apare descrierea formal).
Fie algoritmul {P} A; while c do S {Q}. Presupunem c exist o proprietate invariant I (vezi mai jos) si
o functie de terminare t cu valori numere ntregi care satisfac urmtoarele conditii:
Cnd I este adevrat atunci expresia boolean c este bine definit (adic I -> Def(c)).
Proprietatea I rezult prin executarea secventei A (adic, {P} A {I} este algoritm corect).
La terminarea instructiunii while, proprietatea final Q poate fi dedus (adic, I and (not C) ->
Q).
I este proprietate invariant la executarea unei iteratii: dac I este adevrat nainte de executarea
secventei S si expresia boolean c este adevrat, atunci executarea secventei S se termin ntr-un
interval finit de timp si I este adevrat la sfrsit (adic, {I and c} S {I} este algoritm corect).
Dac rezultatul evalurii expresiei c este true si proprietatea I este adevrat, atunci exist cel
putin o iteratie de efectuat (adic, I and c -> (t > =1)).
Valoarea lui t descreste dup executarea unei iteratii (adic, {(I and c) and (t=a)} S {t < a}).
n aceste conditii, algoritmul considerat este corect.
Exemplul 2.6.2. (Determinarea celui mai mare divizor comun a dou numere ntregi). Fie a si b dou
numere ntregi, iar m = |a| si n = |b|. Atunci urmtorul algoritm este corect.
{(x > 0) and (y > 0) and (x = m) and (y = n)}
while x <> y do
if x > y then x := x - y else y := y - x;
ALGORITMI I file:///C:/ACTIV/Proc/FINAL/C3.HTM
16 of 16 12/9/2007 7:20 PM
{x = cmmdc(m,n)}
ntr-adevr, exist proprietatea invariant
I: (cmmdc(x,y) = cmmdc(m,n)) and (x > 0) and (y > 0),
iar ca functie de terminare se poate lucra cu: t(x,y) = x+y. Verificarea ipotezelor regulii W este simpl.
Exemplul 2.6.3. (Al n-lea termen al sirului lui Fibonacci). Fie f
n
, al n-lea termen al sirului lui Fibonacci.
Urmtorul algoritm este corect.
{n >= 0}
a:=0; b:=1; k:=n;
while (k > 0) do
SEQ
temp := b;
b := a + b;
a := temp;
k := k-1
END;
{a = f
n
}
ntr-adevr, lum functia de terminare t(k) = k, iar proprietate invariant este:
I: (a = f
n-k
) and (b = f
n-k+1
) and (temp = f
n-k
) and (0 <= k <=n).
Deoarece instructiunile repetitive for (ciclu cu contor) si repeat (ciclu cu test final) se pot implementa
folosind instructiunile anterioare, pentru demonstrarea corectitudinii acestora se aplic aceleasi
principii.
Mergi la inceputul capitolului
Text prescurtat dupa G. Albeanu. Algoritmi si limbaje de programare. Editura Fundatiei "Romnia de
Mine", 2000
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
1 of 48 12/9/2007 7:21 PM
3. Limbaje de programare
3.1. Vocabularul si sintaxa limbajelor de programare
3.2. Tipuri de date. Constante. Variabile. Expresii
3.3. Programare n C
3.1. Vocabularul si sintaxa limbajelor de programare
Vocabularul unui limbaj de programare este format din cele mai simple elemente cu semnificatie lingvistic
numite entitti lexicale sau tokens. Elementele vocabularului sunt alctuite din caractere Unicode (c
constituie alfabetul limbajului). Standardul Unicode contine ca subset codul ASCII, dar reprezentarea
intern a caracterelor Unicode foloseste 16 biti. Cele mai utilizate simboluri sunt: literele mari si m
alfabetului englez, cifrele sistemului zecimal, diferite semne speciale.
Unittile lexicale sunt separate, ntre ele, prin comentarii si spatii. Pentru aproape toate limbajele
programare se pot evidentia unitti lexicale precum: cuvinte cheie, identificatori, literali, separatori
operatori. Cuvintele cheie sunt secvente de caractere ASCII rezervate (nu pot avea alt semnificatie)
utilizate pentru definirea unittilor sintactice fundamentale. Pentru exemplificare ne referim la limbajele de
programare Pascal si Java:
Cuvinte cheie Pascal: absolute, and, array, begin, case, const, div, do, downto, else, end, external, file,
for, forward, function, goto, if, implementation, in, inline, interface, interrupt, label, mod, nil, not, of,
or, packed, procedure, program, record, repeat, set, shl, shr, string, then, to, type, unit, until, uses,
var, while, with, xor.
1.
Cuvinte cheie Java: abstract, boolean, break, byte, case, cast, catch, char, class, const, continue,
default, do, double, else, extends, final, finally, float, for, future, generic, goto, if, implements, import,
inner, instanceof, int, interface, long, native, new, null, operator, outer, package, private, protected,
public, rest, return, short, static, super, switch, synchronized, this, throw, throws, transient, try, var,
void, volatile, while, byvalue. Cuvintele cheie subliniate sunt prezente si in limbajul C alaturi de altele.
2.
Identificatorii sunt secvente, teoretic nelimitate, de litere si cifre Unicode, ncepnd cu o liter sau liniuta de
subliniere (n limbajul C). Identificatorii nu pot fi identici cu cuvintele rezervate.
Literalii ne permit introducerea valorilor pe care le pot lua tipurile de date primitive si tipul sir de
caractere. Mai precis, lieralii sunt constante ntregi, flotante, booleene, caracter si, siruri de caractere.
Literalii ntregi, n general, pot fi descrisi prin reprezentri n una din bazele de numeratie: 10, 16 s
Lungimea reprezentrii interne depinde de implementarea limbajului. De exemplu, n limbajul Pascal,
literal ntreg, cu semn, este reprezentat pe 16 biti, descrierea sa n baza 16 fiind o secvent a simbolur
asociate reprezentrii numrului ntreg n baza 16 avnd prefixul $.
Literalii flotanti reprezint numere rationale. Ei sunt formati din urmtoarele elemente: partea ntrea
partea fractionar si exponent. Exponentul, dac exist, este introdus de litera E sau e urmat optional de
un semn al exponentului. Exemple: 3.14; 23.5 e+2; 3e-123.
Literalii booleeni sunt TRUE si FALSE, primul reprezentnd valoarea boolean de adevr, iar cell
valoarea boolean de fals. Desi TRUE si FALSE nu sunt cuvinte rezervate, acestea nu pot fi folos
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
2 of 48 12/9/2007 7:21 PM
identificatori (n Pascal, Java s.a).
Literalii caracter sunt folositi pentru a desemna caracterele codului Unicode (sau ASCII, acolo unde es
cazul). Descrierea unui literal caracter se fie folosind o liter, fie o secvent special. Secventele specia
(numite secvente escape n C, C++ si Java) permit specificarea caracterelor fr reprezentare grafic
precum si a unor caractere speciale. Caracterele ce au reprezentare grafic pot fi descrise ntre apostrofuri,
ca n exemplele: 'P', 'A', '3', '!'. Secventele speciale se descriu diferit de la un limbaj la altul. Vom
exemplifica folosind limbajele Pascal si Java.
Secvente speciale n limbajul Pascal: 1) Un ntreg din domeniul 0, ..., 255 precedat de simbolul #
desemneaz un caracter dat prin codul su ASCII. 2) Un caracter imprimabil precedat de semnul
desemneaz un "caracter de control" avnd codul ASCII n domeniul 0, ..., 31.
Secventele escape n limbajul Java se descriu folosind apostrofuri, semnul \, litere si cifre. Vom exem
indicnd cteva secvente predefinite: '\b' (backspace = #8), '\n' (linefeed), '\r' (carriage return) etc.
Un literal sir de caractere este constituit din zero sau mai multe caractere ntre delimitatori. Secvent
caractere ce formeaz sirul poate contine att caractere imprimabile ct si secvente speciale. n limbaj
Pascal se utilizeaz apostroful ca delimitator, iar n limbajul C( C++, Java) ghilimelele.
Separatorii sunt caractere ce indic sfrsitul unui token si nceputul altuia. Acestia particip si la
constructia sintaxei limbajelor de programare. Ei nu trebuie confundati cu spatiile care si acestea sepa
unitti lexicale distincte. Separatorii sunt necesari cnd unittile lexicale diferite sunt scrise fr spatii ntre
ele. Cei mai ntlniti separatori sunt: ( ) { } [ ] ; , . Exemple: x[10], f(x,y), carte.autor etc. Operatorii sunt
simboluri grafice ce desemneaz operatiile definite de un limbaj de programare. n unele limbaje
programare este posibil redefinirea operatorilor, acelasi simbol fiind utilizat pentru operatii diferite
rezult din contextul n care apar. Lista minimal a operatorilor aritmetici include: +(adunare),
/(mprtire), *(nmultire). Mai sunt admise si operatii precum: % (C, Java) sau mod (Pascal, Modu
(mprtire ntreag n limbajul Pascal). Alti operatori sunt: operatori logici, operatori relationali, operatori
asupra sirurilor de caractere etc. Toti operatorii pot fi priviti si ca separatori.
O constructie aparte utilizat n programe pentru explicarea sau documentarea textului program
comentariul. Comentariile sunt delimitate de textul programului folosind anumiti delimitatori. n limb
Pascal, un comentariu este scris ntre acoladele } sau ntre secventele (*, *). Programele C++, Java p
contine comentarii pe o singur linie si ncep cu //, sau pe mai multe linii si sunt cuprinse ntre /* si */.
Alte elemente lexicale ce pot fi prezente ntr-un program sunt etichetele si clauzele. Etichetele sunt siruri de
cifre zecimale/hexazecimale sau identificatori folosite n legtur cu o instructiune de salt (goto) pen
marcarea unor instructiuni. Clauzele (numite si directive) sunt cuvinte cheie ce desemneaz instructiuni
efect n timpul compilrii.
Prin sintaxa unui limbaj de programare se ntelege, n general, un ansamblu de reguli privind agreg
unittilor lexicale pentru a forma structuri mai complexe (declaratii, instructiuni, module, progra
Prezentarea acestor reguli se poate folosind limbajul natural sau mecanisme formalizate. Descrierea
sintaxei n limbaj natural poate conduce la neclaritti sau specificatii incomplete. Cu ajutorul mecanismelor
formale sintaxa unui limbaj este complet specificat. Cea mai folosit notatie este cunoscut sub numel
notatie BNF (Backus-Naum-Form) si a fost folosit pentru prima dat, n anul 1959, la specificarea
limbajului Algol-60. Aceast notatie are aceeasi putere generativ cu gramaticile independente de c
introduse de N. Chomsky. Totusi, limbajele de programare nu sunt independente de context ci numa
portiuni ale acestora pot fi modelate cu ajutorul limbajelor independente de context. Pentru a putea
specifica un ntreg limbaj de programare se poate folosi notatia BNF extins. n prezentarea din acest
capitol vom utiliza opt metasimboluri: ::= < > { } [ ] | pentru a defini unittile sintactice ale limbajului
Pascal. Metasimbolurile < si > sunt folosite pentru delimitarea numelui unei unitti sintactice. Presupunem,
de asemenea, existenta unei operatii de concatenare pe multimea unittilor sintactice. Metasimbolul ::=
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
3 of 48 12/9/2007 7:21 PM
apare dup numele unei unitti sintactice si are semnificatia "se defineste prin". Metasimbolul | este utilizat
pentru a delimita mai multe variante de definire ale unei unitti sintactice, aceasta fiind obtinut p
reuniunea variantelor. Metasimbolurile { si } indic repetarea posibil (de zero sau mai multe ori)
simbolurilor pe care le delimiteaz. Pentru a desemna prezenta optional a unor simboluri se util
delimitatori, metasimbolurile [ si ]. Vom admite, pentru prescurtare metasimbolul ... care indic
continuarea unui sir de valori conform contextului n care apare. Iat cteva exemple:
<liter> ::= A ... Z descrie multimea literelor mari; 1.
<cifr> ::= 0 ... 9 descrie multimea cifrelor zecimale; 2.
<identificator> ::= <liter> { <liter> | <cifr>} descrie modul de formare a identificatorilor: un sir de
litere si/sau cifre, primul semn fiind o liter.
3.
<secvent cifre> ::= <cifr> { <cifr>} descrie modul de formare a unei secvente de cifre; 4.
<ntreg fr semn> ::= <secvent cifre> defineste un numr ntreg fr semn; 5.
<semn> ::= + | - 6.
<ntreg cu semn>::= [ <semn><ntreg fr semn> spune c un ntreg cu semn este un ntreg fr semn
precedat de un semn: + sau -.
7.
Prin diagrame sintactice se realizeaz o reprezentare grafic a modului de agregare a unittilor sintactice.
n cele ce urmeaz vom prefera limbajul natural (n anumite cazuri) si notatia BNF extins (n alte ca
cititorul interesat asupra diagramelor sintactice poate consulta, de exemplu: N. Wirth: Systematic
Programming: An introduction, Prentice Hall, 1972.
3.2. Tipuri de date. Constante. Variabile. Expresii
Un tip de date este o structur compus din: 1) o multime X de valori numite date si 2) o multime d
compozitie pe X (operatii ce se pot efectua cu valori din X). O dat are un singur tip (apartine unei s
multimi). Exist limbaje de programare puternic tipizate (n sensul verificrii cu regularitate a apartente
unei date la multimea de valori a tipului su, nc din faza de compilare). Astfel de limbaje de programa
sunt: Pascal, Modula, Ada etc.
Tipurile de date sunt standard sau definite de utilizator. Tipurile definite de utilizator se introduc
intermediul unei definitii folosind un cuvnt cheie precum type (n Pascal), typedef (n C) sau class (
limbajele C++ si Java). De asemenea se vor utiliza diverse cuvinte cheie pentru a specifica structura tipu
Dac pentru o anumit structur a unui tip nu este stabilit un identificator, spunem c avem de-a cu u
anonim.
Valorile unui tip de date (elementele multimii X sunt referite fie prin variabile, fie prin constante (literali
sau constante simbolice). O locatie de memorie care poate stoca o valoare a unui anumit tip de date s
numeste, prin abuz de limbaj, variabil. Orice variabil trebuie s fie declarat pentru a putea fi folosit. O
declaratie contine un tip de valori - ce indic: ce se stocheaz, cum se stocheaz si n ce operatii interv
valorile stocate - si un identificator pentru a ne referi la variabila ce obiectul declaratiei. Practic o variabil
este un obiect caracterizat de tip, adres si valoare, pentru care atributul valoare poate fi modificat.
n limbajul Pascal declaratia variabilelor este precedat de cuvntul cheie var:
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
4 of 48 12/9/2007 7:21 PM
var <declaratie variabile>{ <declaratie variabile>}
unde
<declaratie variabile> ::= <identificator>{,<identificator>}: <tip>.
n limbajele C, C++ si Java declaratia variabilelor arat astfel:
<tip> <identificator>{,<identificator>} n functie de locul n care apare declaratia unei variabile, acesteia i
se pot atribui atribute precum: local, global, static etc.
Exist limbaje de programare (de exemplu Java) care definesc o valoare implicit pentru fiecare variab
atunci cnd prin program aceasta nu "primeste" nici o valoare. Totusi, cele mai multe limbaje de
programare nu ofer acest serviciu si este necesar s se realizeze operatii de "initializare" explicit.
Initializarea unei variabile chiar n momentul declarrii acesteia, n limbajele de programare care pe
aceasta, se realizeaz folosind o descriere de forma:
IdentificatorulTipului IdentificatorulVariabilei = ValoareInit;
unde se presupune c ValoareInit este de acelasi tip cu tipul variabilei sau poate fi convertit (transformat
foarte usor) ntr-o valoare de acest tip.
Prezentarea elementelor unui tip este posibil fie prin intermediul literalilor, fie prin intermediu
constantelor simbolice. Constantele simbolice sunt identificatori asociati unor elemente ale anumitor
multimi. Declararea unei constante simbolice Pascal se realizeaz conform regulii:
const <identificator> = <constant>;
unde <constant> este un literal, o expresie constant (n care intervin literali) sau elemente structura
limbajul C, constantele simbolice se pot introduce prin intermediul directivei #define sau cuvntului cheie
const atunci cnd sunt declarate variabile ce nu pot fi modificate n program.
Operatiile cu elemente ale unui tip sunt fie predefinite, fie sunt introduse prin declaratii function sau
procedure (n Pascal) sau operator
(n C++). Agregarea variabilelor, constantelor si a operatorilor conduce la constructii numite expre
Expresiile sunt evaluate n cursul executrii unui program. Rezultatul unei expresii depinde de va
variabilelor n momentul evalurii.
Tipurile de date ntlnite n limbajele de programare actuale sunt clasificate n: tipuri de date simple; tipuri
de date structurate, tipuri referint (pointer), tipuri procedurale. n limbajele C, C++ si Java exist tipu
void. Aceast multime notat prin void nseamn fie multimea vid, fie o multime neprecizat.
Tipurile de date simple numite si tipuri primitive (sau tipuri standard) se refer la multimi de elemen
precum: numere ntregi, numere rationale, valori de adevr (logice sau booleene), caractere, valor
apartinnd unei enumerri sau unui interval (subdomeniu). O parte dintre tipurile simple sunt tipur
ordinale, adic tipuri caracterizate printr-o multime finit de valori, pe care este definit o ordine liniar si,
prin urmare, pentru orice element al unei asemenea multimi se stabileste numrul de ordine ord(.),
elementul predecesor pred(.) si cel succesor succ(.). Tipurile ordinale sunt cele care se refer la multi
precum: multimea numerelor ntregi, multimea valorilor de adevr, multimea caracterelor, multime
valorilor unei enumerri, multimea valorilor dintr-un subdomeniu al uneia dintre multimile anterioa
Tipurile rationale (simpl precizie, dubl precizie, precizie extins etc.) nu sunt considerate tipuri ordinal
desi sunt tot multimi finite de elemente. Trebuie observat c metoda de reprezentare n memor
calculatorului a numerelor rationale ar permite considerarea unei ordini liniare si, elementele unei astfel de
multimi ar avea un numr de ordine.
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
5 of 48 12/9/2007 7:21 PM
Tipurile ntregi ale limbajului Pascal sunt :
a) Tipul Byte : reprezint multimea numerelor ntregi fr semn ncepnd de la 0 pn la 255, reprezen
intern folosind 8 biti (un byte).
b) Tipul ntreg scurt Shortint : reprezint multimea numerelor ntregi cu semn ncepnd de la -128 pn
127, reprezentate n complement fat de doi, pe 8 biti.
c) Tipul ntreg Integer : se refer la domeniul de valori dintre -32768 si 32767, reprezentate pe 16
complement fat de doi.
d) Tipul Word : reprezint multimea numerelor naturale de la 0 la 65535 reprezentate pe 16 biti.
5) Tipul ntreg lung Longint : defineste un domeniu reprezentabil, cu semn, pe 32 de biti, n complement
fat de doi.
Tipuri ntregi ale limbajului Java sunt:
a) Tipul byte : este echivalent cu tipul Shortint al limbajului Pascal.
b) Tipul short (ntreg scurt): este acelasi cu tipul integer al limbajului Pascal.
c) Tipul int (ntreg): corespunde tipului Longint al limbajului Pascal.
d) Tipul ntreg lung (long): reprezint multimea numerelor ntregi, reprezentabile cu semn n complemen
fat de doi, pe 8 bytes adic 64 de biti.
Tipurile de numere rationale ale limbajului Pascal sunt desemnate prin identificatorii standard real (6 bytes),
single (4 bytes), double (8 bytes), extended (10 bytes) si comp (8 bytes) si descriu submultimi de num
rationale reprezentate n memoria intern n virgul mobil. Tipul de date comp este o multime de num
ntregi utilizate n calcule fr parte fractionar.
Tipurile de numere rationale ale limbajului Java se mai numesc tipuri flotante. Sunt disponibile multimile
float (4 bytes) si double (pe 8 bytes). Ca si pentru reprezentrile single, double, extended si comp al
limbajului Pascal, n cazul tipurilor float si double se utilizeaz standardul IEEE 754.
Tipul boolean
este folosit pentru descrierea multimii valorilor de adevr desemnate prin literalii true si false. Pen
declararea unei variabile de tip boolean n limbajele Pascal si Java se foloseste cuvntul boolean. n
versiunea 7.0 a limbajului Turbo Pascal au fost introduse nc trei tipuri booleene: bytebool, wordbo
longbool. Lungimea reprezentrii este: boolean - 8 biti, bytebool - 8 biti, wordbool - 16 biti, longbool - 32
biti. Referitor la tipul boolean, n Pascal, sunt adevrate: false < true, ord(false) = 0, ord(true) =1,
succ(false) = true, pred(true) = false.
Limbajul C++ nu are un cuvnt rezervat pentru variabile logice. Totusi, limbajul permite utilizare
operatiilor uzuale ale calculului cu propozitii: si, sau, negatia prin intermediul operatorilor: &&, ||,
Limbajul trateaz orice valoare nenul drept true si valoarea zero drept false. Valoarea rezultat n urm
unei operatii logice este 1 pentru rezultat true si 0 pentru rezultat false.
Pentru declararea variabilelor de tip caracter se utilizeaz cuvntul char. O variabil de tip caracter poate
avea ca valori coduri Unicode (pe 16 biti, n Java) sau coduri ASCII (pe 8 biti, n Pascal, C, etc.).
caracterelor fiind ordonat, au sens functiile: ord, pred si succ. Functia ord(.) ntoarce codul caracteru
dintre paranteze. O alt functie utilizat este chr, care transform o valoare ntreag ntr-un caracter c
codul Unicode corespunztor. Caracterele pot fi comparate ntre ele pe baza pozitiei lor n setul de
caractere Unicode.
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
6 of 48 12/9/2007 7:21 PM
Tipul enumerare
este reprezentat printr-o multime finit de identificatori separati prin virgule si inclusi ntre pa
Componentele acestui tip se consider ordonate, deci se pot aplica functiile: pred, succ si ord. De asemenea
se pot realiza comparatii ntre elemente. n limbajul Pascal, enumerarea (R, G, B) poate fi utilizat pentru a
introduce tipul RGB, iar ord(R) = 0, pred(B) = G, R<G, etc. n limbajul C, valorile asociate identificatorilor
pot fi sub controlul total al programatorului, precum n exemplul: enum {v1 = -100, v2 = 5, v3 = 7, v4 = -10
} v; permitnd astfel o nou metod de definire a constantelor. Unii identificatori pot fi initializati de ctre
programator urmnd ca ceilalti s primeasc valori n urma compilrii. n descrierea enum {a, b = 6, c, d}
x; vom avea a = 0, b = 6, c = 7, d = 8.
Componentele de tip enumerare nu pot fi citite de la un mediu de intrare si nici afisate deoarece este
retinut numai pozitia lor n enumerare. Un identificator prezent ntr-o list nu poate fi prezent si ntr-o
alt list.
Exemple (Pascal):
type A = (mat, fiz, chim, bio, inf);
B = (ian, feb, mar, apr, mai, iun, iul, aug, sep, oct, nov, dec);
Exemple (C):
typedef
enum {mat, fiz, chim, inf} A;
enum {r, g, b} culoare;
Un subdomeniu este definit ca un interval de valori ale unui tip ordinal, numit tip de baz. Este suficient s
se precizeze valoarea initial si valoarea final. De exemplu, subdomeniul 6..12 descrie secventa de numere:
6, 7, 8, 9, 10, 11, 12. Functia ORD (n limbajul Pascal) aplicat unui element dintr-un interval furniz
numrul de ordine al elementului considerat ca apartinnd tipului de baz. Reprezentarea intern
variabilelor de tip subdomeniu se n aceleasi conditii ca reprezentarea variabilelor tipului de baz.
Exemple (Pascal):
type culori = (red, green, blue, yellow, black);
rgb = red..blue;
Mint = 1..100;
Nu se pot defini subdomenii ale tipurilor rationale si nici ale tipurilor structurate, referint etc.
Pentru tipurile de date descrise mai sus exist operatii predefinite desemnate prin operatori si fun
predefinite. De cele mai multe ori, operatorii sunt binari. Exist ns si operatori unari. Unii dintre
operatori sunt extinsi pentru a actiona si asupra datelor structurate.
Tipurile de date structurate sunt agregri ale unor tipuri de date deja definite. Limbajele de program
actuale permit definirea urmtoarelor tipuri structurate: tablou, sir de caractere, nregistrare, multime,
fisier si obiect sau clas. Tipurile fisier vor fi introduse n 4.7, iar conceptele fundamentale privi
programarea orientat spre obiecte (definirea claselor) vor fi prezentate n alta parte.
Tipul tablou este implementat diferit de la limbaj la limbaj. Vom exemplifica modurile de definire a acestu
tip n cazul limbajului Pascal. Modul de utilizare a tablourilor n limbajul C va fi studiat altundeva.
Fie T un tip de date oarecare numit tip de baz si I un tip ordinal cu exceptia tipurilor longint sa
subdomeniu al acestuia. Prin tip de date tablou cu indici din I si elemente din T se ntelege multimea
tuturor functiilor x definite pe I cu valori n multimea T. Un tip tablou poate fi introdus prin declaratia:
type <identificator> = array [<tip indice> {,<tip indice>}] of <tip element>;
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
7 of 48 12/9/2007 7:21 PM
unde [ si ] sunt elemente ale limbajului Pascal, iar { si } sunt elemente ale metalimbajului, <tip indice> {,
<tip indice>} descrie multimea I, iar <tip element> descrie multimea T din definitie. Multimea I se poate
obtine ca produsul cartezian al unui numr oarecare, dar finit de multimi de tip ordinal (fr longint), dar
zona din memoria intern utilizat pentru stocarea elementelor tabloului nu trebuie s depseasc o
anumit dimensiune, dependent de implementare. Multimea T este orice tip de date cu exceptia tipului
fisier.
Exemple:
type a = array [1..10] of integer;
b = array [-5..5, -10..7] of real;
T = (r, g, b);
c = array [T] of char;
d = array [1..10] of array[-5..5] of array[char] of integer;
Referirea unui element al unui tablou se prin identificatorul tabloului si indexul elementului scris n
paranteze drepte: x['a'] dac x este un tablou cu <tip indice> = char. Dac un tablou este multi-dimensional,
referirea la o component se poate n mai multe moduri. De exemplu, dac x este un tablou bidimensio
atunci x[i,j] si x[i][j] reprezint acelasi element.
Limbajul Borland Pascal permite definirea unui tip numit sir de caractere (string). Lungimea sirurilor est
cel putin 0 (null) si cel mult 255. Din punct de vedere al reprezentrii interne, pentru un sir de caractere
aloc n+1 bytes (n conventia ASCII pe 8 biti), unde n este lungimea efectiv a sirului. Octetul cu adre
relativ zero este rezervat pentru memorarea lungimii efective. Declararea unui tip sir de caracter se
supune regulii:
type identificator = string[lungime_maxima] | string;
unde <lungime_maxim> stabileste limita superioar a numrului de caractere ce pot fi stocate; c
parantezele drepte si aceast limit lipsesc se consider siruri de lungime maxim 255. Un caracter din sir
este accesat similar ca elementul unui tablou, lungimea efectiv a sirului x este obtinut fie prin ord(x[0])
sau prin length(x).
Exemplu:
Definitia Type T30 = string[30]; introduce T30 ca fiind multimea sirurilor de caractere cu cel mult
caractere.
Tipul de date nregistrare (record) se introduce n Pascal prin:
type <identificator> = <tip record>; unde <tip record > este definit prin urmtoarele reguli BNF:
<tip record> ::= record <list de cmpuri> [;]end
<list de cmpuri> ::= <parte fix> [; <parte variante>] | <parte variante>
<parte fix> ::= <sectiune record> {; <sectiune record> }
<sectiune record> ::= <identificator>{, <identificator>}: <tip>
<parte variante> ::= case[ <identificator>:] <tip> of <variant> {; <variant>}
<variant> ::= <constant> {, <constant>} :[<list de cmpuri>] [;])
adic un element de tip record este n general format dintr-o parte fix si una variabil, fiecare dintre
acestea fiind alctuit din cmpuri.
Exemple:
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
8 of 48 12/9/2007 7:21 PM
1) Tipuri de date predefinite n Pascal:
const maxim = 100000;{constanta este de tip longint}
pi = 3.14159;
mint:integer :=maxint-1; {o expresie constanta}
pi2 = pi / 2; {o alta expresie constanta}
stop:char = 'Z';
type T1 = 0..maxint; { subdomeniu al tipului integer; maxint este constanta predefinita 32767}
const st:T1 = 100;
var x,y:T1; {x, y sunt variabile de tip T1}
a, b : real; { a, b sunt variabile de tip real}
flag, poz: boolean; {flag, poz sunt variabile logice}
ch: char;
i,j,k: integer; wi, wj, wk: word;
li, lj,lk:longint;
u:single; v:double; w:extended; {tipuri flotante - standardul IEEE 754}
2) Tipuri de date structurate n Pascal:
Type Data = record
ziua: 1..31;
luna: 1..12;
anul: 1..9999
end;
Figura = (triunghi, patrulater, cerc, elipsa);
Stare = array [Figura] of boolean;
Rvariante = record
{parte fixa}
cod:byte;
nume: string[30];
dataNasterii: Data;
{parte variabila}
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
9 of 48 12/9/2007 7:21 PM
case studii : (medii, superioare) of
medii:(NrClase:byte; Scoala:string[30];);
superioare: (Facultatea:string[20]; specializarea: string[15])
end; {un singur end}
Var d:Data; f: Figura; S: Stare; R: Rvariante;
{Constante denumite impropriu constante cu tip, de fapt sunt variabile initializate}
const d1:Data =(ziua:30; luna:5; anul:1999);
d2:Figura = cerc;
d3: Stare = (true, true, false, false);
d4:Rvariante = (cod:123;
nume:'Ionescu';
dataNasterii: (ziua:12; luna:8; anul:2000);
studii:medii;
Nrclase:12;
Scoala:'Liceul XXXX');
Un identificator de cmp trebuie s fie unic numai n nregistrarea unde a fost definit. Un cmp al u
variabile de tip record este referit prin identificatorul variabilei si identificatorul cmpului separate
printr-un punct. Exemplu: R.cod, R.nume, R.dataNasterii.ziua, R.studii, R.Nrclase, R.Scoala, d.anul etc.
Tipul multime (prezent n Pascal, Modula etc.) permite definirea multimilor ale cror elemente sunt
multimi. Fie T un tip scalar diferit de real si de tipurile flotante. Se numeste tip set cu tipul de baz T
multimea P(T) format din toate submultimile multimii T. Definitia unui tip set se prin:
type <identificator> = set of <Tip>;
unde <Tip> este tipul de baz. Constructia unui element de tip set urmeaz regulile:
<set> ::= [list de elemente] | []
<list de elemente> ::= <element> {, <element>}
<element> ::= <expresie> | <expresie>..<expresie>
cu [ , ] elemente ale limbajului Pascal, |, { si } simboluri ale metalimbajului, iar <expresie> reprezint o
expresie a crei valoare apartine tipului de baz. Astfel, pentru a ne referi la multimea vid folosim notatia
[], pentru a definii multimea vocalelor scriem ['a', 'e', 'i', 'o', 'u'], iar pentru a definii primele cinci numere
naturale nenule putem scrie n una din formele: [1, 2, 3, 4, 5], [5, 4, 3, 2, 1], [1..5], [1..3, 4, 5] etc.
Cu variabile de tip set se pot efectua urmtoarele operatii: + (reuniune), - (diferent), * (intersectie) ce au
ca rezultat un element de tip set, sau operatii relationale cu rezultat de tip logic: = (egalitate), <= (inclus n),
>= (include pe), <> (diferit). Apartenenta unui element t la o multime A este dat de valoarea de adev
expresiei t in A. Aceast expresie este adevrat dac primul operand - element de tip ordinal - este element
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
10 of 48 12/9/2007 7:21 PM
al operandului al doilea - cu multimea de baz compatibil cu t.
Dac tipul de baz are n valori, o variabil de tip set corespunztoare tipului de baz va fi reprezenta
memorie folosind n biti, depusi ntr-o zon de memorie contigu cu lungimea (n div 8) + 1 bytes dac n nu
este divizibil cu 8, respectiv (n div 8) bytes dac n este multiplu de 8. Prin urmare tipul set of char
reprezentat pe 32 de bytes.
Operatorii sunt simboluri care specific operatii efectuate asupra unor variabile sau constante denu
operanzi. Combinatiile valide de operanzi si operatorii reprezint expresii.
Limbajele de programare ofer o multitudine de operatori: operator de atribuire (simbolizat prin := sau =),
operatori aritmetici unari (utilizarea semnului, incrementare, decrementare), operatori aritmetici b
(adunare, scdere, nmultire, mprtire, obtinerea ctului si restului mprtirii a dou numere ntre
operatori logici (si, sau, negare), operatori relationali (egal, diferit, mai mic, mai mic sau egal, mai mare,
mai mare sau egal, apartine), operatori la nivel de bit (si, sau, negare, sau exclusiv, deplasare stnga
deplasare dreapta), operatori combinati (n limbajele C, C++ si Java), operatori asupra multimilor
(reuniune, intersectie, diferent), operatori asupra sirurilor de caractere (concatenare) precum si a
operatori.
Evaluarea expresiilor trebuie s tin seama de pozitia parantezelor si de propriettile operatorilo
(precedent, asociativitate, conversii implicite n cazul tipurilor compatibile, conversii explicite). Precedenta
stabileste ordinea de evaluare a operatiilor n cazul expresiilor care contin mai multi operatori diferiti.
Dac ntr-o expresie se ntlnesc operatii cu aceeasi precedent atunci ordinea de evaluare este dat de tipul
asociativittii (de la stnga la dreapta sau de la dreapta la stnga). Cnd ntr-o expresie apar operati
operanzi de tipuri diferite, nainte de efectuarea operatiei are loc un proces de conversie implicit (cnd nu
se semnaleaz explicit si nu apare fenomenul de incompatibiltate) prin care tipul cu cardinalul mai m
promovat ctre tipul mai bogat (se presupune aici c natura elementelor celor dou tipuri este aceasi).
3.3. Programare n C
Limbajul C a fost creat la AT & T Bell Laboratories in anul 1972 de Dennis Ritchie. Versiunea stan
limbajului C pana in anul 1988 a fost cea furnizata odata cu sistemul de operare UNIX si descrisa in [14]. In
anul 1983 a inceput redactarea standardului ANSI pentru limbajul C. Standardul ANSI a fost finalizat in
anul 1990.
3.3.1. Structura programelor C
In limbajul C programul este o colectie de module distincte numite functii, organizate in una sau mai m
unitati de translatare. Fiecare unitate de translatare poate fi compilata (analizata lexical si sintactic)
separat. O unitate de translatare trebuie sa contina cel putin o declaratie sau o definitie de functie. Ea
consta din fisierul sursa impreuna cu oricare fisier antet si fisiere sursa incluse prin directiva #include. O
unitate de translatare, prin compilare, conduce la un fisier obiect (.obj) relocabil.
Directivele precedate de delimitatorul # se numesc directive preprocesor, acestea specificand opera
anterioare procesului de compilare ce sunt efectuate de o componenta a mediului de programare
preprocesor.
O declaratie C specifica atributele unui identificator sau multime de identificatori. Regulile sintactice ce
stau la baza scrierii declaratiilor sunt redate prin:
<declaratie> ::= <specificator declaratie>
[ <lista declaratori de initializare> ] ;
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
11 of 48 12/9/2007 7:21 PM
<specificator declaratie> ::=
<clasa de memorare> [ <specificator declaratie> ] |
<specificator tip> [ <specificator declaratie> ] |
<calificator tip> [ <specificator declara#ie> ]
<lista declaratori de initializate> ::= < declarator initializare> |
<lista declaratori initializare>, <declarator initializare>
<declarator initializare> ::= <declarator> |
<declarator> = <initializare>
A face o declaratie nu presupune si alocarea memoriei pentru indentificatorul declarat. Exista situati
alocarea se realizeaza in alta unitate de translatare (cazul datelor externe).
Declaratia unui identificator asociaza numelui in mod explicit sau implicit o serie de atribute din m
urmatoare:
Clasa de memorare
- localizeaza zona de memorie in care este plasat elementul declarat (zona de date, un registru al
procesorului, stiva mediului de programare, zona de alocare dinamica) si delimiteaza durata alocarii
(intreg timpul de executare a programului, executarea unei functii sau a unui bloc etc.).
Domeniul numelui
- reprezinta portiunea din program in care poate fi utilizat identificatorul pentru accesarea
informatiei asociate si este determinat de pozitia declaratiei.
Durata de stocare - reprezinta perioada cat elementul asociat exista efectiv in memorie.
Legatura
- indica modul de asociere a unui identificator cu un anumit obiect sau functie, in procesul de editare
a legaturilor.
Tipul datei
(standard sau definit de utilizator) - descrie informatia continuta de elementul definit de identificator.
Clasa de memorare este specificata prin unul dintre cuvintele cheie: typedef, extern, static, auto,
register. Declaratia auto
se poate utiliza pentru variabile temporare - alocate folosind stiva, cu domeniul local. Variabilele declarate
in interiorul unui bloc sunt implicit locale, deci auto este rar utilizat. In limbajul C clasic, o declaratie
register reprezinta un apel la compilator pentru a stoca o variabila int sau char intr-un registru al
procesorului pentru a creste viteza de executare. Versiunile actuale permit specificarea register pentru
orice tip, semnificatia apelului fiind de optimizare a timpului de acces. Specificatorul typedef indica faptul
ca nu se declara o variabila sau functie de un anumit tip, ci se asociaza un nume tipului de date. Sintaxa
este:
typedef <definitie tip> <identificator>;
Specificatorul static
poate sa apara in declaratii locale de variabile pentru a indica durata statica sau in declaratii globale d
functii si de variabile pentru a indica legatura interna. Specificatorul extern este utilizat pentru declaratii
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
12 of 48 12/9/2007 7:21 PM
de functii sau variabile locale sau globale pentru a indica legatura extera si durata statica.
In C (precum si in Pascal), declaratia unei variabile trebuie sa preceada orice referire a ei. Ea poate aparea
in exteriorul oricarei functii, in lista de parametri formali ai unei functii sau la inceputul unui bloc.
Domeniul numelui este regiunea dintr-un program C in care identificatorul este "vizibil". Pozitia
declaratiei determina urmatoarele domenii:
Domeniul bloc - caracterizeaza identificatorii locali (identificatorii declarati in interiorul unui bloc si
au domeniul cuprins intre declaratie si sfarsitul blocului; parametrii formali din definitia unei functii
au ca domeniu blocul functiei).
Domeniul fisier
- caracterizeaza identificatorii declarati in exteriorul oricarei functii - numiti identificatori globali - si
care au domeniul cuprins intre declaratie si sfarsitul fisierului.
Domeniul functie - aplicabil pentru etichetele instructiunilor si este blocul functiei.
Domeniul prototip
- definit pentru identificatorii specificati in lista de parametrii din prototipul unei functii - si care au
domeniul limitat la acel prototip.
Partea din domeniu in care informatia asociata este accesibila se numeste zona de vizibilitate. O declaratie a
unui identificator este vizibila in tot domeniul sau mai putin blocurile sau functiile in care identificatorul
este redeclarat. Pentru identificatorii globali se poate repeta declaratia, dar initializarea trebuie sa se faca o
singura data.
Din punct de vedere al duratei de stocare, sunt posibile trei situatii:
Durata statica:
Obiectele cu durata statica au alocata zona de memorie pe toata durata de executare a programului.
Toate variabilele globale au durata statica. Alte variabile pot avea aceasta calitate prin utilizarea
specificatorilor static sau extern.
Durata locala:
Obiectele cu durata locala sunt cele automatice - spatiul de memorare se aloca (in stiva sau in
registru) la intrarea in executare a blocului sau functiei si este eliberat la iesirea din bloc sau din
functie. In concluzie, orice obiect automatic dispare la incheierea duratei sale de viata, deci informatia
continuta de acesta se pierde.
Durata dinamica:
Pentru obiectele cu durata dinamica, zona de memorie este alocata si eliberata la initiativa
programatorului prin apelarea unor functii C (de exemplu: malloc, free).
Un identificator declarat in diferite domenii, de mai multe ori, sau redeclarat in acelasi domeniu se poat
referi la acelasi obiect sau functie prin procesul numit legare. Legarea poate fi interna, externa sau unic
Daca un identificator are domeniul fisier si clasa de memorare static, el se supune legarii interne. Daca un
identificator are clasa de memorare extern, el se supune aceluiasi tip de legare precum orice declarati
vizibila a identificatorului cu domeniu fisier; daca nu exista declaratii vizibile cu domeniul fisier, se supune
implicit legarii externe. Pentru identificatorii cu legatura externa sunt permise mai multe declaratii
referinta, dar trebuie sa existe o singura definitie. Functiile au implicit legatura externa si durata statica.
In regulile sintactice de mai sus, <calificator tip> se refera la modificatorii de acces (const si volatile) care
controleaza modul in care valoarea unei variabile poate fi modificata. O variabila de tip const nu poate fi
modificata in timpul executiei programului. Declaratia volatile specifica faptul ca variabila poate fi
modificata din exteriorul programului sau intr-un mod care nu rezulta explicit prin program (de exempl
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
13 of 48 12/9/2007 7:21 PM
prin utilizarea adresei variabilei).
Specificatorii de tip indica modul de alocare asociat unei variabile sau tipul rezultatului unei functii. In
exista urmatoarele categorii de tipuri: tipuri de functii, tipuri de variabile si tipul void. Variabilele pot fi de
tip scalar, de tip structurat sau de tip uniune. Tipurile scalare sunt tipuri aritmetice si tipul pointer .
Tipurile structurate cuprind tablourile si inregistrarile (numite in C, structuri). In categoria tipuri
aritmetice intra multimile de elemente specificate prin cuvintele cheie: char, int, float, double; extinse cu
ajutorul modificatorilor de tip: signed, unsigned, short, long. Tot tip aritmetic este considerat a fi si
tipul obtinut prin enumerare.
Dimensiunea zonei de memorie ocupata de un tip sau de o variabila se poate afla prin intermediu
operatorului sizeof cu sintaxa sizeof (<tip>) sizeof <expresie>.
Tipul void indica absenta oricarei valori si este utilizat in urmatoarele situatii: declaratia unei functii fara
parametrii sau fara rezultat, tipul pointer generic si conversii de tip pentru pointeri.
Literalii sunt si ei afectati de existenta modificatorilor de tip prin indicarea unui sufix (U, u, L, l, f, F).
Efectul sufixului asociat unui literal intreg este ilustrat prin situatiile: U sau u - unsigned int sau
unsigned long int (in functie de valoare); L sau l - long int sau unsigned long int (in functie de
valoare); UL, ul, Ul, uL - unsigned long int. Un literal de tip numar zecimal, este automat de tip double;
daca se utilizeaza sufixul F sau f va fi considerat de tip float, iar daca se utilizeaza sufixul L sau l, va fi
considerat de tip long double.
Tabloul este o lista de elemente de acelasi tip plasate succesiv intr-o zona contigua de memorie. Nu exist
limita pentru numarul dimensiunilor tabloului.
Structura este o colectie de date eterogene (corespunde tipului record din limbajul Pascal). O declaratie de
structura precizeaza identificatorii si tipurile elementelor componente si constituie o definitie a unui tip d
date nou. Acestui tip i se poate asocia un nume. In cazul general, sintaxa declaratiei unei structuri este:
<declaratie structura> ::=
struct < id _tip> {
<tip _camp _1> <id _camp _1>;
<tip _camp _2> <id _camp _2>;
...
<tip _camp _i> <id _camp _i>;
...
<tip _camp _n> <id _camp _n>;
} <lista identificatori de tip struct>;
in care:
struct
- este cuvant cheie pentru construirea unui tip inregistrare;
<id_tip> - este un identificator ce desemneaza numele tipului structura ce este declarat;
<tip_camp_i> - tipul campului i;
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
14 of 48 12/9/2007 7:21 PM
<id_camp_i> - identificatorul campului i (campurile structurii se mai numesc si membrii structurii);
<lista identificatori de tip struct> - lista identificatorilor declarati.
Daca numele tipului <id_tip>
lipseste, structura se numeste anonima. Daca lista identificatorilor declarati lipseste, s-a definit doar noul
tip structura. Cel putin una dintre aceste specificatii trebuie sa existe. Daca <id_tip> este prezent, ulterior,
se pot declara noi variabile de tip structura prin intermediul declaratiei:
struct <id_tip> <lista noilor identificatori>;
Referirea unui membru al unei variabile de tip structura se face folosind operatorul de selectie (.) Int
expresie care precizeaza identificatorul variabilei si al campului.
Structurarea datelor la nivel de bit este posibila in limbajul C prin definirea de campuri de biti. Ace
facilitate este utila pentru scrierea aplicatiilor de control al dispozitivelor fizice s.a. Campurile de biti se pot
declara ca membrii ai unei structuri astfel:
struct <id_tip> {
<tip_ camp_ 1> <id_camp_1>:lungime _1;
<tip_camp_ 2> <id_camp _2>:lungime_ 2;
...
<tip_camp_i> <id _camp_ i>:lungime_i;
...
<tip_ camp_n> <id_ camp_n>:lungime_n;
} <lista identificatori de tip struct>;
Totusi, pentru c|mpurile de biti, < tip_ camp_i> poate fi doar int, signed sau unsigned, lungime _i este o
constanta intreaga cu valoarea in domeniul 0-15.
In exemplul:
struct s _bit {
unsigned a:1;
unsigned b:3;
unsigned :4;
unsigned c:3;
unsigned d:2;
} s;
pentru variabila s se vor aloca 16 biti (numerotati 0-15), ce pot fi accesati prin: s.a (bitul 0); s.b (bitii 1-3);
s.c (bitii 8-10); s.d (bitii 11,12). Observam ca bitii 4-7 nu pot fi accesati, pentru ei nu s-a specificat nici un
identificator de camp.
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
15 of 48 12/9/2007 7:21 PM
Alocarea campurilor poate ridica probleme de portabilitate, deoarece organizarea memoriei depinde
sistemul de calcul.
Uniunile
sunt entitati care pot contine (la momente de timp diferite) obiecte de tipuri diferite. Practic, mai mu
variabile sunt suprapuse in acelasi spatiu de memorie. Sintaxa declaratiei este similara cu cea a structurii
dar identificatorii declarati ca membrii reprezinta numele cu care sunt referite diferitele tipuri de variabile
ce ocupa aceeasi zona de memorie:
<declaratie uniune> ::=
union <id_tip> {
<tip_var_ 1> <id_var_1>;
<tip_ var_2> <id_ var_2>;
...
<tip_ var_i> <id _var_i>;
...
<tip_ var_ n> <id_ var_n>;
} <lista identificatori de tip union>;
Spatiul alocat in memorie corespunde tipului cu dimensiune maxima. Tipurile uniune sunt utile pen
conversii de date, in implementarea programelor de comunicatie etc.
Tipul enumerare
consta dintr-un ansamblu de constante intregi (cel putin un element), fiecare fiind asociata cate
identificator. Constanta unui element al enumerarii este fie asociata implicit, fie explicit. Implicit, pri
element are asociata valoarea 0, iar pentru restul este valoarea _precedenta+1.
Cel mai simplu program C este constituit din directive preprocesor, declaratii globale si functii. Printr
functii trebuie sa existe una cu numele "main
" cu care va incepe executarea programului. Chiar daca programul este organizat pe mai multe fisiere
sursa, numai intr-un singur fisier, numai o singura functie poate purta numele "main". Celelalte functii
sunt subprograme definite de programator sau functii din biblioteca de subprograme. Limbajul C nu
contine functii predefinite cum sunt cele din unitatea System a mediului Borland Pascal.
Functiile din bibliotecile C sunt declarate impreuna cu constantele, tipurile si variabilele globale asociate, in
fisiere antet, cu extensia ".h", situate in subarborele include al arborelui asociat mediului de programare.
Operatiile de intrare-iesire necesita specificarea fisierului stdio.h, incadrat de delimitatoriii < si >, intr-o
directiv{ # include. Fisierele antet ale programatorului vor fi incadrate folosind delimitatorul ".
O functie C are structura:
<tip_ rezultat> <id_functie> (<lista _parametri_ formali>){
declaratii_locale
secventa_instructiuni
}
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
16 of 48 12/9/2007 7:21 PM
unde <tip_ rezultat> indica tipul rezultatului returnat de functie, <id _functie> reprezinta numele
(identificatorul) functiei, iar <lista_parametri_ formali> consta in enumerarea declaratiilor parametrilor
functiei sub forma:
<tip_ parametru> <id_ parametru> [ ,<tip_parametru> <id _parametru>]
Acoladele { }
sunt delimitatori ce incadreaza o instructiune compusa (bloc) alcatuita din declaratii si instructiuni.
Secventa de instructiuni a functiilor pentru care <tip _rezultat> este diferit de tipul void, trebuie sa contina
o instructiune return, cu sintaxa generala:
return <expresie>
Rezultatul functiei este valoarea expresiei.
Functia main poate avea parametri si poate intoarce un rezultat. In exemplele ce urmeaza functia main nu
va avea parametri si nu va intoarce nici un rezultat.
Exemplul 3.3.1. (Program C pentru implementarea metodei bisectiei)
/* declaratii pentru functiile din biblioteci */
# include <stdio.h> /* biblioteca functiilor de intrare/iesire */
# include <math.h> /* biblioteca necesara pentru functia abs */
/* declaratii macrodefinitii: Preprocesorul inlocuieste in tot textul sursa, partea stanga (epsilon, pi) cu sirul
din dreapta. O conventie uzuala este folosirea literelor mari pentru identificatori, pentru a usu
recunoasterea lor in program. Sirul se termina cu linie noua. */
# define EPSILON 1E-7
# define PI 3.1415926
/* prototipuri ale functiilor definite in program */
float f(float);
float bisectie( float, float );
/* definitii ale functiilor */
float f( float x){
return (x-1)*(x-2)*(x-PI)*(x-2*PI);
}
float bisectie(float a, float b){
float c, fc;
int sfa;
sfa = (f(a) < 0.0);
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
17 of 48 12/9/2007 7:21 PM
do {
c = (a+b)/2;
fc = f(c);
if ((fc<0) == sfa) a=c; else b=c;
} while (fabs(b-a) >= EPSILON && fabs(fc) <= EPSILON);
return c;
}
/* functia main */
void main (void){
float a,b;
printf("\ n");
do {
printf("Introduceti a:"); scanf("%f",&a);
printf("Introduceti b:"); scanf("%f",&b);
} while (f(a)*f(b) >= 0);
printf("Radacina ecuatiei este: %15.8f \ n",bisectie(a,b));
}
Exemplul 3.3.2.
(Ridicarea la putere a unui numar complex dat sub forma algebrica se poate face cu ajutorul conversiei in
forma trigonometrica si al utilizarii formulei lui Moivre). Se solicita cititorului scrierea unei functii main
pentru folosirea functiilor definite in cadrul acestui exemplu.
#include <stdlib.h> /* pentru iabs */
#include <math.h> /* pentru sqrt, atan2, sin, cos etc. */
typedef struct {float mod; float arg;}F_TRIG;
typedef struct {float re; float im;} F_ALG;
float z_power(float x, int n){
float p=1.0; int m;
m = iabs(n);
if (m == 0) return 1.0; else {
while (m--) p *=x;
}
if (n<0) return 1.0/p; else return p;
}
F_TRIG cnv_trig(F_ALG t) {
F_TRIG s;
s.mod = sqrt(t.re*t.re+t.im*t.im);
s.arg = atan2(t.im, t.re);
return s;
}
F_ARG cnv_alg (F_TRIG s){
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
18 of 48 12/9/2007 7:21 PM
F_ALG t ;
t.re = s.mod * cos (s.arg);
t.im = s.mod *sin(s.arg);
return t;
}
F_ALG c_power(F_ALG z, int n) {
F_TRIG s = cnv_trig(z);
s.mod:=int_power(s.mod, n);
s.arg *= n;
return cnv_alg(s);}
In exemplele de mai sus am folosit functiile printf si scanf. De asemenea am folosit mai multi operatori.
Acestea vor fi prezentate in urmatoarele subsectiuni.
3.3.2. Functiile de intrare-iesire pentru consola
Consola sau dispozitivul standard de intrare-iesire reprezentate de tastatura (zona de date - stdin ) si ecran
(zonele de date - stdout si stderr) permit utilizatorului interactiunea cu programul aflat in executare.
posibile operatii de citire/scriere fara formatare si operatii de citire/scriere cu formatare.
Operatii de citire/scriere fara formatare. Acestea permit lucrul cu caractere (char ) sau cu siruri de
caractere (* char).
Pentru citirea unui caracter din stdin pot fi utilizate functiile: int getchar(void), int getche(void ) si int
getch( void), ultimele doua variante nefiind prevazute de standardul ANSI, dar sunt prezente in vers
Borland (fisierul antet conio.h). Functia getchar intoarce primul caracter din stdin , care corespunde
primei taste apasate, dar numai dupa apasarea tastei Enter. Caracterul este transformat in intreg fara
semn. In cazul unei erori sau la intalnirea combinatiei EOF (sfarsit de fisier) functia intoarce valoa
(codificata prin EOF).
Functia getche
asteapta apasarea unei taste si intoarce caracterul corespunzator pe care il afiseaza pe ecran (nu e nevoie de
Enter ). Functia getch este similara cu getche(), dar nu afiseaza ecoul pe ecran.
Pentru scrierea unui caracter la stdout se utilizeaza functia int putchar (int c) care afiseaza pe ecran
caracterul cu codul ASCII c. Daca operatia reuseste, intoarce caracterul afisat, iar in caz de esec valoare
EOF (-1).
Pentru citirea (resp. scrierea) sirurilor de caractere se lucreaza cu functia gets (respectiv puts). Functia cu
prototipul char *gets (char *s) citeste caractere din stdin si le depune in zona de date de la adresa s, pana
la apasarea tastei Enter. In sir, tastei Enter
ii va corespunde caracterul '\0'. Daca operatia reuseste, functia intoarce adresa sirului, altfel valoarea
NULL ( = 0 ). Functia cu prototipul int puts( const char *s) afiseaza pe ecran sirul de la adresa s sau o
constanta sir de caractere (secventa de caractere intre ghilimele) si apoi trece la linie noua. La succes,
functia intoarce ultimul caracter, altfel valoarea EOF.
Operatii de citire/scriere cu formatare.
La citire, formatarea specifica conversia datelor de la reprezentarea externa in reprezentarea binara.
Pentru operatia ce scriere se efectueaza conversia inversa.
Pentru citirea datelor se utilizeaza functia scanf cu prototipul:
int scanf( const char * format [ , lista_adrese_ variabile] );
iar pentru scrierea datelor se utilizeaza functia printf cu prototipul:
int printf( const char *format, lista_valori);
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
19 of 48 12/9/2007 7:21 PM
Sirul de caractere format poate contine in general:
specificatori de format: siruri precedate de caracterul '%' care descriu fiecare camp asteptat; I.
caractere de spatiere: spatiu (' '), tab ('\t'), linie noua ('\n'); II.
orice alt caracter Unicode. III.
Fiecarei variabile din lista ii corespunde o specificatie de format (tipul I.). Functia scanf intoarce numarul
de campuri citite si depuse la adresele din lista. Daca nu s-a stocat nici o valoare, functia intoarce valoarea
0. Functia printf intoarce numarul de octeti transferati sau EOF in caz de esec.
Functia scanf citeste succesiv caractere din stdin pe care le interpreteaza prin compararea succesiva a
caracterului citit cu informatia curenta din sirul format. Prezenta unui caracter de tip II determina citire
fara memorare a secventei pana la intalnirea unui caracter de tip I sau III. Prezenta unui caracter de tip III
determina citirea fara stocare a caracterului curent de la tastatura, daca este identic.
La scriere, caracterele de tip II si III se afiseaza pe ecran asa cum apar in sirul format. Forma generala a
unui descriptor pentru scriere este:
% [ flags] [ width] [ .prec] [ lmod] type
specificatiile dintre [ si ] fiind optionale. Elementele de mai sus au urmatoarea semnificatie:
flags - poate fi unul dintre semnele: +, -, 0, spatiu, #. Semnele au urmatoarea semnificatie:
- : aliniere la stanga a argumentului in cadrul campului;
+ : numerele vor fi obligatoriu tiparite cu semn;
0 : indica completarea la stanga cu zerouri (la numere);
spatiu: daca primul caracter nu e semnul, se va afisa un spatiu;
width: este un numar care specifica latimea minima a campului. Argumentul corespunzator va fi afisat pe
un camp cu latime cel putin width. Daca sunt mai putine caractere de scris, se va completa campul cu spatii
la stanga (implicit) sau la dreapta, daca s-a specificat flagul - . Daca s-a specificat flagul 0, se va completa la
stanga cu zero. Daca width
este caracterul *, atunci latimea este data de urmatorul argument din lista (trebuie sa fie neaparat un int).
prec: este un numar care specifica precizia de scriere; pentru %s prec indica numarul maxim de caractere
ce se va scrie; pentru %e, %E si %f prec indica numarul de zecimale; pentru %g si %G prec indica
numarul de cifre semnificative, iar la descriptorii pentru intregi indica numarul minim de cifre. Daca prec
este *, atunci se considera ca latimea de scriere este data de urmatorul argument din lista, care trebuie sa
fie de tip int.
lmod: este un specificator de lungime care corespunde unui argument short sau unsigned short (h), long
sau unsigned long (l), respectiv long double (L).
type: este descriptorul propriu-zis. Se utilizeaza urmatoarele caractere: d, i (int ) - notatie zecimala cu
semn; 0 (int ) - notatie in baza 16 fara semn; x, X (int ) - notatie in baza 16 fara semn cu abcdef pentr x si
ABCDEF pentru X; u (int ) - notatie zecimala fara semn; c (int ) - un caracter; s (char *) - sir de caractere
terminat cu '\0' ; f (double ) - numarul in virgula mobila cu format standard; e, E (double ) - numarul in
virgula mobila cu format exponential; g, G (double ) - in loc de f, e, E; p (void *) - se tipareste argumentul
ca adresa; % - se tipareste %.
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
20 of 48 12/9/2007 7:21 PM
Forma generala a unui descriptor pentru citire este:
% [ *] [ width] [ lmod] type
unde:
* - suprima atribuirea urmatorului camp din stdin la urmatoarea variabila;
width, lmod - ca mai sus;
type - descrie tipul de conversie. Cele mai importante specificatii de conversie sunt: d (int *) - intreg
zecimal; i (int *) - intreg oarecare (zecimal, octal sau hexa); o (int *) - intreg octal; u (unsigned int *) -
intreg zecimal fara semn; x (int *) - intreg hexa, c (char *) - caractere; s (char *) - sir de caractere (se va
incheia cu '\0 '); e, f, g (float *) - numere in virgula mobila; p (void *) - valoarea unei adrese asa cum e
tiparita de printf.
In descrierea de mai sus, intre paranteze se indica tipul argumentului supus operatiei de intrare-iesire
Notatia tip * inseamna adresa unei locatii de tipul tip.
3.3.3. Operatori si expresii
Operatorii sunt simboluri care descriu operatii efectuate asupra unor variabile sau constante (numite
generic operanzi). O combinatie corecta de operatori, variabile, constante, apeluri de functii reprezin
expresie. Pentru constructia expresiilor, limbajul C ofera o gama foarte larga de operatori.
Operatorul de atribuire. Operatorul de atribuire (=) permite crearea unei expresii de forma:
<variabila> = <expresie>
ce se evalueaza de la dreapta la stanga. Dupa evaluarea membrului drept, valoarea rezultata este inscrisa in
<variabila>, iar intreaga constructie are valoarea variabilei dupa inscriere.
Operatori aritmetici.
Operatorii aritmetici sunt: + (adunare), - (scadere), * (inmultire), / (impartire), % (impartire mo
impartitor). Ordinea operatiilor este cea binecunoscuta, dar se pot utiliza paranteze pentru schimbare
ordinii operatiilor. Pentru scrierea instructiunii de atribuire <variabila> = <variabila> + 1; se poate uti
forma prescurtata <variabila>++, operatorul ++ fiind numit operator de incrementare. Exista, de asemenea,
si un operator de decrementare (--): <variabila>--; ce este echivalentul instructiunii: <variabila>
<variabila> - 1;
Operatori logici si relationali. Pentru scrierea expressilor booleene se utilizeaza operatorii logici si operatorii
relationali. Exista trei operatori logici: || (SAU logic - SAU INCLUSIV), && (SI logic), ! (NU logic)
Operatorii relationali intalniti in limbajul C sunt urmatorii: < (mai mic strict), > (mai mare strict), <= (m
mic sau egal), >= (mai mare sau egal), == (egal cu), != (diferit de). Ori de cate ori relatia este falsa s
genereaza valoarea 0, valoarea 1 fiind generata atunci cand relatia este adevarata. Trebuie evidenti
operatorii aritmetici au prioritate fata de operatorii relationali.
Operatori la nivel de bit. Operatorii la nivel de bit se pot aplica operanzilor de tip intreg (char, int, short,
long , cu sau fara semn): & (SI logic la nivel de bit), (SAU logic la nivel de bit), ^ (SAU exclusiv la nivel
de bit), << (deplasare stanga), >> (deplasare dreapta) si (negare la nivel de bit).
Operatori de atribuire combinati. Pentru realizarea atribuirii
<variabila> = <variabila> <operator> <var _sau_const>;
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
21 of 48 12/9/2007 7:21 PM
se pot utiliza operatorii de atribuire combinati: += (atribuire cu adunare), -= (atribuire cu scadere),
(atribuire cu inmultire), /= (atribuire cu impartire), %= (atribuire cu impartire modulo); expresia fiind
scrisa prescurtat:
<variabila> <operator>= <var _sau_const>;
Operatorul virgula.
In limbajul C, virgula (,) este un operator binar, care leaga expresii oarecare. Constructia <expresie_ 1>,
<expresie_2> este una corecta, constand din evaluarea celor doua expresii, in ordinea in care apar, valoarea
intregii constructii fiind data de valoarea lui <expresie_2>. Asocierea operatorului virgula se face de la
stanga la dreapta, astfel incat o expresie de forma e1,e2,e3 este echivalenta cu: (e1, e2), e3.
Exemple:
1) # define Schimba(a,b) (temp=a, a=b, b=temp)
2) for(i=0, j=1; i<n; i+=1, j+=1) printf("%d, %d", i,j);
Operatorul conditional (?:)
Operatorul conditional este o constructie decizionala a limbajului C care are urmatoarea
<Expresie-booleana> ? <expresie_ 1> : <expresie _2>; avand urmatorul inteles: Daca <Expresie-booleana>
este adevarata atunci intreaga expresie conditionala are valoarea <expresie_1>, in caz contrar, valoarea
expresiei conditionale fiind valoarea <expresie_2>.
Exemple:
1) # define Semn(x) ((x<0) ? (-1) : (1))
2) e = (x<0) ? x*x+3 : sqrt(x);
Alti operatori:
In aceasta categorie includem operatorii specifici tipului referinta, operatorii pentru selectarea elemente
unui tip de date structurat, precum si operatorii introdusi de extensia C++.
3.3.4. Instructiuni C
Cea mai simpla instructiune C este instructiunea <expresie>; ce ofera un echivalent in C pentru
urmatoarele instructiuni Pascal: atribuire, apel de procedura, instructiunea vida. O secventa de instructiuni
incadrata de acolade este considerata ca o singura instructiune si este numita instructiune compusa sau
bloc. Spre deosebire de instructiunea compusa a limbajului Pascal, instructiunea compusa din limbajul
poate contine atat declaratii cat si instructiuni, declaratiile fiind pozitionate la inceputul blocului. In
implicit, identificatorii declarati in blocul delimitat de acolade, au ca domeniu de vizibilitate blocul, iar
timpul de viata este limitat la timpul de executare a blocului.
Programarea unei structuri decizionale, in C, poate fi realizata folosind: instructiunea if...else ; operatorul
conditional (?:) si instructiunea switch. Sintaxa instructiunii if...else este:
<instructiune_if> ::=
if ( <Expresie>) <Instructiune _T>;
if ( <Expresie>) <Instructiune_ T> else <Instructiune_ F>
unde: <Expresie> are o valoare de tip scalar reprezentand o constructie de tip expresie, <Instructiune_ T>
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
22 of 48 12/9/2007 7:21 PM
reprezinta o instructiune C care se va executa cand <Expresie> are o valoare nenula (adevarat),
<Instructiune_ F> reprezinta acea instructiune C ce se va executa pentru valoare 0 (false) a lui <Expresie>.
Conform celor de mai sus, constructia: e1 ? e2 : e3; poate inlocui instructiunea if...else: if (e1) e2; else e3;
Atunci cand o selectie multipla este controlata de valoarea unei singure expresii, se poate utiliza
instructiunea switch , un pseudo-echivalent C a constructiei Pascal case .
Sintaxa instructiunii switch este:
<instructiune_switch> ::= switch ( <expresie>) {
case <const_ 1> : <lista_ instructiuni> [ break;]
case <const_2> : <lista _instructiuni> [ break;]
...
[ default:] <lista_instructiuni> [ break ;]
}
unde: <expresie> este o o expresie cu valoare intreaga (tip intreg sau enumerare); <const_1>, <const _2>, ...
sunt constante de selectie, cu valori distincte, convertibile la tipul expresiei <expresie>, iar <lista
_instructiuni> este o secventa de instructiuni C.
Fiecare eticheta case indica o singura constanta, dar se pot asocia mai multe etichete case , scrise
consecutiv, pentru aceeasi secventa de instructiuni.
Instructiunea break intrerupe lista de instructiuni si duce la incheierea instructiunii switch . Daca
valoarea expresie nu apare in lista constantelor de selectie, se executa instructiunile asociate etichetei
default , daca exista.
Programarea ciclurilor poate fi realizata folosind instructiunile de ciclare: ciclul cu test initial (instructiunea
while ), ciclul cu test final (instructiunea do...while ) si ciclul cu test initial si contor (instructiunea for ).
Forma instructiunii while este:
while (<expresie>) <instruc#iune>.
]n particular, <instruc#iune> poate fi chiar instruc#iunea vid{.
Sintaxa instruc#iunii do..while este:
do <instruc#iune> while (<expresie>);
Instruc#iunea dintre do
~i while se execut{ cel pu#in o dat{ ~i se repet{ c|t timp <expresie> este compatibil{ cu valoarea log
adev{rat.
Instruc#iunea for, ofer{ cea mai compact{ metod{ pentru scrierea ciclurilor cu test ini#ial ~i are o defini#
care }i extinde domeniul de aplicare fa#{ de alte limbaje de programare. Forma instruc#iunii for este:
for ( <expresie_1> ; <expresie_3> ; <expresie_3> ) <instruc#iune>
~i are efectul similar cu al secven#ei:
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
23 of 48 12/9/2007 7:21 PM
<expresie_1>; while (<expresie_2>) { <instruc#iune> <expresie_3>;}
Cele trei expresii dintre paranteze pot fi toate vide, caz }n care avem de-a face cu un ciclu infinit.
]ntreruperea necondi#ionat{
a unei secven#e de instruc#iuni ~i continuarea dintr-un alt punct al programului este posibil{ prin utilizarea
instruc#iunilor de salt: goto (salt la o instruc#iune etichetat{), break (}n contextul instruc#iunii switch c|t
~i }n instruc#iunile de ciclare pentru a determina ie~irea for#at{ din ciclu, indiferent de valoarea condi#iei
de ciclare) ~i continue
(}n cadrul blocului instruc#iunilor de ciclare pentru a }ntrerupe execu#ia itera#iei curente). ]n
instruc#iunilor while ~i do..while, instruc#iunea continue determin{ activarea testului condi#iei de
ciclare, iar pentru instruc#iunea for se va continua cu evaluarea, }n aceast{ ordine, expresiilor
<expresie_3>, <expresie_2>.
Exemplul 3.4.3. (Evaluarea unei func#ii polinomiale date explicit):
# include <stdio.h>
void main (void) {
float t, val;
do {
printf(\ n Introduce#i valoare lui t:);
scanf(%f, &t);
val = (((5*t+4)*t-2)*t+3)*t-10;
printf(\ n Rezultatul evalu{rii este: %f, val);
printf(Continua#i [ d/n] ?);
} while (getche() == d);}
Exemplul 3.4.4.
(O implementare a algoritmului lui Nicomachus - utilizarea sc{derilor repetate - pentru determinarea celui
mare divizor comun a dou{ numere naturale nenule)
# include <stdio.h>
int cmmdc(int, int);
void main(void) {
int u,v;
while (scanf(%d %d, &u, &v) != EOF)
if ( (u>0) && (v>0) )
printf(%d %d %d \ n, u,v, cmmdc(u,v));
}
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
24 of 48 12/9/2007 7:21 PM
int cmmdc(int m, int n){
int temp;
do {
if (m<n) {
temp = m; m = n; n = temp;
}
m = m - n;
} while (m != n);
return(m);
}
Exemplul 3.4.5.
(Implementarea algoritmului lui Roy Warshall pentru determinarea matricei existen#ei drumurilor pentru u
graf G cu maxim 20 de v|rfuri.) Se noteaz{ cu x matricea de adiacen#{ a grafului (x[ i,j] = 1 dac{ v{rfurile i ~i
j sunt conectate direct, x[ i,j] =0, }n caz contrar). Se va ob#ine matricea y cu elemente: y[ i,j] =1 dac{
v{rfurile i ~i j sunt conectate printr-un drum, y[ i,j] =0, }n caz contrar.
# include <stdio.h>
# define maxlin 20
# define maxcol 20
# define or | |
# define nl \ n
unsigned char x[ maxlin] [ maxcol] , y[ maxlin] [ maxcol] ;
void main(void){ int i,j,n,k;
do { printf( nl Introduce#i dimensiunea grafului (cel mult %d):, maxlin);
scanf(%d, &n); } while ((n<1) or (n>maxlin));
printf( nl Introduce#i matricea de adiacen#{: nl);
for (i=0; i<=n-1; i++) for (j=0; j<n; j=j+1) scanf(%d, &x[ i] [ j] );
printf( nl S-a introdus matricea: nl);
for (i=0; i<n; i++) {
for (j=0; j<n; j++) { printf(%d, x[ i] [ j] ); y[ i] [ j] =x[ i] [ j] ; }
printf(nl);
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
25 of 48 12/9/2007 7:21 PM
}
for (j=0; j<n;j++) for (i=0; i<n; i++)
if (y[ i] [ j] != 0) for (k=0; k<n; k++) y[ i] [ k] = y[ i] [ k] or y[ j] [ k] ;
printf(nl Matricea existen#ei drumurilor: nl);
for(i=0; i<n; i++) {
for(j=0; j<n; j++) printf(%d, y[ i] [ j] );
printf(nl);
}
}
Exemplul 3.4.6. (Evaluarea unei func#iei). Se cere evaluarea func#iei urm{toare pentru un n ~i x da#i:
f
n
(x) := if (n = 1) then else
if (n = 2) then log
3
(1+| 3x+5| ) else
if (n = 3) then .
# include <stdio.h>
# include <math.h>
void main(void) { int n; float x,v,a,b,c;
do {
printf(N in [ 1, 2, 3] :); scanf(%d, &n);
} while ((n-1)*(n-2)*(n-3) != 0);
printf(x = ); scanf(%f, &x);
switch (n){
case 1: a=x*x; v=atan((2+a)/(1+a))+atan(3+2*a);
break;
case 2: v=log(1+fabs(3*x+5))/log(3);
break;
case 3: a=exp((x-3)*log(5)); b=x*x*x*x*x; c = a+b+1;
v=exp(log(fabs(c))/5.0); if (c<0) v=-v;
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
26 of 48 12/9/2007 7:21 PM
break;
}
printf(\ n N= %d x = %4.2f --> v =%7.3f, n, x, v);}
3.5. Recursivitate }n limbajele de programare
3.5.1. No#iunea de recursivitate
]n general, prin recursivitate se }n#elege proprietatea intrinsec{ a unei entit{#i (fenomen, proces etc.) de a fi
definit{ ~i/sau analizat{ folosind entit{#i de aceea~i natur{. Un algoritm }n a c{rui descriere este nece
referirea la el }nsu~i se nume~te algoritm recursiv. Aceast{ clas{ de algoritmi este }nt|lnit{ frecvent. Ea face
posibil{ prezentarea unor descrieri simple ~i elegante ale opera#iilor algoritmului.
Iat{ dou{ moduri diferite utilizate pentru a defini n!, unde n este un num{r }ntreg pozitiv. Prima defini#ie
este nerecursiv{, a doua este recursiv{.
n! este produsul tuturor numerelor }ntregi cuprinse }ntre 1 ~i n inclusiv.
Dac{ n=1 atunci n!=1, altfel n! este produsul dintre n ~i (n-1)!.
Observ|nd c{ }n a doua defini#ie se folose~te aceea~i descriere dar pentru o valoare mai mic{, adic{ n-1, ~i
c{ procedeul poate continua p|n{ la }nt|lnirea valorii 1, putem demonstra prin induc#ie c{ a doua defini#ie
este corect{.
Limbajele de programare moderne ofer{ posibilitatea descrierii ~i utiliz{rii subprogramelor recursive
Printre aceste limbaje g{sim: Pascal, PL/C, Lisp, APL, C, Java precum ~i altele. Ceea ce caracter
subprogram recursiv este faptul c{ se autoapeleaz{, pentru un domeniu restr|ns de valori.
Exemplific{m implementarea defini#iilor de mai sus }n subprograme Pascal. Func#ia fact_nr descrie
algoritmul de calcul nerecursiv, iar func#ia fact_r codific{ defini#ia recursiv{.
Exemplul 3.5.1. (Calculul factorialului)
Program Demonstrativ_Fact;
var eroare: boolean;
function fact_nr(n:integer):integer;
var p, i:integer;
begin
if n<=0 then begin eroare:=true; fact_nr:=-1 end
else begin
eroare:=false; p:=1; for i:=1 to n do p:=p*i;
fact_nr:=p
end
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
27 of 48 12/9/2007 7:21 PM
end;
function fact_r(n:integer):integer;
begin
if n<=0 then begin eroare:=true; fact_r:= -1 end
else if n=1 then begin eroare:=false; fact_r:=1 end
else fact_r:=n*fact_r(n-1)
end;
var x:integer;
begin
eroare:=false;
for x:= -1 to 7 do
if not eroare then writeln(fact_nr(x), , fact_r(x))
end.
Trebuie s{ observ{m necesitatea testului n<=0, omiterea acestuia, pentru numere }ntregi negative,
conduce la continuarea autoapelului p|n{ la blocarea sistemului.
]ntotdeauna, structura global{ a unui subprogram recursiv este:
subprogram Id(lista de variabile);
SEQ
...
If (conditie_de_oprire_a_autoapelului) then SEQ .... END
else SEQ ...;
apeleaz{ ID(lista de variabile - cu valori modificate);
...
END;
...
END
3.5.2. Tipuri de recursivitate
]ntr-un program Pascal de forma p[ ...; q; ...; r; ...] :
program p;
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
28 of 48 12/9/2007 7:21 PM
...
procedure q;
...
begin ... end;
...
procedure r;
...
begin ... end;
...
begin ... end.
subprogramul r poate sa apeleze subprogramul q, dar q nu poate apela r deoarece r nu este }nc{ decla
Pentru aceasta, limbajul Pascal, propune utilizarea directivei forward. ]n declara#ia propriu-zis{ a lui r
care urmeaz{ subprogramului q, se folose~te un antet redus }n care se specific{ doar numele lui r,
parametrii ~i tipuri (similar prototipurilor de func#ii C). Programul P va avea forma p[ ..; r forward; ..; q;
..; r; ..] :
program p;
...
procedure r (var x:integer); forward;
...
procedure q;
...; var t:integer; ...
begin ...; r(t); ... end;
...
procedure r;
...
begin ...; x:=x+1; ... end;
...
begin
...
end.
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
29 of 48 12/9/2007 7:21 PM
Referirea lui r }n q este posibil{ ~i f{r{ folosirea directivei forward, prin simpla inversare a ordinei
declara#iilor lui q ~i r }n p. Se ob#ine forma: p[ ...; r; ...; q; ...] . Dac{ at|t q apeleaz{ r c|t ~i r apeleaz{ q,
inversarea nu rezolv{ problema ~i trebuie folosit{ directiva forward. Referirea mutual{ a dou{ sau mai
multe subprograme }n maniera descris{ mai sus, cu folosirea necesar{ a directivei forward, se nume~te
recursie indirect{. Atunci c|nd un subprogram se apeleaz{ nemijlocit pe el }nsu~i spunem c{ recursia este
direct{.
]n limbajul C, introducerea declara#iilor f{r{ defini#ii ale func#iilor (prototipuri), nu numai c{ p
recursivit{#ii indirecte este rezolvat{, dar compilatorul are ~i posibilitatea de a efectua verificarea
validit{#ii apelurilor (num{rul ~i tipul parametrilor) precum ~i eventualele conversii de tip pentru
parametri ~i rezultat. Vom prezenta un exemplu de program C }n care apare fenomenul de recursivitate
Mai multe exemple (subprograme recursive codificate }n C sau Pascal) vor fi introduse }n capitole
urm{toare.
Exemplul 3.5.2.
(Metoda inser#iei binare pentru ordonarea cresc{toare a unui tablou unidimensional cu numere }n virgu
mobil{).
]ncep|nd cu al 2-lea element, se determin{ - prin c{utare binar{ - pozi#ia pe care trebuie s-o ocupe un
element, cunosc|nd numai elementele deja prelucrate, apoi deplaseaz{ anumite elemente pentru a-l depune
la locul potrivit.
# include <stdio.h>
# include <conio.h>
# define max 100
typedef float vector[ max] ;
int n,i,k; vector a;
int poz(int st, int dr, int j) {
/* determin{ pozi#ia elementului a[ j] }n ~irul a[ st] ,..., a[ dr] */
int mijloc;
if (st == dr) if (a[ j] < a[ st] ) return (st); else return (j);
else if (dr-st == 1)
if (a[ j] <a[ dr] ) if (a[ j] >= a[ st] ) return (dr);
else return (st);
else return(j);
else { mijloc = (st+dr)/2;
if (a[ mijloc] <= a[ j] ) return (poz(mijloc, dr, j));
else return (poz(st, mijloc, j));
} }
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
30 of 48 12/9/2007 7:21 PM
void deplasare(int j, int pozi#ie) {
int i, temp;
if (j > pozitie) {
temp = a[ j] ;
for (i=j; i>=pozi#ie+1; i--) a[ i] = a[ i-1] ;
a[ pozi#ie] = temp;
}
}
void main(void) {
clrscr(); printf(n>); scanf(%d, &n);
for (i=0; i<=n-1; i++) { printf(%d:, i); scanf(%f, &a[ i] );}
for (i=1; i<=n-1; i++) { k=poz(0,i-1,i); deplasare(i,k); }
printf(Sirul ordonat:\ n);
for (i=0; i<=n-1; i++) printf(%5.2f, a[ i] );
gotoxy(1,25); printf(Apas{ orice tast{!); getch();
}
3.6. Tipul referin#{ }n limbajele de programare
Tipul referin#{ reprezint{ adrese ale unor zone de memorie. Variabilele ce stocheaz{ adrese ale unor zone
de memorie se mai numesc ~i pointeri. Pointerii sunt necesari pentru a permite lucrul cu variabile
dinamice, care pot fi create ~i distruse }n timpul execut{rii unui program. Datorit{ diferen#elor sintactice
}n definirea ~i utilizarea pointerilor, care exist{ }ntre limbajele de programare Pascal ~i C, }n cele ce
urmeaz{ se va discuta mai }nt|i tipul de date referin#{ }n Pascal, apoi declararea ~i opera#iile cu poin
limbajul C.
3.6.1. Tipul referin#{ }n Pascal
]n limbajul Pascal este permis{ utilizarea a dou{ clase de variabile: statice ~i dinamice. Variabilele statice
sunt alocate }n timpul compil{rii, iar locul ocupat de ele }n memorie nu poate fi modificat }n execu#ie; e
exist{ pe durata }ntregii execu#ii a blocului (program, procedur{ sau func#ie). Variabilele statice su
declarate }n sec#iunea VAR.
Variabilele dinamice nu apar }ntr-o declara#ie explicit{ }n sec#iunea VAR, ~i accesul la acestea nu se poate
face direct. Crearea ~i distrugerea variabilelor dinamice se realizeaz{ cu procedurile New ~i Getmem
respectiv Dispose ~i Freemem. Aceste subprograme aloc{, respectiv elibereaz{ spa#iul de memorie pentru
variabile dinamice. Adresa zonei de memorie alocat{ unei variabile dinamice va fi stocat{ }ntr-o variabil{ de
tip special, numit referin#{. Lungimea zonei alocate depinde de tipul variabilei dinamice. De exemplu,
pentru adrese ale locatiilor de tip intreg se aloca 2 bytes, pentru locatii care s{ stocheze numere }n virg
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
31 of 48 12/9/2007 7:21 PM
mobil{ dubl{ precizie (double) se aloc{ 8 bytes. Spa#iul de memorie supus aloc{rii/eliber{rii dinamice
nume~te HEAP.
Definirea unui tip referin#{ se poate face }n sec#iunea type, astfel:
type PT = ^ T;
unde semnul ^
semnific{ o adres{. Mul#imea valorilor de tip PT const{ dintr-un num{r nelimitat de adrese; fiecare
adres{ identific{ o variabil{ de tip T. La aceast{ mul#ime de valori se mai adaug{ valoarea NIL care
identific{ nici o variabil{. Limbajul Pascal permite ca }n momentul }nt|lnirii tipului variabilei dinamice
acesta s{ nu fi fost definit; acest tip va fi, totu~i, declarat }n aceea~i declara#ie de tip (referire }nainte sau
autoreferire).
Exemplu: (Referire }nainte)
type referinta = ^articol; articol = record u, v: integer end;
var p,q:referinta; (* referire la variabile de tip articol *)
r: ^real; (* referire variabile dinamice *)
s: ^boolean; (* de tip ra#ional, respectiv logic *)
Exemplu: (Tip de date recursiv) O list{ este fie vid{, fie este identificata prin primul element ~i prin sublista
ce urmeaza acestuia. Defini#ia are caracter recursiv ~i este specificat{ prin:
type reper = ^lista;
lista = record
element: string[ 10] ; sublista: reper
end;
var p, q, r: reper;
begin
new(p);
new(q);
q^.sublista:=NIL;
p^.sublista:=q;
p^.element:=PRIMUL;
q^.element:=ULTIMUL;
end.
Dup{ crearea unei variabile dinamice a c{rei adres{ este depus{ }ntr-o variabil{ de tip referin#{, ea po
accesat{ prin a~a numita dereferen#iere: numele variabilei de tip referin#{ este urmat de semnul ^. Acest
semn poate fi urmat ~i de un alt calificator (de c|mp, ca }n exemplul 2; de tablou etc.). ]ntotde
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
32 of 48 12/9/2007 7:21 PM
dereferen#ierea unei variabile cu con#inut NIL declan~eaz{ o eroare de execu#ie.
Exist{ un tip predefinit Pointer, care este un tip referin#{ f{r{ tip de baz{. Astfel, o variabil{ de acest tip
poate s{ repereze o variabil{ de orice tip, motiv pentru care acestui tip i se mai spune ~i tip generic sau
liber. Declararea unei variabile de acest tip se face prin Var <identificator>:pointer; Variabilele de acest
tip sunt compatibile cu valoarea NIL, dar nu pot fi dereferentiate: scrierea simbolului ^ dup{ o astfel de
variabil{ constituie eroare. Variabilele de tip pointer sunt utile pentru memorarea unor variabile de tip
legat.
Valorile de tip referin#{ pot fi create cu operatorul @ ~i cu func#ia standard Ptr. Aceste valori sunt tratate
ca referin#e pentru valori dinamice.

3.6.2. Tipul referin#{ }n C
Facilit{#ile oferite pentru lucrul cu variabile de tip referin#{ (numite }n continuare pointeri) reprezint{ unul
dintre atuurile foarte importante ale limbajului C. Din punct de vedere al zonei adresate se disting 2
categorii de pointeri cu roluri ~i propriet{#i distincte: pointeri de date (con#in adrese de variabile s
constante din memorie) ~i pointeri de func#ii (con#in adresa codului executabil al unei func#ii). O a
categorie permite utilizarea pointerilor generici, numi#i ~i pointeri void.
3.6.2.1. Pointeri de date.
Sintaxa unui pointer de date este:
TIP *vpt;
Simbolul * precizeaz{ c{ vpt este numele unei variabile pointer, iar TIP este tipul obiectelor a c{ror adres{ o
va con#ine (adic{ tipul de baz{).
Pentru toate opera#iile }n care intervin pointeri, compilatorul interpreteaz{ zona de memorie adresat{
pointer ca obiect de tipul indicat la declarare, cu toate atributele tipului: num{rul de bytes necesa
semnifica#ia con#inutului zonei.
Declara#ia void
*vpt; este permis{ ~i permite declararea unui pointer generic. Tipul de baz{, }n declararea de mai sus, nu
este specificat. ]n cazul unui pointer void, dimensiunea zonei de memorie adresate ~i interpretare
informa#iei nu sunt definite, iar propriet{#ile sunt diferite de cele ale altor pointeri de date.
O variabil{ pointer este tot un obiect, deci are sens declararea unui pointer (ac#iune de indirectare) d
pointer. ]ntotdeauna, }nainte de utilizare, o variabil{ pointer trebuie ini#ializat{ (cu valoarea NULL =
adresa unei variabile existente sau adresa returnat{ de un apel de alocare a memoriei). Pointerii de orice tip
pot fi compara#i cu NULL pentru a verifica egalitatea sau inegalitatea.
Folosirea variabilelor pointer este posibil{ prin intermediul operatorilor unari: operatorul & (adresa
}ntoarce adresa unui variabile oarecare ~i, operatorul * (indirectare) pentru accesul la variabila adresat{ de
un pointer.
Fie declara#iile:
TIP var;
TIP *pvar;
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
33 of 48 12/9/2007 7:21 PM
atunci: &var (se cite~te adresa variabilei var) este de tip TIP *, deci atribuirea pvar = &var este corect{.
De asemenea, *pvar
(se cite~te la adresa pvar) reprezint{ obiectul de tip TIP adresat de pvar. Construc#ia *pvar poate
utilizat{ oriunde folosirea unei variabile este permis{ (inclusiv modificare).
Atribuirea este permis{ }ntre pointeri dac{ sunt de tipuri compatibile. ]n cazul pointerilor generici, e
necesar{ utilizarea operatorului cast de forma (TIP *).
Exemplu: (Un pointer poate indica obiecte diferite pe parcursul execu#iei programului)
void main(void){
int a=1, b=2, *c=&a; float d=3.14; void *e; printf(%d,*c);
*c=10; printf(%d %d,*c,a);
(*(c=&b))++; printf(%d %d %d,a,b,*c);
e=&d; printf(%f%f, d, *(float *)e);
e=&a; printf(%d %d, a, *(int *)e);
}
Al{turi de atribuire, }n limbajul C, sunt permise ~i opera#ii de comparare, adunare ~i sc{dere (
incrementare ~i decrementare):
compararea a doi pointeri folosind operatori rela#ionali. De exemplu, secven#
a {...; int *a, *b; ...; if (a<b) printf(%d %d, a, b); ... }este corect{.
compararea unui pointer cu valoarea NULL. Secven#a de alocare a 5 loca#ii de tip
float:
{...; if ((ptr=malloc(sizeof(float)*5))=NULL)
printf(Mem. insuficient{); else ... }
este echivalent{ cu:
{...; if (!(ptr=malloc(sizeof(float)*5)))
printf( Mem. insuficient{); else ...}.
adunarea dintre un pointer de obiect ~i un }ntreg, conform unei reguli specifice: Pentru variabila
pointer declarat{ prin:
TIP *varpt; opera#iile: varpt + n ~i varpt - n corespund adun{rii (resp. sc{derii la (resp. din) adresa
varpt a valorii n*sizeof(TIP). Pentru aceste opera#ii, operanzii nu pot fi de tip void ~i nici pointeri de
func#ii.
sc{derea a doi pointeri de acela~i tip (excluz|nd cazurile
void
~i pointeri de func#ii), av|nd ca rezultat num{rul de obiecte de tipul respectiv. De exemplu, pentru
declara#iile: ...; int n; float *a, *b; ..., atribuirea n=b-a; este echivalent{ cu atribuirea lui n a valorii
(adr_b - adr_a)/sizeof(float).
Limbajul C permite utilizarea variabilelor tablou ca pointeri. Mai precis un nume de tablou f{r{ index este
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
34 of 48 12/9/2007 7:21 PM
un pointer constant de tipul elementelor tabloului ~i are ca valoare adresa primului element din ta
Opera#iile aritmetice de mai sus sunt definite consider|nd c{ obiectele adresate constituie un tablou.
Referitor la leg{tura dintre tablouri ~i pointeri, se impun urm{toarele observa#ii:
se pot da exprim{ri echivalente privind adresa unui element oarecare al unui tablou: dac{
tab este un tablou cu elemente de tip int, atunci construc#ia &tab[ i] este echivalent{ cu tab+i. Este
evident c{ expresia &tab[ 0] == tab este adev{rat{.
se pot realiza exprim{ri echivalente privind elementele tabloului: dac{
tab este tabloul de mai sus, atunci tab[ i] este echivalent cu *(tab+i). La parcurgerea unui tablou,
utilizarea pointerilor poate fi mai rapid{ dec|t indexarea. Urm{toarele secven#e determin{ lungimea
unui ~ir de caractere.
Secven#a:
... int k; char sir[ 50] ;
... for (k=0; sir[ k] ; k++); printf(%d, k);
...
realizeaz{ aceea~i opera#ie ca secven#a:
... int k; char sir[ 50] , *ad=sir;
... for(k=0; *ad; ad++) k++; printf(%d,k); ....
Observa#i diferen#ele de implementare. Referitor la constantele ~ir de caractere, compilatorul C
aloc{ zona de memorie necesar{ ~i }nscrie codurile ASCII ale caracterelor ~i codul final \0.
Urm{toarele exprim{ri sunt corecte:
char *sir; ...; sir=Acesta este un sir;
char *sir=Al doilea sir;
char sir[ ] =Al treilea sir;
]n privin#a tablourilor multidimensionale trebuie remarcat c{ numele tabloului este un pointer de
tablouri, iar c|nd numele unui tablou apare f{r{ indexare ca operand }ntr-o expresie sizeof, el refer{
}ntregul tablou.
incrementarea pointerilor este echivalent{ cu accesarea elementelor unui tablou: dac{ consider{m
declara#ia
int *p; atunci opera#ia *(p+i) este echivalent{ cu srierea p[ i] .
Pentru alocarea memoriei din spa#iul HEAP, biblioteca de func#ii a compilatorului C ofer{ un se
subprograme. Prototipurile func#iilor de alocare/eliberare se afl{ }n fi~ierele alloc.h ~i stdlib.h. Cele mai
folosite func#ii sunt: malloc() ~i free(). Func#ia care realizeaz{ alocarea unei zone de memorie ar
prototipul:
void *malloc(unsigned nr_bytes);
unde nr_bytes reprezint{ dimensiunea }n octe#i a zonei solicitate. Dac{ alocarea a reu~it, func#ia }ntoarce
un pointer care con#ine adresa primului octet al zonei alocate. ]n caz contrar (spa#iul disponibil e
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
35 of 48 12/9/2007 7:21 PM
insuficient), rezultatul returnat este NULL (=0). Cum tipul rezultatului este void, trebuie utilizat
operatorul cast
pentru conversie de tip la atribuire, iar pentru precizarea dimensiunii zonei solicitate se poate utili
operatorul sizeof.
Eliberarea spa#iului alocat trebuie solicitat{ de c{tre programator. Acesta va utiliza func#ia cu prototipul:
void free(void *ptr);
unde parametrul ptr indic{ adresa de }nceput a zonei care trebuie eliberat{. Este obligatoriu ca ptr s{ fi fost
rezultatul unui apel al func#iei malloc.
Alte func#ii de alocare/eliberare disponibile }n implementarea Borland/Turbo C sunt: calloc(), corel
realloc(); farmalloc(); farcalloc(); farfree() etc.
3.6.2.2. Transferul parametrilor }n C.
]n limbajul C transferul implicit al parametrilor, }ntre subprograme, este prin valoare. Dac{ dorim ca
func#ie s{ modifice o variabil{ parametru formal, trebuie s{ transmitem func#iei adresa variabilei, ia
interiorul func#iei s{ folosim operatorul *. Func#ia schimba () din exemplul urm{tor inverseaz{ valorile
dou{ variabile av|nd tipul TIP. Pentru a schimba efectiv, func#ia are nevoie de adresele celor dou{
variabile:
schimba(TIP *u, TIP *v) {
TIP t;
t=*u; *u=*v; *v=t;
}
Apelul functiei pentru a schimba con#inutul a dou{ loca#ii este:
...
TIP a,b;
...
schimba(&a, &b);
...
Transferul parametrilor prin referin#{ este permis }n limbajele Pascal ~i C++. Astfel }n limbaju
subprogramul schimba, se scrie:
procedure schimba(var x, y:TIP);
var t:TIP;
begin
t:=x; x:=y; y:=t
end;
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
36 of 48 12/9/2007 7:21 PM
Prin folosirea parametrilor formali referin#{, limbajul C++ permite realizarea transferului prin referin#{
de o manier{ apropiat{ limbajului Pascal. Secven#a de program C++ demonstrativ{ este:
void schimba(TIP &, TIP &);
void main (void) {
TIP u,v;
...
schimba(u,v);
...
}
void schimba(TIP &x, TIP &y){
TIP t;
t=x; x=y; y=t;
}
Relativ la transmiterea tablourilor }ntre unit{#i de program C, trebuie spus c{ este implementat transfer
prin referin#{ deoarece tablourile con#in, }n general, o cantitate mare de date. Pe de alt{ parte chiar
numele tabloului este echivalent cu adresa sa. Pentru tablourile multidimensionale, compilatorul treb
cunoasc{ modul de organizare a tabloului pentru ca elementele s{ poat{ fi referite indexat }ntr-o func#
Pentru un tablou multidimensional, este esen#ial ca func#ia s{ cunoasc{ toate dimensiunile tabloului ma
pu#in prima. Fie scrmat
func#ia care tip{re~te elementele unei matrice de numere }n virgul{ mobil{. Urm{torul cod C reprezin
solu#ia corect{ a problemei.
void scrmat(float (*a)[ ] , int m, int n){
int i,j;
for (i=0; i<m; i++) {
for (j=0; j<n; j++) printf(%f, ((float * ) a)[ i*n+j] );
printf(\n);
}
}
La apel (scrmat(p,5,7);) se transmite adresa matricei (p) interpretat{ de tip float (*)[ ] , adic{ pointer c{tre
un tablou. Pentru a ob#ine adresa elementului a[ i] [ j] se utilizeaz{ expresia a+(i*n+j)*sizeof(float).
3.6.2.3. Pointeri de func#ii
Variabilele pointer care con#in adresa de start a unei func#ii permit: transferul func#iei asociate
parametru, apelul func#iei prin intermediul pointer-ului.
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
37 of 48 12/9/2007 7:21 PM
]ntotdeauna, o declara#ie de forma:
tip_r (* pfct) (<l_param>);
introduce pfct ca pointer cu tipul de baz{ func#ie cu lista de parametrii l_param ~i cu rezultat tip_r.
Trebuie observat rolul parantezelor pentru a distinge }ntre un pointer de func#ie ~i o func#ie care
}ntoarce un pointer.
Declara#ia
tip_r * fct(...);
este prototipul unei func#ii care }ntoarce un pointer, }n timp ce prin declara#ia
tip_r (* fct) (...);
se introduce fct ca pointer c{tre o func#ie.
Urm{torul tabel indic{ diverse situa#ii }n care apar pointeri, tablouri, func#ii.
Expresia Semnifica#ia expresiei
(* x) x este un pointer
(* x)[ ] x este un pointer la un tablou
(* (* x[ ] ))
x este un pointer la un tablou de pointeri.
(* (* x)[ ]
)()
x este un pointer la un tablou de pointeri la
func#ii care }ntorc pointeri
int (*p)[ ] ;
p este un pointer la un tablou de }ntregi
int (**p)[ ]
;
p este un pointer la un pointer la un masiv de
}ntregi
int *(*p)[ ]
;
p este un pointer la un masiv de pointeri la
}ntregi
int * (*f)(); f este un pointer la o func#ie care }ntoarce un
pointer la un }ntreg.
Exemplu: (Utilizarea func#iei standard qsort ce implementeaz{ algoritmul Quick Sort pentru sortare intern{).
Func#ia qsort, are prototipul (descris }n fi~ierul stdlib.h):
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
38 of 48 12/9/2007 7:21 PM
void qsort (void *tab, int n, int m, int (* comp) (const void *, const void *));
unde tab este tabloul de sortat cu n elemente, fiecare element av|nd dimensiunea m. Func#ia de comparare
trebuie scris{ de utilizator, comp
fiind un pointer la aceast{ func#ie. Dup{ compararea a dou{ elemente, func#ia va }ntoarce: 0 dac{
elementele sunt egale, o valoare negativa dac{ primul element este mai mic dec|t al doilea ~i o valoare
pozitiv{ altfel. Sensul rela#iilor mai mic, mai mare, egal este abstract ~i trebuie specificat de programator
Fie func#iile:
int comp_int (const void *x, const void *y) {
return * ((int *)x) -*((int *)y);
}
int comp_str (const void *x, const void *y) {
return strcmp(x,y);
}
Urm{toarele secven#e de apel realizeaz{:
ordonarea cresc{toare a unui tablou cu 500 de numere }ntregi:
int vector[ 500] ;
qsort(vector, 100, sizeof(int), cmp_int);
ordonarea cresc{toare a unui tablou de 500 de ~iruri de caractere, fiecare put|nd avea maxim 65 de
octe#i:
char x[ 500] [ 65] ; qsort(x,100,65,cmp_str);
3.7. Fi~iere
Organizarea datelor, necesar{ pentru prelucrarea acestora, presupune realizarea unor opera#ii
identificarea, clasificarea ~i descrierea atributelor caracteristice; gruparea datelor }n colec#ii; stoc
colec#iilor pe suporturi de date (}n general de tip magnetic); specificarea ~i implementarea procedu
prelucrare a datelor precum ~i alte proceduri (manuale sau automate) de }ntre#inere a suporturilo
informa#ii.
Structurile de date necesare prelucr{rii colec#iilor mari de date sunt at|t interne c|t ~i externe. Structura de
date de tip extern o reprezint{ fi~ierul. Un fi~ier este o mul#ime de date omogene ca interpretare ~
prelucrare. Din punct de vedere al sistemului de operare un fi~ier are anumite caracteristici (nume,
atribute, informa#ii pentru asigurarea accesului ~i a securit{#ii datelor). Intern, un fi~ier este o colec#ie de
articole (date de tip record - }n Pascal, struct
- }n C). Lungimea unui articol este dat{ de suma lungimii c|mpurilor componente. Dac{ toate articolele unui
fi~ier au aceea~i lungime spunem c{ fi~ierul are articole de lungime fix{, altfel fi~ierul este cu articole
lungime variabil{.
Implementarea fizic{ difer{ de la un limbaj de programare la altul. De asemenea difer{ ~i subprogramele
care permit realizarea opera#iilor asupra fi~ierelor. Limbajele Pascal ~i C permit definirea ~i prelucrarea
at|t a fi~ierelor cu articole de lungime fix{ c|t ~i a celor ce con#in articole de lungime variabil{. Pe suportul
extern, datele stocate sunt secven#e de octe#i. Numai }n momentul prelucr{rii, aceste succesiuni
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
39 of 48 12/9/2007 7:21 PM
interpreteaz{ adecvat, fiind posibil{ prelucrarea octet cu octet sau prelucrarea blocurilor de octe#i.
Pentru organizarea extern{, pe suport de date, sunt posibile mai multe metode: organizarea secven#i
(singura permis{ de limbajele Pascal ~i C), organizarea relativ{ ~i cea indexat{ (permise de limba
specializate, de exemplu COBOL).
Pozi#ia din care se cite~te, respectiv }n care se scrie, este dat{ de un indicator de articol (notat, }n
continuare, prin IA).
Accesul pentru scrierea datelor sau pentru citirea datelor stocate depinde de modul de organizare ale
Accesul secven#ial este posibil pentru orice mod de organizare, el presupune }nregistrarea articolelor
ordinea }n care devin disponibile ~i citirea articolelor }n ordinea }n care au fost }nscrise pe suport.
Pentru citirea }n acces secven#ial, este foarte important controlul identific{rii sf|r~itului fi~ierului. Dup
citirea ultimului articol (a ultimei linii sau a ultimului octet) indicatorul este pozi#ionat pe marcatorul d
sf|r~it de fi~ier (EOF - End Of File). Sesizarea sf|r~itului de fi~ier se face diferit }n func#ie de limbajul de
programare:
la citirea articolului (FORTRAN, COBOL); adic{ dup{ citirea ultimului articol, mai este necesar{ o
citire pentru a vedea dac{ s-a ajuns la sf|r~it.
independent de opera#ia de citire (Pascal, C, etc.), adic{ dac{ indicatorul IA este dup{ ultimul articol,
automat se consider{ sf|r~it de fi~ier; urm{toarea citire va produce eroare de intrare/ie~ire.
]n consecin#{, algoritmii de prelucrare depind de modul de sesizare a marcajului EOF. De regul{,
}ncercarea de citire din fi~ier dup{ ce s-a atins marcajul EOF este urmat{ de apari#ia unei erori.
Accesul direct este permis numai pentru fi~ierele cu o anumit{ organizare, entitatea de citire este articolu
sau blocul ~i sunt memorate pe discuri magnetice, CD sau VideoDisk (suporturi adresabile). Valoarea IA,
nu se calculeaz{ }n func#ie de valoarea sa anterioar{ (ca }n cazul accesului secven#ial) ci direct cu ajutoru
unei func#ii f cunoscute de sistem IA(k)=f(k). Sunt posibile dou{ moduri de acces direct: acces dup{ chei
acces dup{ num{rul articolului. ]n cazul accesului dup{ cheie (implementat de exemplu }n COBOL)
presupune c{ fiecare articol are un c|mp, numit cheie, care este folosit la }nregistrare/citire pentr
identificarea articolului. Pentru accesul relativ, implementat }n limbajele Pascal ~i C, articolul este localizat
prin num{rul s{u relativ. Articolul k are num{rul relativ k-1.
Asupra fi~ierelor se pot executa opera#ii de gestiune divizate pe dou{ niveluri: opera#ii globale (}ns
fi~ierului }ntr-un folder (catalog), deschiderea pentru consultare/actualizare a unui fi~ier, }nchiderea u
fi~ier, redenumirea, ~tergerea, copierea fi~ierelor, etc.) ~i opera#ii la nivel de articol (scriere sau citire de
articole).
]n programele Pascal, C, Java, ~. a. , opera#iile de intrare-ie~ire sunt realizate prin intermediul
subprograme (proceduri ~i func#ii }n Pascal, func#ii }n C, metode }n Java). Pentru unele opera#ii es
necesar{ utilizarea mai multor subprograme (de exemplu, }n Pascal, pentru opera#ia de deschidere s
necesare fie apelurile Assign+Reset, fie apelurile Assign+Rewrite.)
3.7.1. Fi~iere }n C
Bibliotecile standard C ofer{ o gam{ larg{ de func#ii care implementeaz{ opera#iile de intrare-ie~ire
orientate pe fi~iere. Dispozitivele periferice, ale sistemului de calcul, sunt v{zute tot ca fi~iere, da
identificatori predefini#i. Prototipurile func#iilor de bibliotec{ privind lucrul cu fi~iere sunt cuprinse
fi~ierul antet stdio.h. Se pot distinge 3 categorii: sistemul de intrare-ie~ire standard ANSI C; sist
intrare-ie~ire compatibil UNIX ~i, func#ii specifice implement{rii mediului de dezvoltare, neprev{z
standardul limbajului. ]n cele ce urmeaz{ ne vom ocupa de prima categorie. Celelalte categorii se pot studia
folosind manualul on-line sau manualul firmei produc{toare a mediului de dezvoltare.
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
40 of 48 12/9/2007 7:21 PM
Conceptul de baz{ relativ la opera#iile de intrare-ie~ire standard este cel de pointer la fi~ier. Mai precis, }n
fi~ierul stdio.h este definit un tip de structur{, numite FILE. Din punct de vedere intern, fi~ierele prezente
}n func#iile de intrare-ie~ire sunt specificate prin variabile de tip FILE *.
Declararea unui pointer la fi~ier se realizeaz{ prin scrierea
FILE * <identificator>;
Prin opera#ia de deschidere, se aloc{ o zon{ de memorie care va con#ine: numele extern al fi~ierului, adresa
unei zone tampon util{ }n realizarea transferurilor ~i informa#ii utile privind starea opera#iilor
intrare-ie~ire. Aceast{ conexiune logic{ rezultat{ }n urma deschiderii unui fi~ier se nume~te stream (sau
flux de date). Eliberarea zonelor alocate se realizeaz{ }n urma opera#iei de }nchidere.
Dispozitivele de intrare-ie~ire standard au asociate permanent c|te un asemenea pointer al c{rui nu
predefinit: stdin (conola pentru intrare), stdout (consola pentru ie~ire), stderr (consola pentru ie~ire),
stdaux (pentru primul port al interfe#ei seriale ), stdprn (pentru primul port al interfe#ei paralele); ultimi
doi identificatori fiind caracteristici implement{rii BORLAND pentru calculatoare compatibile IBM
Microsoft.
De asemenea, }n fi~ierul stdio.h, mai sus definite constantele FILENAME_MAX (pentru a indica lungimea
maxim{ a numelui unui fi~ier, din punct de vedere extern) ~i FOPEN_MAX (care precizeaz{ num{rul
maxim de fi~iere ce pot fi deschise simultan).
Se disting dou{ categorii de tipuri de transfer:
un stream de tip text care transfer{ secven#e de caractere organizate }n linii; }n C separarea liniilor
se face prin caracterul LF. Pentru adaptarea la dispozitivul fizic poate fi necesar{ }nlocuirea
caracterului LF cu secventa CR-LF.
un stream binar care transfer{ o secven#{ de octe#i f{r{ alte prelucr{ri.
Distingerea }ntre cele dou{ categorii nu este obligatorie; programatorul este cel care trebuie s{ rez
eventualele probleme de conversie a datelor.
Deschiderea fi~ierelor se realizeaz{ folosind func#ia fopen care returneaz{, c|nd toate condi#iile de
prelucrare sunt }ndeplinite, un pointer c{tre structura FILE. Este unica modalitate prin care se atribuie
corect o valoare unui pointer la fi~ier. Prototipul func#iei fopen este:
FILE * fopen(const char * nume_fis, const char * mod_acces);
unde nume_fis
este un ~ir de caractere (constant{ sau ob#inut prin atribuire) care specific{ numele extern al fi~ierului, iar
mod_acces
este un ~ir de caracter (constituit similar) care descrie modul de acces. ]n cazul unei opera#ii de desch
corecte, pointerul returnat de apel este diferit de NULL, }n caz contrar rezultatul apelului este NULL.
Modurile posibile de acces sunt:
deschidere flux de tip text (r sau rt), respectiv flux binar (rb) pentru citire (mod
reset);
deschidere flux de tip text (w sau wt), respectiv flux binar (wb) pentru scriere (cu distrugerea
fi~ierului anterior, dac{ acesta exista- mod
rewrite);
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
41 of 48 12/9/2007 7:21 PM
deschidere flux de tip text (a sau at), respectiv flux binar (ab) pentru ad{ugare la sf|r~it (mod
append);
deschidere flux de tip text (r+ sau r+t), respectiv flux binar (r+b) pentru actualizare (citire ~i
scriere folosind acela~i pointer la fi~ier);
deschidere flux de tip text (w+ sau w+t), respectiv flux binar (w+b) pentru actualizare (dac{
fi~ierul exista anterior, con#inutul s{u se pierde);
deschidere flux de tip text (a+ sau a+t), respectiv flux binar (a+b) pentru actualizare cu scriere
la sf{r~itul fi~ierului.
]nchiderea fi~ierelor se realizeaz{ apel|nd func#ia fclose definit{ astfel:
int fclose(FILE * <identificator>);
care }ntoarce EOF }n caz de eroare sau 0 }n caz normal. Prin }nchidere }nceteaz{ conexiunea logic{ d
pointer ~i fi~ier cu scrierea datelor din zona tampon de ie~ire (}n cazul deschiderii pentru
scriere/actualizare), respectiv cu pierderea datelor din zona tampon de intrare (}n cazul desc
citire/actualizare).
Detectarea sf|r~itului de fi~ier se realizeaz{ prin utilizarea macrodefini#iei feof cu prototipul:
int feof(FILE * <identificator>);
al c{rei rezultat este nenul (s-a detectat EOF) respectiv zero (nu s-a detectat EOF).
Exemplul 3.7.4 (Copierea unui fi~ier de tip text f1.txt }n fi~ierul text f2.txt).
#include <stdio.h>
int main(void) {
FILE *sursa, *dest;
if ((sursa=fopen(f1.txt, rt)) == NULL) {
fprintf(stderr,Nu se poate deschide f1.txt !);
return 1;
}
if ((dest=fopen(f2.txt,wt)) == NULL) {
fprintf(stderr, Nu se poate deschide f2.txt!);
return 2;
}
while (!feof(sursa)) fputc(fgetc(sursa),dest);
fclose(sursa);
fclose(dest);
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
42 of 48 12/9/2007 7:21 PM
return 0;
}
Asocierea unui nou fi~ier la un flux deschis deja se realizeaz{ folosind func#ia freopen cu prototipul:
FILE * freopen(const char * <id_fis_extern>, const char * <mod_acces>, FILE * p_fis);
unde p_fis este identificatorul fluxului existent care se va }nchide }n urma apelului ~i se va deschide fi~ierul
cu numele <id_fis_extern> }n modul de prelucrare <mod_acces> atribuind pointerul la structura creat{
variabilei p_fis. Func#ia returneaz{ valoarea atribuit{ lui p_fis.
For#area scrierii zonelor tampon asociate fi~ierelor deschise pentru scriere se realizeaz{ folosind func#ia
fflush cu prototipul:
int fflush(FILE * <id_fis>);
care returneaz{ EOF }n caz de eroare, respectiv 0 }n cazul normal.
Multe aplica#ii necesit{ lucrul cu fi~iere temporare care s{ fie ~terse automat la }nchidere sau la terminarea
normal{ a programului. ]n sprijinul programatorului, pentru a }nlesni astfel de activit{#i, biblioteca C ofer{
o func#ie cu prototipul: FILE *tmpfile(void);
care la apel creeaz{ un fi~ier temporar }n modul wb+. Func#ia }ntoarce un pointer la acel fi~ier. A
succesive vor deschide fi~iere distincte.
Alte opera#ii la nivel de fi~ier sunt:
~tergerea unui fi~ier - folosind func#ia
int remove(const char * nume_fis);
schimbarea numelui - folosind func#ia
int rename(const char *f_nou, const char *f_vechi);
Ambele func#ii }ntorc o valoare nenul{ }n caz de eroare ~i zero }n cazul normal.
Opera#iile de transfer se realizeaz{ folosind urm{toarele func#ii clasificate }n func#ie de tipul fluxului (text,
respectiv binar) ~i de tipul opera#iei (scriere, respectiv citire).
I. Flux de tip text
a) Scriere cu format. Se pot folosi urm{toarele func#ii: fprintf, printf, sprintf, vfprintf, vprintf, vsprinf. Ne
vom referi numai la func#iile fprintf ~i printf.
Func#ia fprintf este o func#ie cu num{r variabil de parametrii av|nd prototipul:
int fprintf(FILE *fp, const char *format, ...);
unde fp se refer{ la fluxul de date deschis }n vederea realiz{rii transferului, iar format respect{
specifica#iile descrise }n sec#iunea 4.4.2.
Func#ia printf a fost descris{ }n sec#iunea amintit{ anterior ~i este echivalent{ cu fprintf(stdout,format,
...).
b) Citire cu format.
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
43 of 48 12/9/2007 7:21 PM
Se pot folosi urm{toarele func#ii:fscanf, scanf, sscanf. Vom utiliza numai func#iile fscanf ~i scanf. Func#ia
fscanf este o func#ie cu num{r variabil de argumente ~i are prototipul:
int fscanf(FILE *fp, const char *format, ...);
Parametrii apelului au acelea~i semnifica#ii ca mai sus, iar func#ia scanf este echivalent{ cu scanf(stdin,
format, list{_adrese).
c) Citire de caractere din fi~iere text.
Se pot utiliza func#ia fgetc ~i macrodefini#ia getc. Func#ia cu prototipul int fgetc(FILE *fp); }ntoarce
urm{torul caracter din fp ca un }ntreg f{r{ semn, convertit la int sau EOF dac{ s-a detectat sf|r~itul de
fi~ier sau a ap{rut o eroare. Macrodefini#ia cu prototipul int getc(FILE *fp); este echivalent{ cu func#ia
fgetc. Reamintim posibilitatea utiliz{rii apelului getchar() echivalent cu getc(stdin).
d) Scriere de caractere }n fi~iere text. Scrierea unui caracter c }ntr-un fi~ier text cu identificatorul intern
fp se realizeaz{ folosind func#ia cu prototipul:
int fputc(int c, FILE *fp);
care returneaz{ c
}n cazul succesului, respectiv EOF }n caz de e~ec. Se poate utiliza ~i macroinstruc#iunea cu prototipul int
putc(int c, FILE *fp); similar{ cu fputc, iar apelul putchar(c); este echivalent cu putc(c, stdout);.
e) Citirea unui ~ir de caractere din fi~iere text se realizeaz{ folosind func#ia cu prototipul:
char *fgets(char *s, int n, FILE *fp);
la al c{rei apel se citesc, }n s, cel mult n-1 caractere din fi~ierul fp la care se adaug{ caracterul \0 ~i se
returneaz{ s sau NULL }n caz unei erori sau la }nt|lnirea codului EOF.
Reamintim utilizarea func#iei cu prototipul:
char *gets(char *s);
care cite~te urm{toarea linie de la consol{ ~i o depune }n s.
f) Scrierea unui ~ir de caractere }ntr-un fi~ier text se realizeaz{ }n urma apelului func#iei cu prototipul:
int fputs(const char *s, FILE *fp);
care }ntoarce EOF }n caz de eroare, respectiv num{rul de caractere transferate }n caz de succes. Pentr
scriere la consol{ se utilizeaz{ func#ia:
int puts(const char *s);
II. Flux binar
]n aceast{ categorie intr{ func#iile de intrare/ie~ire }n acces direct care citesc/scriu din/}n fi~iere f{r{ nici o
conversie ~i f{r{ a se face vreo interpretare a datelor. No#iunea fundamental{ este cea de zon{ compact{
octe#i (}nregistrare) care se cite~te sau se scrie. Citirea/scrierea se face de la / la pozi#ia curent{ din fi~ier,
care poate fi modificat{ cu func#ii speciale dup{ cum vom vedea mai jos. Dup{ executarea opera#iei, pozi#ia
indicatorului (de octet }n cazul limbajului C) este actualizat{ automat, pentru a indica urm{toar
}nregistrare. Citirea a nrec }nregistr{ri din fi~ierul cu identificatorul fp, fiecare av|nd lungimea L, cu
stocare }n tabloul ptr se realizeaz{ folosind apelul:
n = fread(ptr, L, nrec, fp);
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
44 of 48 12/9/2007 7:21 PM
care }ntoarce un }ntreg n
ce furnizeaz{ num{rul de }nregistr{ri citite. Dac{ s-a }nt|lnit EOF sau eroare atunci n va fi 0.
Pentru scrierea a nrec }nregistr{ri de lungime L fiecare, din zona cu adresa ptr }n fi~ierul cu identificatorul
intern fp se folose~te apelul:
m = fwrite(ptr, L, nrec, fp);
unde m va reprezenta num{rul de }nregistr{ri scrise, cu m < nrec numai }n caz de eroare.
Pentru a avea acces la orice zon{ a fi~ierului, biblioteca C ofer{ un set de func#ii care permit:
citirea valorii indicatorului de pozi#ie. Func#ia
fgetpos }nscrie valoarea indicatorului }n variabila poz ~i }ntoarce 0 }n caz de succes. Prototipul
func#iei este:
int fgetpos(FILE *fp, long int *poz);
Func#ia ftell
}ntoarce pozi#ia curent{ }n fi~ier }n caz de succes ~i -1L }n caz de e~ec. Aceasta are prototipul:
long int ftell(FILE * fp);
modificarea valorii indicatorului de pozi#ie. Sunt disponibile func#iile: fsetpos, fseek ~i rewind.
Func#ia
fsetpos are prototipul:
int fsetpos(FILE *fp, const long int *poz);
~i atribuie indicatorului valoarea variabilei poz ~i }ntoarce 0 }n caz de succes.
Func#ia fseek face o deplasare a indicatorului de pozi#ie cu nr_octe#i relativ la o pozi#ie de referin#{
specificat{ prin constanta }ntreag{ origine. Se pot utiliza urm{toarele valori: 0 = SEEK_SET (}nceput de
fi~ier), 1=SEEK_CUR (pozi#ie curent{), 2 = SEEK_END (sf|r~it de fi~ier). Valoarea }ntoars{ de fseek este
0 pentru succes ~i nenul{ }n caz de e~ec. Prototipul func#iei fseek este:
int fseek(FILE *fp, long nr_octe#i, int origine);
Folosind func#ia rewind are loc pozi#ionarea la }nceputul fi~ierului. Prototipul func#iei rewind este:
void rewind(FILE *fp);
Pentru a ob#ine informa#ii despre un fi~ier se pot utiliza func#iile stat ~i fstat cu prototipul declarat }n
fi~ierul stat.h din catalogul sys. Ne vom referi la func#ia stat. Aceasta are prototipul:
int stat (char *cale, struct stat * statzona);
unde: cale reprezint{ numele fi~ierului sau catalogului, iar statzona este adresa unei structuri de tip stat
ale c{rei c|mpuri descriu starea entit{#ii }n discu#ie. De exemplu, c|mpul st_size furnizeaz{ dimensiunea
unui fi~ier, }n octe#i.
Exemplul 3.7.5.
(Aflarea dimensiunii unui fi~ier folosind func#iile de citire-modificare a indicatorului de pozi#ie).
#include <stdio.h>
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
45 of 48 12/9/2007 7:21 PM
long filesize(FILE *fp);
int main(void){
FILE *f;
f=fopen(F_test.txt,w+);
fprintf(f, Aflarea dimensiunii unui fisier folosind functiile\n);
fprintf(f, de citire-modificare a indicatorului de pozitie.\n);
printf(%ld,filesize(f));
return 0;
}
long filesize(FILE *fp){
long cp, lung;
cp = ftell(fp);
fseek(fp, 0L, SEEK_END);
lung=ftell(fp);
fseek(fp, cp, SEEK_SET);
return lung;
}
Exemplul 3.7.6. (Metode de sortare a datelor stocate }n fi~iere). Sortarea datelor stocate }ntr-un fi~ier se
poate realiza cu aducerea integral{ a datelor }n memoria volatil{ (sortare intern{) sau cu aducerea }
memoria principal{ a c|te unui articol (sortare extern{). Metodele prezentate aici nu sunt din cele
performante, ele ilustreaz{ accesul la datele stocate }n fi~iere ~i principalele modalit{#i de prelucrare. O alt{
metod{ de sortare a datelor externe utilizeaz{ procedeul interclas{rii colec#iilor ordonate. Principiul a
metode va fi explicat }n contextul rezolv{rii problemelor prin metoda divide et impera.
a) Sortarea intern{.
Metoda se poate aplica numai fi~ierelor de dimensiune redus{ (ca num{r de articole sau ca lungim
articolelor). Se pot descrie mai multe solu#ii posibile:
Stocarea integral{ a datelor }n memoria principal{. Se va utiliza un vector de articole, compararea
fiind realizat{ prin intermediul cheii de sortare. Pentru sortare intern{ se poate utiliza oricare dintre
metodele cunoscute. ]n final vectorul sortat se }nregistreaz{ }n fi~ierul redeschis pentru scriere.
Con#inutul vechi va fi automat distrus.
Sortare cu manipularea cheii de sortare ~i a pozi#iei articolului }n fi~ier (indexul articolului). Aceast{
metod{ presupune memorarea }ntr-un vector numai a valorii cheii de sortare, }mpreun{ cu num{rul
relativ al articolului fi~ierul de sortat. Compara#iile asupra valorilor cheii de sortare vor conduce la
interschimb{ri }n vectorul intern, Ob#inerea fi~ierului sortat se va face prin parcurgerea }n acces
secven#ial a fi~ierului ini#ial ~i scrierea articolelor, }n ordine, }n fi~ierul rezultat. Programul care
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
46 of 48 12/9/2007 7:21 PM
urmeaz{ ilustreaz{ aceast{ strategie.
#include <stdio.h>
typedef struct {char nume[ 20] ; float media;} articol;
FILE *fin, *fout;
float x[ 300] ; int index[ 300] ;
long filesize(FILE *fp);
/* se include definitia de la exemplul 4.7.5 */
void main (void){
long i,j,n,itemp; float xtemp; articol a;
fin=fopen(f1.dat,rb); fout=fopen(f2.dat,wb);
n=filesize(fin)/sizeof(articol);
for (i=0; i<n; i++){
fread(&a,sizeof(articol),1,fin); x[ i] =a.media;index[ i] =i;
}
for (i=0; i<n-1; i++)
for (j=i+1; j<n; j++)
if (x[ i] >x[ j] ) {
itemp=index[ i] ; index[ i] =index[ j] ; index[ j] =itemp;
xtemp=x[ i] ; x[ i] =x[ j] ; x[ j] =xtemp; }
for (i=0; i<n; i++) {
fseek(fin,index[ i] *sizeof(articol),SEEK_SET);
fread(&a, sizeof(articol), 1, fin);
fwrite(&a, sizeof(articol), 1, fout);
}
fclose(fin); fclose(fout);
}
b) Sortare extern{.
Aceast{ abordare este caracteristic{ fi~ierelor de dimensiune mare, pentru care nu se poate aplica o metod
de tip a2. Opera#iile trebuie realizate direct }n fi~ier. Ilustr{m utilizarea func#iilor fseek, fread ~i fwrite
}n implementarea metodelor de sortare prin interschimbare ~i prin selec#ie. Se utilizeaz{ elementele
descrise }n cadrul programului a2.
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
47 of 48 12/9/2007 7:21 PM
sortare prin interschimbare:
FILE *fp; int ok; long i, n; articol a[ 2] ;

fp=fopen(fis.dat,r+b);
n= filesize(fp)/sizeof(articol);
do {ok=0;
for(i=0; i<n-1; i++) {
fseek(fp, i*sizeof(articol), SEEK_SET);
fread(a, sizeof(articol), 2,fp);
if (a[ 0] .media > a[ 1] .media) {
fseek(fp, i*sizeof(articol), SEEK_SET);
fwrite(a+1, sizeof(articol),1,fp);
fwrite(a,sizeof(articol),1,fp);
ok = 1;
}
}while (ok);

sortare prin selec#ie:

FILE *fp; long i,j, n; articol a, b;

fp=fopen(fis.dat,r+b); n= filesize(fp)/sizeof(articol);
for(i=0; i<n-1; i++) {
fseek(fp, i*sizeof(articol),SEEK_SET);
fread(&a, sizeof(articol), 1, fp);
for(j=i+1; j<n; j++) {
fseek(fp, j*sizeof(articol), SEEK_SET);
fread(&b, sizeof(articol),1,fp);
if (a.media>b.media) {
Limbaje de programare - C Autor: Prof. Univ. Dr. Grigore Albeanu file:///C:/ACTIV/Proc/FINAL/C4.HTM
48 of 48 12/9/2007 7:21 PM
fseek(fp, i*sizeof(articol), SEEK_SET);
fwrite(&b, sizeof(articol), 1, fp);
fseek(fp, j*sizeof(articol), SEEK_SET);
fwrite(&a, sizeof(articol), 1, fp);
a=b;}
}}

Vreau sa merg la inceputul capitolului


Vreau sa vad Cuprinsul documentului.
Versiune prescurtata a capitolulul 4 din: G. Albeanu, Algoritmi si limbaje de programare. Editura "Fundatiei
Romnia de Mine", 2000
Bazele Informaticii: Bibliografie suplimentara file:///C:/ACTIV/Proc/FINAL/BIB.HTM
1 of 2 12/9/2007 7:22 PM
Bibliografie suplimentara
Aho A. V., Hopcroft J. R., J. D. Ullman, The Design and Analysis of Computer Algorithms, Addison-Wesley Comp,
1975.
1.
Albeanu G., Algoritmi si limbaje de programare. Editura Fundatiei "Romnia de Mine", 2000 2.
Albeanu G., Programarea in Pascal si Turbo Pascal. Culegere de probleme. Editura Tehnic, 1994. 3.
Albeanu G., Sisteme de operare, Editura Petrion, 1996. 4.
Blnescu T., Corectitudinea algoritmilor, Editura Tehnic, Bucuresti, 1995. 5.
Barbu Gh., Vduva I., M. Bolosteanu, Bazele Informaticii, Editura Tehnic, 1995. 6.
Bohm C., G. Jacopini, Flow-diagrams, Turing Machines and languages with only two formation rules. Comm. ACM.,
9, 1966, 366-371.
7.
Calude C., Complexitatea calculului. Aspecte calitative. Editura stiintific si Enciclopedic, Bucuresti, 1982. 8.
Dahl, O.J., Dijkstra E. W., C. A. R. Hoare, Structured programming, Academic Press, London, 1972. 9.
Enescu Gh., Logica simbolic, Editura stiintific, Bucuresti, 1971. 10.
Flanagan D., Java in a Nutshell: A Desktop Quick Reference for Java Programmers, O Reilly & Associates, INC. 11.
Hoare C. A. R. s.a., Laws of Programming, Comm. ACM., 30(8), 1987, 672-685. 12.
Ichim I., Gh. Marinescu, Metode de aproximare numeric, Editura Academiei RSR, 1986. 13.
Isaacson E., H. B. Keller, Analysis of Numerical Methods, Wiley, 1966. 14.
Kerninghan B. W., D. M. Ritchie, The C Programming Language, Englewood Cliffs, Prentice Hall, 1978, 1988. 15.
Knuth D., The art of computer programming, Vol. 1, Fundamental Algorithms, 3rd ed., Addison Wesley Longman,
1997; Arta Programrii Calculatoarelor. Vol. 1, Algoritmi Fundamentali, Teora, 1999.
16.
Knuth D., The Art of Computer Programming. Seminumerical Algorithms, Vol. 2, 1981; Tratat de programare a
calculatoarelor. Algoritmi seminumerici, Editura Tehnic, 1983.
17.
Knuth, Moris, Pratt, Fast pattern matching in strings, SIAM Journal on Computing, 6, 2, 1975. 18.
Livovschi L., H. Georgescu, Sinteza si analiza algoritmilor. Editura Stiintific si Enciclopedic, 1986. 19.
Mateescu E., I. Maxim, Arbori, Editura Tara fagilor, 1996. 20.
Niculescu R., Albeanu G., V. Domocos, Programarea calculatoarelor. Probleme rezolvate in limbajul Pascal, Editura
Tempus, 1992.
21.
Novikov P.S., Elemente de logic matematic, Editura Stiintific, Bucuresti, 1966. 22.
Pan V., Strassen's algorithm is not optimal, Proc. 19th Annual Symposium on the Foundations of Computer Science,
1978.
23.
Plya G., Cum rezolvm o problem? Editura Stiintific, Bucuresti, 1965. 24.
Popovici C., Georgescu H, L. State. Bazele Informaticii I, Tipografia Universittii Bucuresti, 1990. 25.
Popovici C., Rudeanu S., H. Georgescu, Bazele Informaticii II, Tipografia Universittii, 1992. 26.
Rudeanu S., Latici si algebre booleene, Tipografia Universittii Bucuresti, 1982. 27.
Bazele Informaticii: Bibliografie suplimentara file:///C:/ACTIV/Proc/FINAL/BIB.HTM
2 of 2 12/9/2007 7:22 PM
State L., Elemente de logic matematic si demonstrarea automat a teoremelor. Tipografia Universittii Bucuresti,
1989.
28.
Strassen V., Gaussian elimination is not optimal, Numeriche mathematik, 13, 1969, 354-356. 29.
Vduva I., Modele de simulare cu calculatorul. Editura Tehnic, 1975. 30.
Vduva I., Sisteme Informatice, Tipografia Universittii Bucuresti, 1981. 31.
Wirth N., Systematic Programming. An Introduction, Prentice Hall, 1972. 32.
Wirth N., Algorithms + Data Structures = Programs, Prentice Hall, 1976. 33.
Wirth N., The programming development by stepwise refinement, Comm. ACM., 14 , 1971, 221-225. 34.
Wirth N., Modula: A language for modular programming, Software Practice and Experience, 7, 1977, 3-35. 35.
Waite M., R. Lafore, Data Structures & Algorithms in Java, Waite Group Press, 1998; Structuri de date si algoritmi in
Java, Teora, 1999.
36.
Winograd S., On the multiplication of 2x2 matrices, IBM Research Report 267, 1970. 37.
Vreau sa vad inceputul listei
Vreau sa vad Cuprinsul.
Data ultimei actualizari: 26 Februarie 2002
Se consider programul:
#include <stdio.h>
void main(void){
int n, a;
printf("a = "); scanf("%d", &a);
printf("n = "); scanf("%d", &n);
printf("a = (a>>n)<<n are rezultatul : %d",
a = (a>>n)<<n
);
}
1
5 min
Ce se afieaz pentru:
i) a = 7, n = 2;
ii) a = 8, n = 2;
iii) a = 8, n = 4;
Se consider programul:
#include <stdio.h>
int a, b; float x;
int f(int c){
int a; /* linia T */
a = 7; b = 3; return a+b+c;
}
void main(void){
a = 1; b= 2; x = f(a)/10;
printf("%3d %3d", a, b); printf(" %5.1f", x);
}
2
5 min
Ce va afia, dac:
a) lipsete linia T
b) nu lipsete linia T
3
Se consider programul:
#include <stdio.h>
int suma(int max){ int i; static int s = 0;
for (i=s; i<max; i++) s+=i;
return s;
}
void main(void){ int j, n= 5;
for (j=0; j<n; j++) printf("%3d",suma(j));
}
5 min
Ce afieaz ?
4
Se consider programul:
#include <stdio.h>
void main(void){
int t[4]={0, 1, 2, 3}; int *p = &t[1];
printf("%d\n", *p++);
printf("%d\n", *++p);
printf("%d\n", ++*p);
}
5 min
Ce afieaz ?
5
Se consider programul:
#include <stdio.h>
int a[5] = {0, 1, 2, 3, 4};
int i = 4; int j =2;
void main(void){
printf("\n%d", a[i]);
printf("\n%d", i[a]);
}
3 min
Ce afieaz?
a) 4, 4
b) 4, 0
c) Construcia i[a] nu este corect.
6
Declaraia
char *x[];
l definete pe x ca:
a) pointer ctre tablouri de tip char;
b) tablou de pointeri ctre elemente de tip
char
c) a i b
1 min
7
Ce afieaz secvena de program ?
#include <stdio.h>
void main(void){
putchar (getchar()-'A'+'a');
putchar('\n');
}
dac se introduce:
i) A
ii) G
iii) X
2 min
Se consider programul:
#include <stdio.h>
char i = 0x63;
signed char j = 9, k;
void main(void){
printf(" i = %d \n", i = i & 0x5f);
printf(" j = %d \n", ~j);
printf(" k = %d \n", k = j | 0x30);
}
8
6 min
Ce valori vor avea variabilele i , j i
k dup executarea acestuia?
Interpretai rezultatul.
Fie programul:
#include <stdio.h>
unsigned f(unsigned n){
unsigned i, p;
for (p = 1, i = 1; i<=n; i++) p *= i;
return p;
}
void main(void){
for (int n = 0; n<=20; n++) printf("%d \n", f(n));
}
9
4 min
Exista numere naturale n pentru care
programul nu afieaz rezultatul
corect ? Argumentai !
10
Fie programul:
char *dup2(const char *str){
static char p[1000];
int n, k; for(n=0; str[n]!='\0';n++);
for(k=0; k<n; k++){ p[2*k]=str[k]; p[2*k+1] = str[k]; }
p[2*n]='\0';
return p;
}
int main(int argc, char *argv[]){
char *p1, *p2;
if(argc != 3){printf("Utilizai: %s sir1 sir2\n", argv[0]);
return 0;
}
p1=dup2(argv[1]);puts(p1); p2=dup2(argv[2]);puts(p2);
puts(p1); puts(p2);
return 1;
}
9 min
Studiai comportamentul programului i simulai executarea
acestuia. Precizai intrrile i ieirile programului.

You might also like