Sunteți pe pagina 1din 145

1

Manual de Informatic pentru licen 2012,



Specializarea Informatic

Tematica general:

Partea 1.Algoritmi i specificri. Clase de algoritmi.

a. Cautari (secventiala si binara), sortari (selectie, bubblesort, quicksort), metodele
backtracking si divide et impera. (Sect. 1.1)
b. Algoritmi i specificri. Scrierea unui algoritm pornind de la o specificatie data;
recunoasterea algoritmului intr-un program dat. Se da un algoritm; se cere
specificarea lui si / sau rezultatul executiei si / sau corectarea lui in conformitate cu
specificatia. (Sect. 1.2)

Partea 2. Programare orientat pe obiecte

a. Concepte OOP n limbaje de programare (C++, Java, C#): Clase i obiecte, Membrii
unei clase i specificatorii de acces, Constructori i destructori, Clase derivate i
relaia de motenire, Suprascrierea metodelor, Polimorfism, Legare dinamica, Clase
abstracte i interfee(Sect. 2.1)
b. Diagrame de clase si de interactiune intre obiecte n UML: Pachete, Clase si interfete,
Relatii intre clase si interfete, Obiecte, Mesaje(Sect. 2.2)

Partea 3. Structuri de date

a. Cozi, Stive, Liste, Arbori (binari). Specificarea operaiilor caracteristice (fr
implementri) (Sect. 3.1).
b. Identificarea structurilor i tipurilor de date potrivite pentru rezolvarea problemelor
(doar dintre cele de la punctul a.) (Sect. 3.2)

Partea 4. Baze de date

a. Baze de date relaionale. Primele trei forme normale ale unei relaii(Sect. 4.1)
b. Gestiunea bazelor de date relaionale cu SQL (Create table, Drop table, Alter table,
Insert, Update, Delete) (Sect. 4.2)
c. Interogarea bazelor de date cu operatori din algebra relaional(Sect. 4.3)
d. Interogarea bazelor de date relaionale cu SQL (Select) (Sect. 4.4)

Partea 5. Sisteme de operare

a. Structura i funciile sistemelor de operare(Sect. 5.1)
b. Sisteme de fiiere: structura ierarhic, legturi, studiul de caz Unix (Linux) (Sect. 5.2)
c. Procese Unix: creare, funciile fork, exec, exit, wait; comunicare prin pipe i
FIFO(Sect. 5.3)
d. Interpretoare ale fiierelor de comenzi, cu exemplificare sh (Unix) (Sect. 5.4)

2

Cuprins:

1. ALGORITMI I SPECIFICRI. CLASE DE ALGORITMI .................................... 4
1.1. CLASE DE ALGORITMI I METODE DE REZOLVARE ....................................................... 4
1.1.1. Cutri ............................................................................................................... 4
1.1.1.1. Cutare secvenial ........................................................................................ 4
1.1.1.2. Cutare binar ................................................................................................ 5
1.1.2. Sortri ................................................................................................................ 6
1.1.2.1. Sortare prin selecie........................................................................................ 7
1.1.2.2. Bubble sort ..................................................................................................... 7
1.1.2.3. Quicksort ........................................................................................................ 8
1.1.3. Metode clasice de rezolvare a problemelor ....................................................... 9
1.1.3.1. Metoda backtraking ....................................................................................... 9
1.1.3.2. Metoda "divide et impera" ........................................................................... 13
1.2. ALGORITMI I SPECIFICRI ........................................................................................ 15
1.2.1. Scrierea unui algoritm pornind de la o specificaie dat ................................ 15
1.2.2. Prezentai specificaia i / sau corectai .......................................................... 17
1.2.3. Ce face? ........................................................................................................... 18
1.2.4. Inspectai soluia .............................................................................................. 21
2. PROGRAMAREA ORIENTAT PE OBIECTE ...................................................... 25
2.1. CONCEPTE OOP N LIMBAJE DE PROGRAMARE .......................................................... 25
2.1.1. Noiunea de clas ............................................................................................. 25
2.1.1.1. Realizarea proteciei datelor prin metoda programrii modulare ................ 25
2.1.1.2. Tipuri abstracte de date ................................................................................ 26
2.1.1.3. Declararea claselor ....................................................................................... 27
2.1.1.4. Membrii unei clase. Pointerul this ............................................................... 28
2.1.1.5. Constructorul................................................................................................ 29
2.1.1.6. Destructorul.................................................................................................. 32
2.1.2. Metoda programrii orientate obiect .............................................................. 33
2.1.2.1. Bazele teoretice ............................................................................................ 34
2.1.2.2. Declararea claselor derivate ......................................................................... 34
2.1.2.3. Funcii virtuale ............................................................................................. 35
2.1.2.4. Clase abstracte ............................................................................................. 40
2.2. DIAGRAME DE CLASE I INTERACIUNI NTRE OBIECTE N UML ............................... 43
2.2.1. Diagrame de clase ........................................................................................... 46
2.2.2. Diagrame de interaciune ................................................................................ 53
2.2.3. Detalii despre subiecte propuse ....................................................................... 55
3. STRUCTURI DE DATE ............................................................................................... 57
3.1. COZI, STIVE, LISTE, ARBORI BINARI .......................................................................... 57
3.1.1. Liste .................................................................................................................. 57
3.1.2. Stiva.................................................................................................................. 61
3.1.3. Coada ............................................................................................................... 62
3.1.4. Arbori ............................................................................................................... 64
3.2. IDENTIFICAREA STRUCTURILOR DE DATE POTRIVITE N APLICAII ............................. 67
4. BAZE DE DATE ............................................................................................................ 72
3
4.1. BAZE DE DATE RELAIONALE .................................................................................... 72
4.1.1. Modelul relaional ........................................................................................... 72
4.1.2. Primele trei forme normale ale unei relai ..................................................... 74
4.2. GESTIUNEA BD RELAIONALE .................................................................................. 83
4.2.1. Atribute, legturi, operatii ............................................................................... 83
4.2.2. Gestiunea BD relaionale cu SQL.................................................................... 85
4.2.3. Interogri ale BD ............................................................................................. 88
4.3. INTEROGAREA BD CU OPERATORI DIN ALGEBRA RELAIONAL ............................... 89
4.4. INTEROGAREA BD RELAIONALE CU SQL ................................................................ 93
5. SISTEME DE OPERARE ............................................................................................. 99
5.1. STRUCTURA I FUNCIILE SO .................................................................................... 99
5.1.1. Strile unui proces i principalele funcii ale SO ............................................ 99
5.1.2. Structura general a unui SO .......................................................................... 101
5.1.2.1. Structura unui SO ....................................................................................... 101
5.1.2.2. Partea de control ........................................................................................ 102
5.1.2.3. Partea de servicii ........................................................................................ 103
5.2. SISTEME DE FIIERE ................................................................................................ 107
5.2.1. Probleme generale privind fiierele............................................................... 107
5.2.1.1. Operaii asupra fiierelor............................................................................ 107
5.2.1.2. Clasificri ale fiierelor .............................................................................. 109
5.2.2. Particulariti ale sistemului de fiiere Unix ................................................. 111
5.2.2.1. Tipuri de fiiere i sisteme de fiiere ......................................................... 111
5.2.2.2. Legturi hard i legturi simbolice ............................................................ 112
5.2.2.3. Principalele directoare ale unui system de fiiere Unix ............................. 115
5.3. PROCESE UNIX ........................................................................................................ 119
5.3.1. Principalele apeluri system de gestiune a proceselor ................................... 119
5.3.1.1. Crearea proceselor Unix. Apelul fork ........................................................ 119
5.3.1.2. Execuia unui program extern; apelurile exec ........................................... 121
5.3.1.3. Apelurile exit i wait .................................................................................. 122
5.3.2. Comunicarea ntre procese prin pipe ............................................................ 123
5.3.2.1. Conceptul de pipe ...................................................................................... 123
5.3.2.2. Exemplu: implementarea who | sort prin pipe i exec ............................... 124
5.3.3. Comunicarea ntre procese prin FIFO .......................................................... 125
5.3.3.1. Conceptul de FIFO ..................................................................................... 125
5.3.3.2. Exemplu: aplicare FIFO la comunicare client / server .............................. 127
5.4. INTERPRETOARE ALE FIIERELOR DE COMENZI ........................................................ 129
5.4.1. Funcionarea unui interpretor de comenzi shell ............................................ 129
5.4.2. Programarea n shell ..................................................................................... 130
5.4.2.1. Scurt prezentare a limbajului sh ............................................................... 130
5.4.2.2. Variabile sh i mecanisme de substituie ................................................... 132
5.4.2.3. Structura de control if din sh ...................................................................... 136
5.4.2.4. Structuri de control repetitive sh ................................................................ 137
5.4.2.5. Exemplul 1: o aplicaie de supraveghere ................................................... 139
5.4.2.6. Exemplul 2: utilizri break i continue ...................................................... 141
5.4.2.7. Exemplul 3: reunirea fiierelor tipribile ntr-unul singur ......................... 141
6. BIBLIOGRAFIE GENERAL .................................................................................. 144

4

1. Algoritmi i specificri. Clase de algoritmi

1.1. Clase de algoritmi i metode de rezolvare

1.1.1. Cutri

Datele se afl n memoria intern, ntr-un ir de articole. Vom cuta un articol dup un
cmp al acestuia pe care l vom considera cheie de cutare. n urma procesului de cutare va
rezulta poziia elementului cutat (dac acesta exist).
Notnd cu k
1
, k
2
, ...., k
n
cheile corespunztoare articolelor i cu a cheia pe care o cutm,
problema revine la a gsi (dac exist) poziia p cu proprietatea a = k
p
.
De obicei articolele sunt pstrate n ordinea cresctoare a cheilor, deci vom presupune c

k
1
< k
2
< .... < k
n
.

Uneori este util s aflm nu numai dac exist un articol cu cheia dorit ci i s gsim n caz
contrar locul n care ar trebui inserat un nou articol avnd cheia specificat, astfel nct s se
pstreze ordinea existent.
Deci problema cutrii are urmtoarea specificare:

Date a,n,(k
i
, i=1,n);
Precondiia: neN, n>1 i k
1
< k
2
< .... < k
n
;
Rezultate p;
Postcondiia: (p=1 i a s k
1
) sau (p=n+1 i a > k
n
) sau (1<psn) i (k
p-1
< a s k
p
).

1.1.1.1. Cutare secvenial

O prim metod este cutarea secvenial, n care sunt examinate succesiv toate cheile.
Sunt deosebite trei cazuri: ak
1
, a>k
n
, respectiv k
1
< a k
n
, cutarea avnd loc n al treilea caz.

Subalgoritmul CautSecv(a, n, K, p) este: {neN, n>1 i k
1
< k
2
< .... < k
n
}
{Se caut p astfel ca: (p=1 i a s k
1
) sau}
{ (p=n+1 i a>k
n
) sau (1<psn) i (k
p-1
< a s k
p
).
Fie p := 0; {Cazul "nc negasit"}
Dac a s k
1
atunci p := 1 altfel
Dac a > k
n
atunci p := n + 1 altfel
Pentru i := 2; n execut
Dac (p = 0) i (a s k
i
) atunci p := i sfdac
5
sfpentru
sfdac
sfdac
sf-CautSecv

Se observ c prin aceast metod se vor executa n cel mai nefavorabil caz n-1 comparri,
ntruct contorul i va lua toate valorile de la 2 la n. Cele n chei mpart axa real n n+1 intervale.
Tot attea comparri se vor efectua n n-1 din cele n+1 intervale n care se poate afla cheia
cutat, deci complexitatea medie are acelai ordin de mrime ca i complexitatea n cel mai ru
caz.
Evident c n multe situaii acest algoritm face calcule inutile. Atunci cnd a fost deja
gsit cheia dorit este inutil a parcurge ciclul pentru celelalte valori ale lui i. Cu alte cuvinte
este posibil s nlocuim ciclul PENTRU cu un ciclu CTTIMP. Ajungem la un al doilea
algoritm, dat n continuare.
Subalgoritmul CautSucc(a, n, K, p) este: {neN, n>1 i k
1
< k
2
< .... < k
n
}
{Se caut p astfel ca: p=1 i a s k
1
) sau }
{(p=n+1 i a>k
n
) sau (1<psn) i (k
p-1
< a s k
p
).
Fie p:=1;
Dac a>k
1
atunci
Cttimp psn i a>k
p
execut p:=p+1 sfct
sfdac
sf-CautSucc

n cel mai ru caz i acest algoritm face acelai numr de operaii ca i subalgoritmul
Cautsecv. n medie numrul operaiilor este jumtate din numrul mediu de operaii efecuat de
subalgoritmul Cautsecv deci complexitatea este aceeai.
Menionm, c acest tip de cutare se poate aplica i n cazul n care cheile nu sunt n
ordine cresctoare.

1.1.1.2. Cutare binar

O alt metod, numit cutare binar, care este mult mai eficient, utilizeaz tehnica
"divide et impera" privitor la date. Se determin n ce relaie se afl cheia articolului aflat n
mijlocul coleciei cu cheia de cutare. n urma acestei verificri cutarea se continu doar ntr-o
jumtate a coleciei. n acest mod, prin njumtiri succesive se micoreaz volumul coleciei
rmase pentru cutare. Cutarea binar se poate realiza practic prin apelul funciei
BinarySearch(a, n, K, 1, n), descris mai jos, folosit n subalgoritmul dat n continuare.

Subalgoritmul CautBin(a, n, K, p) este: {neN, n>1 i k
1
< k
2
< .... < k
n
}
{Se caut p astfel ca: (p=1 i a s k
1
) sau}
{(p=n+1 i a>k
n
) sau (1<psn) i (k
p-1
< a s k
p
)}
Dac a s k
1
atunci p := 1 altfel
Dac a > k
n
atunci p := n+1 altfel
P := BinarySearch(a, n, K, 1, n)
6
sfdac
sfdac
sf-CautBin


Funcia BinarySearch(a, n, K, St, Dr) este:
Dac St > Dr - 1
atunci BinarySearch := Dr
altfel m := (St+Dr) Div 2;
Dac a s k
m

atunci BinarySearch := BinarySearch(a, n, K, St, m)
altfel BinarySearch := BinarySearch(a, n, K, m, Dr)
sfdac
sfdac
sf-BinarySearch

n funcia BinarySearch descris mai sus, variabilele St i Dr reprezint capetele
intervalului de cutare, iar m reprezint mijlocul acestui interval. Prin aceast metod, ntr-o
colecie avnd n elemente, rezultatul cutrii se poate furniza dup cel mult log
2
n comparri.
Deci complexitatea n cel mai ru caz este direct proporional cu log
2
n. Fr a insista asupra
demonstraiei, menionm c ordinul de mrime al complexitii medii este acelai.
Se observ c funcia BinarySearch se apeleaz recursiv. Se poate nltura uor
recursivitatea, aa cum se poate vedea n urmtoarea funcie:

Funcia BinSeaNerec(a, n, K, St, Dr) este:
Cttimp Dr St > 1 execut
m := (St+Dr) Div 2;
Dac a s k
m
atunci Dr := m altfel St := m sfdac
sfct
BinSeaNerec := Dr
sf-BinSeaNerec

1.1.2. Sortri

Prin sortare intern vom nelege o rearanjare a unei colecii aflate n memoria intern
astfel nct cheile articolelor s fie ordonate cresctor (eventual descresctor).
Din punct de vedere al complexitii algoritmilor problema revine la ordonarea cheilor.
Deci specificarea problemei de sortare intern este urmtoarea:

Date n,K; {K=(k
1
,k
2
,...,k
n
)}
Precondiia: k
i
eR, i=1,n
Rezultate K';
Postcondiia: K' este o permutare a lui K, dar ordonat cresctor.
Deci k
1
s k
2
s ... s k
n
.

7
1.1.2.1. Sortare prin selecie

O prim tehnic numit "Selecie" se bazeaz pe urmtoarea idee: se determin poziia
elementului cu cheie de valoare minim (respectiv maxim), dup care acesta se va interschimba
cu primul element. Acest procedeu se repet pentru subcolecia rmas, pn cnd mai rmne
doar elementul maxim.

Subalgoritmul Selectie(n, K) este: {Se face o permutare a celor}
{n componente ale vectorului K astfel}
{ca k
1
s k
2
s .... s k
n
}
Pentru i := 1; n-1 execut
Fie ind := i;
Pentru j := i + 1; n execut
Dac k
j
< k
ind
atunci ind := j sfdac
sfpentru
Dac i < ind atunci t := k
i
; k
i
:= k
ind
; k
ind
:= t sfdac
sfpentru
sf-Selectie

Se observ c numrul de comparri este:
(n-1)+(n-2)+...+2+1=n(n-1)/2
indiferent de natura datelor. Deci complexitatea medie, dar i n cel mai ru caz este O(n
2
).

1.1.2.2. Bubble sort

Metoda "BubbleSort", compar dou cte dou elemente consecutive iar n cazul n care
acestea nu se afl n relaia dorit, ele vor fi interschimbate. Procesul de comparare se va ncheia
n momentul n care toate perechile de elemente consecutive sunt n relaia de ordine dorit.

Subalgoritmul BubbleSort(n, K) este:
Repet
Fie kod := 0; {Ipoteza "este ordine"}
Pentru i := 2; n execut
Dac k
i-1
> k
i
atunci
t := k
i-1
;
k
i-1
:= k
i
;
k
i
:= t;
kod := 1 {N-a fost ordine!}
sfdac
sfpentru
pncnd kod = 0 sfrep {Ordonare}
sf-BubbleSort

Acest algoritm execut n cel mai nefavorabil caz (n-1)+(n-2)+ ... +2+1 = n(n-1)/2
comparri, deci complexitatea lui este O(n
2
).
O variant optimizat a algoritmului "BubbleSort" este :

Subalgoritmul BubbleSort(n, K) este:
8
Fie s := 0
Repet
Fie kod := 0; {Ipoteza "este ordine"}
Pentru i := 2; n-s execut
Dac k
i-1
> k
i
atunci
t := k
i-1
;
k
i-1
:= k
i
;
k
i
:= t;
kod := 1 {N-a fost ordine!}
sfdac
sfpentru
s := s + 1
pncnd kod = 0 sfrep {Ordonare}
sf-BubbleSort

1.1.2.3. Quicksort

O metod mai performant de ordonare, care va fi prezentat n continuare, se numete
"QuickSort" i se bazeaz pe tehnica "divide et impera" dup cum se poate observa n
continuare. Metoda este prezentat sub forma unei proceduri care realizeaz ordonarea unui
subir precizat prin limita inferioar i limita superioar a indicilor acestuia. Apelul procedurii
pentru ordonarea ntregului ir este : QuickSort(n,K,1,n), unde n reprezint numrul de articole
ale coleciei date. Deci

Subalgoritmul SortareRapid(n, K) este:
Cheam QuickSort(n, K, 1, n)
sf-SortareRapid

Procedura QuickSort (n,K,St,Dr) va realiza ordonarea subirului k
St
,k
St+1
,..., k
Dr
.
Acest subir va fi rearanjat astfel nct k
St
s ocupe poziia lui final (cnd irul este ordonat).
Dac i este aceast poziie, irul va fi rearanjat astfel nct urmtoarea condiie s fie ndeplinit:

k
j
s k
i
s k
l
, pentru st s j < i < l sdr (*)

Odat realizat acest lucru, n continuare va trebui doar s ordonm subirul k
St
, k
St+1
, ...
,k
i-1
prin apelul recursiv al procedurii QuickSort(n,K,St,i-1) i apoi subirul k
i+1
,..., k
Dr

prin apelul QuickSort(n,K,i+1,Dr). Desigur ordonarea acestor dou subiruri (prin apelul
recursiv al procedurii) mai este necesar doar dac acestea conin cel puin dou elemente.
Procedura QuickSort este prezentat n continuare :

Subalgoritmul QuickSort (n, K, St, Dr) este:
Fie i := St; j := Dr; a := k
i
;
Repet
Cttimp k
j
> a i (i < j) execut j := j - 1 sfct
k
i
:= k
j
;
Cttimp k
i
s a i (i < j) execut i := i + 1 sfct
9
k
j
:= k
i
;
pncnd i = j sfrep
Fie k
i
:= a;
Dac St < i-1 atunci Cheam QuickSort(n, K, St, i - 1) sfdac
Dac i+1 < Dr atunci Cheam QuickSort(n, K, i + 1, Dr) sfdac
sf-QuickSort

Complexitatea algoritmului prezentat este O(n
2
) n cel mai nefavorabil caz, dar
complexitatea medie este de ordinul O(nLog
2
n).

1.1.3. Metode clasice de rezolvare a problemelor

1.1.3.1. Metoda backtraking

Metoda backtracking (cutare cu revenire) este aplicabil in general unor probleme ce au
mai multe soluii.
Vom considera nti un exemplu, dup care vom indica civa algoritmi generali pentru
aceast metod.

Problema 1. (Generarea permutrilor) Fie n un numr natural. Determinai permutrile
numerelor 1, 2, ..., n.
O soluie pentru generarea permutrilor, n cazul particular n = 3, ar putea fi:

Subalgoritmul Permutri1 este:
Pentru i1 := 1; 3 execut
Pentru i2 := 1; 3 execut
Pentru i3 := 1; 3 execut
Fie posibil := (i1, i2, i3)
Dac componentele vectorului posibil sunt distincte
atunci
Tiprete posibil
sfdac
sfpentru
sfpentru
sfpentru
sf-Permutri1


10
1
1
1 2 3
2
1 2 3
3
1 2 3
2
1
1 2 3
2
1 2 3
3
1 2 3
3
1
1 2 3
2
1 2 3
3
1 2 3
x
1
x
2
x
3

Figura 1.1. Reprezentare grafic a produsului cartezian {1, 2, 3}
3

Observaii privind subalgoritmul Permutri1:
Pentru n oarecare nu putem descrie un algoritm care s conin n cicluri n textul
surs.
Numrul total de vectori verificai este 3
3
, iar n general n
n
. Vectorii posibil verificai
sunt reprezentai grafic n Figura 1.1 - fiecare vector este un drum de la rdcin (de sus)
spre frunze (baza arborelui).
Algoritmul atribuie valori tuturor componentelor vectorului x, apoi verific dac
vectorul este o permutare.

O mbuntire a acestor algoritmi ar consta n a verifica anumite condiii din problem n
timp ce se construiesc vectorii, evitnd completarea inutil a unor componente.
De exemplu, dac prima component a vectorului construit (posibil) este 1, atunci este
inutil s atribuim celei de a doua componente valoarea 1, iar componentei a treia oricare din
valorile 1, 2 sau 3. Dac n este mare se evit completarea multor vectori ce au prefixul (1, ...). n
acest sens, (1, 3, ...) este un vector promitor (pentru a fi o permutare), n schimb vectorul (1, 1,
...) nu este. Vectorul (1, 3, ...) satisface anumite condiii de continuare (pentru a ajunge la
soluie) - are componente distincte. Nodurile haurate din Figura 1.1 constituie valori care nu
conduc la o soluie.
Vom descrie un algoritm general pentru metoda Bactracking dup care vom particulariza
acest algoritm pentru problemele enunate la nceputul seciunii. Pentru nceput vom face cteva
observaii i notaii privind metoda Backtracking aplicat unei probleme n care soluiile se
reprezint pe vectori, nu neaprat de lungime fix:
spaiul de cutare a soluiilor (spaiul soluiilor posibile): S = S
1
x S
2
x ... x S
n
;
posibil este vectorul pe care se reprezint soluiile;
posibil[1..k] e S
1
x S
2
x ... x S
k
este un vector care poate conduce sau nu la o soluie; k
reprezint indice pentru vectorul posibil, respectiv nivel n arborele care red grafic procesul
de cutare (Figura 1.2).
posibil[1..k] este promitor dac satisface condiii care pot conduce la o soluie;
soluie(n, k, posibil) funcie care verific dac vectorul (promitor) posibil[1..k] este soluie
a problemei.
11

Figura 1.2. Spaiul soluiilor posibile pentru generarea permutrilor

Procesul de cutare poate fi urmrit n algoritmul care urmeaz:

Algoritmul Backtracking este: {varianta nefinisat}
Fie k := 1
@Iniializeaz cutarea pe nivelul k (= 1)
Cttimp k > 0 execut {posibil[1..k-1] este promitor}
@Caut (secvenial) pe nivelul k o valoare v, pentru a completa n
continuare vectorul posibil[1..k-1] astfel nct posibil[1..k] s
fie promitor
Dac cutarea este cu succes
atunci Fie posibil[k] := v {posibil[1..k] este promitor}
Dac soluie(n, k, posibil)
atunci {o soluie! (rmnem pe nivelul k)}
Tiparete posibil[1..k]
altfel {e doar un vector promitor}
@Initializeaza cautarea pe nivelul k+1
Fie k := k + 1 {pas n fa (pe nivelul k+1)}
sfdac
altfel {pas n spate (revenire pe nivelul k-1)}
k := k - 1
sfdac
sfct
sf-Backtracking

Pentru a finisa acest algoritm trebuie s precizm elementele nestandard prezente. Astfel,
avem nevoie de funcia boolean
condiii-continuare(k, posibil, v)
funcie care verific dac vectorul promitor posibil[1..k-1] completat cu valoarea v conduce la
un vector promitor.
Apoi, pentru a iniializa cutarea la nivelul j avem nevoie de a alege un element fictiv din
mulimea S
j
, activitate realizat de funcia
12
init(j)
care returneaz acest element fictiv, care are rolul de a indica faptul c din mulimea S nc nu s-
a ales nici un element, deci dup el urmeaz primul element propriu din aceast mulime. Pentru
a cuta o valoare pe nivelul j, n ipoteza c valoarea curent nu e bun, avem nevoie de funcia
boolean
urmtor(j,v,nou)
care este True dac poate alege o valoare din S
j
care urmeaz dup valoarea v, valoare notat
prin nou i False n cazul n care nu mai exist alte valori n S
j
, deci nu mai poate fi fcut
alegerea. Cu aceste notaii algoritmul devine:

Algoritmul Backtracking este: {versiune final}
Fie k := 1;
posibil[1] := init(1);
Cttimp k > 0 execut {posibil[1..k-1] este promitor}
Fie Gsit := false; v := posibil[k] ;
Cttimp Urmtor(k, v,urm) i not Gsit execut
Fie v := urm;
Dac condiii-continuare(k, posibil, v) atunci
Gsit := true
sfdac
sfct
Dac Gsit
atunci Fie posibil[k] := v; {posibil[1..k] este promitor}
Dac soluie(n, k, posibil)
atunci {o soluie! (rmnem pe nivelul k)}
Tiparete posibil[1..k]
altfel {e doar un vector promitor}
Fie k := k + 1; {pas n fa (pe nivelul k+1)}
posibil[k] := init(k)
sfdac
altfel {pas n spate (revenire pe nivelul k-1)}
k := k - 1;
sfdac
sfct
sf-Backtracking
Procesul de cutare a unei valori pe nivelul k i funciile condiii-continuare i soluie sunt
dependente de problema care se rezolv. De exemplu, pentru generarea permutrilor funciile
menionate sunt:

Funcia init(k) este:
Init := 0
sf-init;

Funcia Urmtor(k, v, urm) este:
Dac v < n
atunci Urmtor := True; urm := v + 1
altfel Urmtor := False
sfdac
sf-urmator

Funcia conditii-continuare(k, posibil, v) este:
Kod := True; i := 1;
Cttimp kod i (i < k) execut
Dac posibil[i] = v atunci kod := False sfdac
13
i := i + 1;
sfct
conditii-continuare:=kod
sf-conditii

Funcia soluii(n, k, posibil) este:
Soluii := (k = n)
sf-solutii

n ncheiere, menionm c explorarea backtracking poate fi descris de asemenea recursiv. Dm
n acest scop urmtoru subalgoritm:

Subalgoritmul Backtracking(k, posibil) este:

{posibil[1..k] este promitor}
Dac soluie(n, k, posibil) atunci
{o soluie! terminare apel recursiv, astfel}
Tipareste posibil[1..k]
{rmnem pe acelai nivel}
altfel
Pentru fiecare v valoare posibil pentru posibil[k+1] execut
Dac condiii-continuare(k + 1, posibil, v) atunci
posibil[k + 1] := v
Backtracking(k + 1, posibil)
{pas in fa}
sfdac
sfpentru
sfdac
{terminare apel Backtracking(k, posibil)}
sf-Backtracking {deci, pas n spate (revenire)}

cu apelul iniial Cheam Backtracking(0, posibil).

1.1.3.2. Metoda "divide et impera"

Strategia "Divide et Impera" n programare presupune:

- mparirea datelor ("divide and conquer");
- mpartirea problemei n subprobleme ("top-down");

Metoda se aplica problemelor care pot fi descompuse n subprobleme independente,
similar problemei iniiale, de dimensiuni mai mici i care pot fi rezolvabile foarte uor.

Observaii:
o mprirea se face pn cnd se obine o problem rezolvabil imediat.
o Tehnica admite i o implementare recursiv.

Formalizare

14
Sublalgoritmul NumeAlg(D) este:
Dac dim(D) s a atunci
@problema se rezolva
altfel
@ Descompune D in d1, d2,..., dk
Cheama NumeAlg(d1)
Cheama NumeAlg(d2)
.
.
Cheama NumeAlg(dk)
@ construieste rezultatul final prin utilizarea rezultatelor
partiale din apelurile de mai sus
sfdac
sf-NumeAlg
15

1.2. Algoritmi i specificri

1.2.1. Scrierea unui algoritm pornind de la o specificaie dat

Problema 1
Se cere s se scrie un algoritm/program pentru rezolvarea urmtoarei probleme.

La un concurs pe facultate particip mai multe grupe. Pentru fiecare grup se cunosc (se dau)
rezultatele (notele) studenilor la mai multe discipline. Ctig grupa cu cea mai mare medie
de concurs. Media de concurs este (se calculeaz ca) media aritmetic a notelor rmase dup
eliminarea rezultatelor unui student i a rezultatelor la o disciplin. Studentul i disciplina se
vor alege de ctre eful de grup astfel nct media de concurs s fie maxim.



Reformulare: Ce linie i ce coloan se pot tia dintr-o matrice
data,
astfel nct suma elementelor rmase s fie maxim?
O Ob bs s. .: :

Contraexemplu:
2 6 6 5 1 19 9 1 17 7
5 5 1 3 1 14 4 9 9
4 9 7 8 2 28 8 2 24 4
2 2 6 2 1 12 2 - -- -> > - -- -
1 11 1 2 20 0 1 14 4 1 16 6 m mi in n
l lc c

m ma ax x= =5 50 0! !
|
Suma max.= 50!
0 6 6 5
0 5 1 3
0 9 7 8
0 0 0 0
E Ex xe em mp pl lu u:
2 6 6 5
5 5 1 3
4 9 7 8
2 2 6 2
O O s so ol lu u i ie e (2,1):
Suma Max.= 51
0 6 6 5
0 0 0 0
0 9 7 8
0 2 6 2
Matricea A:
7 5 5 8
9 1 1 4
4 5 2 1
1 3 7 1
Suma Max.=
44
7 5 0 8
9 1 0 4
4 5 0 1
0 0 0 0
Suma max.=
43
7 0 5 8
9 0 1 4
0 0 0 0
1 0 7 1
17%
83%
Prin eliminarea studentului cu
medie minim i a disciplinei cu
medie minim nu se obine
rezultatul optim ntotdeauna!
16


Problema 2

Scriei o funcie care satisface urmtoarea specificaie:

Date nr;
Precondiia: nreN, nr1
Rezultate l
1
,l
2
,...,l
n
;
Postcondiia: neN
*
, n j i j i l l n i nr l
l
nr
j i i
i
s s = = s s =
(

, 1 , , 1 , n este
maximal

Problema 3

Scriei o funcie care satisface urmtoarea specificaie:

Date n,L=(l
1
,l
2
,...,l
n
);
Precondiia: l
i
eR, i=1,n
Rezultate R=(r
1
,r
2
,...,r
n
);
Postcondiia: R este o permutare a lui L, r
1
> r
2
> ... > r
n
.

Problema 4

Se cere s se scrie un algoritm/program pentru rezolvarea urmtoarei probleme.

Cnd merge la cumprturi, Ana i pregtete tot timpul o list de cumprturi:
denumire, cantitate, raion (alimente, mbrcminte, nclminte, consumabile), pre estimat.
int Pm(int* X, int n)
{
int m=1;
for (int i=2; i<=n; i++) if (X[i]<X[m])
m=i;
return m;
}
int Alb (Mat a, Mat b, int n)
{
int s,sij, sm=0,im=0,jm=0; int
X[10],Y[10];
s=Sum(a,n); SumCol(a,n,X);
SumLin(a,n,Y);
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++) {
sij=s-Y[i]-X[j]+a[i][j];
if (sij>sm) { sm=sij; im=i; jm=j; }
}
Mut(a,b,n);
Lin(b,n,im);Col(b,n,jm);
return sm;
}
int L_c (Mat a, Mat c, int n)
{
int im, jm, Sl[10], Sc[10];
Mut(a,c,n);
SumLin(c,n,Sl);
Lin(c,n,Pm(Sl,n));
SumCol(c,n,Sc);
Col(c,n,Pm(Sc,n));
return Sum(c,n);
}
void main ()
{ clrscr(); randomize();
Mat a,b,c; int n,Sa,Sb, Nt=10000, Ce=0;
for (int t=1; t<=Nt; t++) {
Gen(a,n);
Sa=Alb(a,b,n);
Sb=L_c(a,c,n);
if (Sa!=Sb) { Ce++;
g << endl <<" Matricea A:"<< endl;
Tipf(a,n);
g << " Suma Max.= "<<Sa<<endl;
Tipf(b,n);
g << " Suma max.= "<<Sb<<endl;
Tipf(c,n);
}
}
if (!Ce) cout << " Ok dupa " << Nt << " teste." << endl;
else cout << " See ContraEx.Txt "<<Ce<<" din
"<<Nt<<endl;
g.close();
getche();
}
void SumLin(Mat a, int n, int* Y)
{
for (int i=1; i<=n; i++) {
Y[i]=0;
for (int j=1; j<=n; j++)
Y[i]+=a[i][j];
}}
void SumCol(Mat a, int n, int* X)
{
for (int j=1; j<=n; j++) {
X[j]=0;
for (int i=1; i<=n; i++)
X[j]+=a[i][j];
}}
void Lin(Mat a, int n, int i)
{
for (int j=1; j<=n; j++)
a[i][j]=0;
}
void Col(Mat a, int n, int j)
{
for (int i=1; i<=n; i++)
a[i][j]=0;
}
void Mut(Mat a, Mat b, int n)
{
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
b[i][j]=a[i][j];
}
int Sum(Mat a, int n)
{
int s=0;
for (int i=1; i<=n; i++)
for (int j=1; j<=n; j++)
s+=a[i][j];
return s;
}
typedef int Mat[10][10];
void Gen(Mat a, int& n)
{
n=random(4)+4;
for (int i=1; i<=n;
i++)
for (int j=1; j<=n;
j++) a[i][j]=random(9)+1;
}
ofstream g("ContraEx.Txt");
void Tipf(Mat a, int n)
{
for (int i=1; i<=n; i++) { g <<
endl;
for (int j=1; j<=n; j++)
g << setw(3)<<setfill('
')<<a[i][j];
} g << endl << endl;
}
S St tu ud di iu u: :

17
Se cere s se afieze lista de cumprturi a Anei ordonat alfabetic dup raion, lista ordonat
descresctor dup cantitate, precum i lista Anei de la un anumit raion. Se cere s se calculeze
i un pre estimativ al cheltuielilor Anei.

Problema 5

Modelai problema de mai jos folosind tehnica Backtraking, specificnd schematic
(precizarea elementelor cheie specifice metodei) construcia unei soluii. Creai un exemplu
pentru care prezentai construcia soluiei. Justificai alegerea tehnicii pentru rezolvarea
problemei.

La un concurs sportiv s-au nscris n concureni, avnd numerele de concurs 1, 2,, n.
Pentru fiecare sportiv se cunoate ara de origine (un ir de caractere). n fiecare zi a
competiiei, vor intra n concurs m concureni (msn). Afisai toate posibilitile de a stabili
ordinea intrrii n concurs a celor m concurenti, tiind c:
a. Doi sportivi din aceeai ar nu pot participa unul dup altul.
b. n cadrul unei zile concurenii intr n concurs n ordinea numrului de
concurs.

Problema 6

Se cere s se scrie un algoritm/program pentru rezolvarea urmtoarei probleme.

S se scrie un program care citete un ir de numere ntregi nenule. Introducerea unui
ir se ncheie odat cu citirea valorii 0. n irul citit programul va elimina secvenele de
elemente consecutive strict pozitive de lungime mai mare dect 3 (dac exist), dupa care va
tipri irul obinut.

1.2.2. Prezentai specificaia i / sau corectai

Problema 7

Se cere s se scrie specificarea urmtoarei funcii scris n limbajul Pascal.


Function f(p:Integer):Boolean;
Var d:Integer;
Begin
d:=2;
While (d<=Sqrt(p)) And (p Mod d>0) Do Inc(d);
f:= d> Sqrt(p)
End;

Problema 8

Recunoatei subalgoritmul de mai jos i scriei specificaia sa.

Subalgoritmul f(n, K, St, Dr) este:
Fie i := St; j := Dr; a := k
i
;
Repet
Cttimp k
j
> a i (i < j) execut j := j - 1 sfct
k
i
:= k
j
;
18
Cttimp k
i
s a i (i < j) execut i := i + 1 sfct
k
j
:= k
i
;
pncnd i = j sfrep
Fie k
i
:= a;
Dac St < i - 1 atunci Cheam f(n, K, St, i - 1) sfdac
Dac i + 1 < Dr atunci Cheam f(n, K, i + 1, Dr) sfdac
sf-f

Problema 9

Corectai urmtorul program Pascal.

(*
Dndu-se numrul natural n, determin numerele prime p1 i p2 astfel ca
n = p1 + p2
(verificarea ipotezei lui Goldbach).
*)

Program Verificarea_ipotezei_lui_Goldbach;

Function Prim(p:Integer):Boolean;
Var d:Integer;
Begin
d:=2;
While (d<=Sqrt(p)) And (p Mod d>0) Do Inc(d);
Prim:= d> Sqrt(p)
End;

Function Desc(n:Integer; Var p1,p2:Integer):Boolean;
Var p:Integer;
Begin
Desc:=False;
For p:=2 To n-2 Do
If Prim(p) And Prim(n-p) Then Begin
Desc:=True;
p1:=p; p2:=n-p
End;
End;

Var n,p1,p2:Integer;
Begin
Repeat
Write(' Dati n : '); Readln(n);
If n>0 Then
If Desc(n,p1,p2) Then Writeln(n:5,p1:7,p2:5)
Else Writeln(' Nu ex. desc.');
Until n=0;
End.

1.2.3. Ce face?

Problema 10

Ce face urmtorul program Pascal?

19
Program Ce_rezolva___;

Function Prim(p:Integer):Boolean;
Var d:Integer;
Begin
d:=2;
While (d<=Sqrt(p)) And (p Mod d>0) Do Inc(d);
Prim:= d> Sqrt(p)
End;

Function Desc(n:Integer; Var p1,p2:Integer):Boolean;
Begin
p1:=2;
While (p1<=n Div 2) And (Not Prim(p1) Or Not Prim(n-p1)) Do Inc(p1);
Desc:= p1<=n Div 2;
p2:=n-p1
End;

Var n,p1,p2:Integer;

Begin
Repeat
Write(' Dati n : '); Readln(n);
If n>0 Then
If Desc(n,p1,p2) Then Writeln(n:5,p1:7,p2:5)
Else Writeln(' Nu ex. desc.');
Until n=0;
End.

Problema 11

Pentru urmtorul program Pascal precizai:

a) ce face acest program;
b) ce realizeaz fiecare subprogram;
c) ce rezultate sunt tiprite pentru 12 1233 1132 2338 8533 10000 21500 0 ?

Program Fis_Sir_P__;
Uses Crt;
Type Sir=Array [1..100] Of Integer;
MultimeC = Set Of 0..9;

Procedure C__S__(Var X:Sir; Var n:Byte);
Var v:Integer; f:Text;
Begin
Assign(f,'Sir.In'); Reset(f); n:=0;
Writeln(' Sir.In : ');
Repeat
Read (f,v);
If v>0 Then Begin Inc(n); x[n]:=v; Write(v,',') End
Until v=0;
Close(f); Writeln
End;

Procedure T__S__(X:Sir; n:Byte);
Var i:Byte; f:Text;
Begin
Assign(f,'Sir.Out'); Rewrite(f);
Writeln(' Sir.Out : ');
For i:=1 To n Do Begin
20
Write(f,x[i],' ');
Write( x[i],' ')
End;
Writeln(f);
Close(f); Writeln
End;

Procedure Mc(a:Integer; Var M:MultimeC);
Begin
M:=[];
Repeat
M:=M+[a Mod 10];
a:=a Div 10
Until a=0;
End;

Function Acc(a,b:Integer):Boolean;
Var Ma, Mb:MultimeC;
Begin
Mc(a,Ma);
Mc(b,Mb);
Acc:= Ma=Mb
End;

Procedure P__(Var p:Integer);
Var v:Integer;
Begin
v:=0;
Repeat
v:=v*10+p Mod 10;
p:=p Div 10
Until p=0;
p:=v
End;

Procedure M__S__(Var X:Sir; n:Byte);
Var i:Byte; v:Integer;
Begin
For i:=1 To n-1 Do
If Acc(x[i],x[i+1]) Then P__(x[i])
End;


Var X:Sir;
n:Byte;
Begin
ClrScr;
C__S__(X,n);
M__S__(X,n);
T__S__(X,n);
Readln
End.


Raspuns c) 12 3321 1132 2338 8533 10000 21500

Problema 12

Precizai ce realizeaz urmtorul program, apoi scriei programul Pascal pentru funcia
invers.
21

Program Str_Lit_Urm;
Uses Crt;

Function UrmL(l:Char):Char;
Begin
Case l Of
'Z': UrmL:='A';
'z': UrmL:='a';
Else UrmL:=Succ(l)
End
End;

Function ModC(c:Char):Char;
Begin
If UpCase(c) In ['A'..'Z'] Then ModC:=UrmL(c)
Else ModC:=c
End;

Function Modif(s:String):String;
Var i:Byte;
Begin
For i:=1 To Length(s) Do s[i]:=ModC(s[i]);
Modif:=s
End;

Var s:String;
Begin
ClrScr;
Writeln(' Dati randurile de codif.:');
Repeat
Readln(s);
Writeln(Modif(s))
Until s=''
End.

Obs. Presupunnd c acest program realizeaz o codificare a unui text, scriei programul care
realizeaz decodificarea!

1.2.4. Inspectai soluia

Problema 13

Se cere s se inspecteze soluia primit i s se fac observaii/sugestii referitoare la
documentaie/proiectare/cod surs ale problemei de mai jos.

Scriei un program Pascal care citete numerele naturale n1, n2, , nk i tiprete cea mai
lung secven ns, ns+1, , nd, cu 1sdk, care conine numai numere prime. Programul
trebuie s conin:
- procedur care citete numerele date;
- o funcie care verific dac un numr natural este prim;
- o procedur care determin indicii s i d, 1sdk, cu proprietatea c ns, ns+1, , nd
sunt numere prime;
- o procedur care tiprete numerele ns, ns+1, , nd.
22

Program ProblemaPentruInspectare; {Cea mai lung secven de numere prime}

Type sirnat = array [1..100] of integer;
Var N : sirnat; {Tablou ce conine numerele date; are cel mult 100 numere}
s,d, { pozitiile ce dau secventa ceruta}
i, k: integer; {k=Lungimea lui N}

Function Prim(m:integer):boolean; {True daca m e prim}
Var i: integer; b: boolean;
Begin
b:=true; {Ipoteza "m e prim"}
if m<2 then b:=false
else begin
i:=1;
while b and (i< m div 2) do
if m mod i = 0
then b:= false {m nu e prim}
else b:=true;
end {if};
Prim := b
end;

Procedure Secventa(i,k:integer; N:sirnat; var j:integer);
{i este dat astfel nct N[i] este prim. Se obine cel mai mare j pentru
care secvena N[i..j] conine numai numere prime}
Begin
j:=i;
While (j<=k) and Prim(N[j+1]) do j:=j+1;
end;

Procedure LongSecv (k:integer; N:sirnat; s,d:integer);
{Se obtin indicii s si d pentru care secventa N[s..d] contine numai numere
prime si e cea mai lunga}
var i,j: integer;
Begin
i:=0; s:=0; d:=0; {variabila d codifica "Sirul nu contine numere
prime"}
While (i<k) do Begin
while Prim(N[i]) and (i<k) do i:=i+1;
if (i<k) then begin
Secventa (i,k,N,j);
if (j-i > d-s) then begin s:=i; d:=j end;
{s-a gasit o secventa mai lunga}
i:=j+2; {pozitie pentru o noua secventa}
end {if}
end {while}
end; {LongSecv}

Begin
writeln('dati lungimea sirului'); readln(k);
for i:=1 to k do readln(N[i]);
LongSecv(k,N,s,d);
If (d=0) then writeln('Nu exista numere prime')
else Begin
writeln('Secventa dorita este:');
for i:=s to d do write(N[i]:5)
end
end.

Problema 14
23

Inspectai urmtorii subalgoritmi, punei n eviden erorile i realizai modificrile necesare.

Subalgoritm care determin numrul de apariii a valorii maxime ntr-un vector dat. Realizai
un subalgoritm DetNrAp2 fr s fie necesar parcurgerea dubl a vectorului.

Subalgoritmul DetNrAp1(nrE, valE, nrAp) este:
Fie valMax := 0;
Pentru i := 1; nrE executa
Dac valE[i] > valMax
atunci valMax := valE[i];
sfdac
sfpentru
Pentru i := 1; nrE executa
Dac valE[i] = valMax
atunci nrAp := nrAp + 1;
sfdac
sfpentru
sf-DetNrAp1

Problema 15

Inspectai urmtorii subalgoritmi, punei n eviden erorile i realizai modificrile necesare.

Subalgoritm DetCifre1(nr, nrC, valC) este:
Fie i := 0;
Cattimp nr <> 0 executa
i := i+1;
valC[i] := nr mod 10;
nr := nr div 10;
sfcat;
nrC := i;
sf-DetCifre1

Subalgoritm CreareNr1(nrC, valC, nrNou) este:
Fie nrNou := 0;
Pentru i := 1; nrC executa
nrNou := nrNou * 10 + valC[i];
sfpentru
sf-CreareNr1


Subalgoritm DetCifre2(nr, valC) este:
Fie i := 0;
Pentru i := 0; 9 executa
valC[i] := 0;
sfpentru;
Cattimp nr <> 0 executa
Cif := nr mod 10;
valC[cif] := valC[cif] + 1;
nr := nr div 10;
sfcat
nrC := i;
sf-DetCifre2

Subalgoritm CreareNr2(valC, nrNou) este:
Fie nrNou := 0;
Pentru i := 0, 9 executa
Pentru j := 1; valC[i] executa
24
nrNou := nrNou * 10 + i;
sfpentru
sfpentru
sf-CreareNr2

25

2. Programarea orientat pe obiecte

2.1. Concepte OOP n limbaje de programare

2.1.1. Noiunea de clas

2.1.1.1. Realizarea proteciei datelor prin metoda programrii modulare

Dezvoltarea programelor prin programare procedural nseamn folosirea unor funcii i
proceduri pentru scrierea programelor. n limbajul C lor le corespund funciile care
returneaz o valoare sau nu. ns n cazul aplicaiilor mai mari ar fi de dorit s putem realiza
i o protecie corespunztoare a datelor. Acest lucru ar nsemna c numai o parte a funciilor
s aib acces la datele problemei, acelea care se refer la datele respective. Programarea
modular ofer o posibilitate de realizare a proteciei datelor prin folosirea clasei de memorie
static. Dac ntr-un fiier se declar o dat aparinnd clasei de memorie static n afara
funciilor, atunci ea poate fi folosit ncepnd cu locul declarrii pn la sfritul modulului
respectiv, dar nu i n afara lui.
S considerm urmtorul exemplu simplu referitor la prelucrarea vectorilor de numere
ntregi. S se scrie un modul referitor la prelucrarea unui vector cu elemente ntregi, cu
funcii corespunztoare pentru iniializarea vectorului, eliberarea zonei de memorie ocupate i
ridicarea la ptrat, respectiv afiarea elementelor vectorului. O posibilitate de implementare a
modulului este prezentat n fiierul vector1.cpp:

#include <iostream>

using namespace std;

static int* e; //elementele vectorului
static int d; //dimensiunea vectorului

void init(int* e1, int d1) //initializare
{
d = d1;
e = new int[d];
for(int i = 0; i < d; i++)
e[i] = e1[i];
}

void distr() //eliberarea zonei de memorie ocupata
{
delete [] e;
}

void lapatrat() //ridicare la patrat
{
26
for(int i = 0; i < d; i++)
e[i] *= e[i];
}

void afiseaza() //afisare
{
for(int i = 0; i < d; i++)
cout << e[i] << ' ';
cout << endl;
}

Modulul se compileaz separat obinnd un program obiect. Un exemplu de program
principal este prezentat n fiierul vector2.cpp:

extern void init( int*, int); //extern poate fi omis
extern void distr();
extern void lapatrat();
extern void afiseaza();
//extern int* e;
int main() {
int x[5] = {1, 2, 3, 4, 5};
init(x, 5);
lapatrat();
afiseaza();
distr();
int y[] = {1, 2, 3, 4, 5, 6};
init(y, 6);
//e[1]=10; eroare, datele sunt protejate
lapatrat();
afiseaza();
distr();
return 0;
}

Observm c dei n programul principal se lucreaz cu doi vectori nu putem s-i folosim
mpreun, deci de exemplu modulul vector1.cpp nu poate fi extins astfel nct s realizeze i
adunarea a doi vectori. n vederea nlturrii acestui neajuns s-au introdus tipurile abstracte
de date.

2.1.1.2. Tipuri abstracte de date

Tipurile abstracte de date realizeaz o legtur mai strns ntre datele problemei i operaiile
(funciile) care se refer la aceste date. Declararea unui tip abstract de date este asemntoare
cu declararea unei structuri, care n afar de date mai cuprinde i declararea sau definirea
funciilor referitoare la acestea.
De exemplu n cazul vectorilor cu elemente numere ntregi putem declara tipul abstract:

struct vect {
int* e;
int d;
void init(int* e1, int d1);
void distr() { delete [] e; }
void lapatrat();
27
void afiseaza();
};

Funciile declarate sau definite n interiorul structurii vor fi numite funcii membru iar datele
date membru. Dac o funcie membru este definit n interiorul structurii (ca i funcia distr
din exemplul de mai sus), atunci ea se consider funcie inline. Dac o funcie membru se
definete n afara structurii, atunci numele funciei se va nlocui cu numele tipului abstract
urmat de operatorul de rezoluie (::) i numele funciei membru. Astfel funciile init, lapatrat
i afiseaza vor fi definite n modul urmtor:

void vect::init(int *e1, int d1)
{
d = d1;
e = new int[d];
for(int i = 0; i < d; i++)
e[i] = e1[i];
}

void vect::lapatrat()
{
for(int i = 0; i < d; i++)
e[i] *= e[i];
}
void vect::afiseaza()
{
for(int i = 0; i < d; i++)
cout << e[i] << ' ';
cout << endl;
}

Dei prin metoda de mai sus s-a realizat o legtur ntre datele problemei i funciile
referitoare la aceste date, ele nu sunt protejate, deci pot fi accesate de orice funcie utilizator,
nu numai de funciile membru. Acest neajuns se poate nltura cu ajutorul claselor.

2.1.1.3. Declararea claselor

Un tip abstract de date clas se declar ca i o structur, dar cuvntul cheie struct se
nlocuiete cu class. Ca i n cazul structurilor referirea la tipul de dat clas se face cu
numele dup cuvntul cheie class (numele clasei). Protecia datelor se realizeaz cu
modificatorii de protecie: private, protected i public. Dup modificatorul de protecie se
pune caracterul :. Modificatorul private i protected reprezint date protejate, iar public date
neprotejate. Domeniul de valabilitate a modificatorilor de protecie este pn la urmtorul
modificator din interiorul clasei, modificatorul implicit fiind private. Menionm c i n
cazul structurilor putem s folosim modificatori de protecie, dar n acest caz modificatorul
implicit este public.
De exemplu clasa vector se poate declara n modul urmtor:

class vector {
int* e; //elementele vectorului
int d; //dimensiunea vectorului
public:
28
vector(int* e1, int d1);
~vector() { delete [] e; }
void lapatrat();
void afiseaza();
};

Se observ c datele membru e i d au fost declarate ca date de tip private (protejate), iar
funciile membru au fost declarate publice (neprotejate). Bineneles, o parte din datele
membru pot fi declarate publice, i unele funcii membru pot fi declarate protejate, dac
natura problemei cere acest lucru. n general, datele membru protejate pot fi accesate numai
de funciile membru ale clasei respective i eventual de alte funcii numite funcii prietene
(sau funcii friend).
O alt observaie important referitoare la exemplul de mai sus este c iniializarea datelor
membru i eliberarea zonei de memorie ocupat s-a fcut prin funcii membru specifice.
Datele declarate cu ajutorul tipului de dat clas se numesc obiectele clasei, sau simplu
obiecte. Ele se declar n mod obinuit n forma:

nume_clas list_de_obiecte;

De exemplu, un obiect de tip vector se declar n modul urmtor:

vector v;

Iniializarea obiectelor se face cu o funcie membru specific numit constructor. n cazul
distrugerii unui obiect se apeleaz automat o alt funcie membru specific numit destructor.
n cazul exemplului de mai sus

vector(int* e1, int d1);

este un constructor, iar

~vector() { delete [] e; }

este un destructor.
Tipurile abstracte de date de tip struct pot fi i ele considerate clase cu toate elementele
neprotejate. Constructorul de mai sus este declarat n interiorul clasei, dar nu este definit, iar
destructorul este definit n interiorul clasei. Rezult c destructorul este o funcie inline.
Definirea funciilor membru care sunt declarate, dar nu sunt definite n interiorul clasei se
face ca i n cazul tipurilor abstracte de date de tip struct, folosind operatorul de rezoluie.

2.1.1.4. Membrii unei clase. Pointerul this

Referirea la datele respectiv funciile membru ale claselor se face cu ajutorul operatorilor
punct (.) sau sgeat (->) ca i n cazul referirii la elementele unei structuri. De exemplu, dac
se declar:

29
vector v;
vector* p;

atunci afiarea vectorului v respectiv a vectorului referit de pointerul p se face prin:
v.afiseaza();
p->afiseaza();

n interiorul funciilor membru ns referirea la datele respectiv funciile membru ale clasei se
face simplu prin numele acestora fr a fi nevoie de operatorul punct ( . ) sau sgeat ( -> ).
De fapt compilatorul genereaz automat un pointer special, pointerul this, la fiecare apel de
funcie membru, i folosete acest pointer pentru identificarea datelor i funciilor membru.
Pointerul this va fi declarat automat ca pointer ctre obiectul curent. n cazul exemplului de
mai sus pointerul this este adresa vectorului v respectiv adresa referit de pointerul p.
Dac n interiorul corpului funciei membru afiseaza se utilizeaz de exemplu data membru d,
atunci ea este interpretat de ctre compilator ca i this->d.
Pointerul this poate fi folosit i n mod explicit de ctre programator, dac natura problemei
necesit acest lucru.

2.1.1.5. Constructorul

Iniializarea obiectelor se face cu o funcie membru specific numit constructor. Numele
constructorului trebuie s coincid cu numele clasei. O clas poate s aib mai muli
constructori. n acest caz aceste funcii membru au numele comun, ceea ce se poate face
datorit posibilitii de suprancrcare a funciilor. Bineneles, n acest caz numrul i/sau
tipul parametrilor formali trebuie s fie diferit, altfel compilatorul nu poate s aleag
constructorul corespunztor.
Constructorul nu returneaz o valoare. n acest caz nu este permis nici folosirea cuvntului
cheie void.
Prezentm n continuare un exemplu de tip clasa cu mai muli constructori, avnd ca date
membru numele i prenumele unei persoane, i cu o funcie membru pentru afiarea numelui
complet.
Fiierul persoana.h:

class persoana {
char* nume;
char* prenume;
public:
persoana(); //constructor implicit
persoana(char* n, char* p); //constructor
persoana(const persoana& p1); //constructor de copiere
~persoana(); //destructor
void afiseaza();
};

Fiierul persoana.cpp:

30
#include <iostream>
#include <cstring>
#include "persoana.h"

using namespace std;

persoana::persoana()
{
nume = new char[1];
*nume = 0;
prenume = new char[1];
*prenume = 0;
cout << "Apelarea constructorului implicit." << endl;
}

persoana::persoana(char* n, char* p)
{
nume = new char[strlen(n)+1];
prenume = new char[strlen(p)+1];
strcpy(nume, n);
strcpy(prenume, p);
cout << "Apelare constructor (nume, prenume).\n";
}

persoana::persoana(const persoana& p1)
{
nume = new char[strlen(p1.nume)+1];
strcpy(nume, p1.nume);
prenume = new char[strlen(p1.prenume)+1];
strcpy(prenume, p1.prenume);
cout << "Apelarea constructorului de copiere." << endl;
}

persoana::~persoana()
{
delete[] nume;
delete[] prenume;
}

void persoana::afiseaza()
{
cout << prenume << ' ' << nume << endl;
}

Fiierul persoanaTest.cpp:

#include "persoana.h"

int main() {
persoana A; //se apeleaza constructorul implicit
A.afiseaza();
persoana B("Stroustrup", "Bjarne");
B.afiseaza();
persoana *C = new persoana("Kernighan","Brian");
C->afiseaza();
delete C;
persoana D(B); //echivalent cu persoana D = B;
//se apeleaza constructorul de copire
D.afiseaza();
return 0;
31
}

Observm prezena a doi constructori specifici: constructorul implicit i constructorul de
copiere. Dac o clas are constructor fr parametri atunci el se va numi constructor implicit.
Constructorul de copiere se folosete la iniializarea obiectelor folosind un obiect de acelai
tip (n exemplul de mai sus o persoan cu numele i prenumele identic). Constructorul de
copiere se declar n general n forma:

nume_clas(const nume_clas& obiect);

Cuvntul cheie const exprim faptul c argumentul constructorului de copiere nu se modific.
O clas poate s conin ca date membru obiecte ale unei alte clase. Declarnd clasa sub
forma:

class nume_clasa {
nume_clasa_1 ob_1;
nume_clasa_2 ob_2;
...
nume_clasa_n ob_n;
...
};

antetul constructorului clasei nume_clasa va fi de forma:

nume_clasa(lista_de_argumente):
ob_1(l_arg_1), ob_2(l_arg_2), ..., ob_n(l_arg_n)

unde lista_de_argumente respectiv l_arg_i reprezint lista parametrilor formali ai
constructorului clasei nume_clasa respectiv ai obiectului ob_i.

Din lista ob_1(l_arg_1), ob_2(l_arg_2), ..., ob_n(l_arg_n) pot s lipseasc
obiectele care nu au constructori definii de programator, sau obiectul care se iniializeaz cu
un constructor implicit, sau cu toi parametrii implicii.

Dac clasa conine date membru de tip obiect atunci se vor apela mai nti constructorii
datelor membru, iar dup aceea corpul de instruciuni al constructorului clasei respective.

Fiierul pereche.cpp:

#include <iostream>
#include "persoana.h"

using namespace std;

class pereche {
persoana sot;
persoana sotie;
public:
pereche() //definitia constructorului implicit
{ //se vor apela constructorii impliciti
32
} //pentru obiectele sot si sotie
pereche(persoana& sotul, persoana& sotia);
pereche(char* nume_sot, char* prenume_sot,
char* nume_sotie, char* prenume_sotie):
sot(nume_sot, prenume_sot),
sotie(nume_sotie, prenume_sotie)
{
}
void afiseaza();
};

inline pereche::pereche(persoana& sotul, persoana& sotia):
sot(sotul), sotie(sotia)
{
}

void pereche::afiseaza()
{
cout << "Sot: ";
sot.afiseaza();
cout << "Sotie: ";
sotie.afiseaza();
}

int main() {
persoana A("Pop", "Ion");
persoana B("Popa", "Ioana");
pereche AB(A, B);
AB.afiseaza();
pereche CD("C","C","D","D");
CD.afiseaza();
pereche EF;
EF.afiseaza();
return 0;
}

Observm c n cazul celui de al doilea constructor, parametrii formali sot i sotie au fost
declarai ca i referine la tipul persoana. Dac ar fi fost declarai ca parametri formali de tip
persoana, atunci n cazul declaraiei:

pereche AB(A, B);

constructorul de copiere s-ar fi apelat de patru ori. n astfel de situaii se creeaz mai nti
obiecte temporale folosind constructorul de copiere (dou apeluri n cazul de fa), dup care
se execut constructorii datelor membru de tip obiect (nc dou apeluri).

2.1.1.6. Destructorul

Destructorul este funcia membru care se apeleaz n cazul distrugerii obiectului. Destructorul
obiectelor globale se apeleaz automat la sfritul funciei main ca parte a funciei exit. Deci,
nu este indicat folosirea funciei exit ntr-un destructor, pentru c acest lucru duce la un ciclu
infinit. Destructorul obiectelor locale se execut automat la terminarea blocului n care s-au
definit. n cazul obiectelor alocate dinamic, de obicei destructorul se apeleaz indirect prin
operatorul delete (obiectul trebuie s fi fost creat cu operatorul new). Exist i un mod
33
explicit de apelare a destructorului, n acest caz numele destructorului trebuie precedat de
numele clasei i operatorul de rezoluie.
Numele destructorului ncepe cu caracterul ~ dup care urmeaz numele clasei. Ca i n cazul
constructorului, destructorul nu returneaz o valoare i nu este permis nici folosirea
cuvntului cheie void. Apelarea destructorului n diferite situaii este ilustrat de urmtorul
exemplu. Fiierul destruct.cpp:

#include <iostream>
#include <cstring>

using namespace std;

class scrie { //scrie pe stdout ce face.
char* nume;
public:
scrie(char* n);
~scrie();
};

scrie::scrie(char* n)
{
nume = new char[strlen(n)+1];
strcpy(nume, n);
cout << "Am creat obiectul: " << nume << '\n';
}

scrie::~scrie()
{
cout << "Am distrus obiectul: " << nume << '\n';
delete nume;
}

void functie()
{
cout << "Apelare functie" << '\n';
scrie local("Local");
}

scrie global("Global");

int main() {
scrie* dinamic = new scrie("Dinamic");
functie();
cout << "Se continua programul principal" << '\n';
delete dinamic;
return 0;
}

2.1.2. Metoda programrii orientate obiect


34
2.1.2.1. Bazele teoretice

Prin folosirea tipurilor abstracte de date, se creeaz un tot unitar pentru gestionarea datelor i
a operaiilor referitoare la aceste date. Cu ajutorul tipului abstract clas se realizeaz i
protecia datelor, deci n general elementele protejate nu pot fi accesate dect de funciile
membru ale clasei respective. Aceast proprietate a obiectelor se numete ncapsulare
(encapsulation).
n viaa de zi cu zi ns ne ntlnim nu numai cu obiecte separate, dar i cu diferite legturi
ntre aceste obiecte, respectiv ntre clasele din care obiectele fac parte. Astfel se formeaz o
ierarhie de clase. Rezult a doua proprietate a obiectelor: motenirea (inheritance). Acest
lucru nseamn c se motenesc toate datele i funciile membru ale clasei de baz de ctre
clasa derivat, dar se pot aduga elemente noi (date membru i funcii membru) n clasa
derivat. n cazul n care o clas derivat are mai multe clase de baz se vorbete despre
motenire multipl.
O alt proprietate important a obiectelor care aparin clasei derivate este c funciile membru
motenite pot fi suprancrcate. Acest lucru nseamn c o operaie referitoare la obiectele
care aparin ierarhiei are un singur identificator, dar funciile care descriu aceast operaie pot
fi diferite. Deci, numele funciei i lista parametrilor formali este aceeai n clasa de baz i n
clasa derivat, dar descrierea funciilor difer ntre ele. Astfel, n clasa derivat funciile
membru pot fi specifice clasei respective, dei operaia se identific prin acelai nume.
Aceast proprietate se numete polimorfism.

2.1.2.2. Declararea claselor derivate

O clas derivat se declar n felul urmtor:

class nume_clas_derivat : lista_claselor_de_baz {
//date membru noi i funcii membru noi
};

unde lista_claselor_de_baz este de forma:
elem_1, elem_2, ..., elem_n
i elem_i pentru orice 1 i n poate fi
public clas_de_baz_i
sau
protected clas_de_baz_i
sau
private clas_de_baz_i

Cuvintele cheie public, protected i private se numesc i de aceast dat modificatori de
protecie. Ei pot s lipseasc, n acest caz modificatorul implicit fiind private. Accesul la
elementele din clasa derivat este prezentat n tabelul 1.

Accesul la Modificatorii de Accesul la
35
elementele din clasa
de baz
protecie referitoare
la clasa de baz
elementele din clasa
derivat
public public public
protected public protected
private public inaccesibil
public protected protected
protected protected protected
private protected inaccesibil
public private private
protected private private
private private inaccesibil

Tabelul 1: accesul la elementele din clasa derivat

Observm c elementele de tip private ale clasei de baz sunt inaccesibile n clasa derivat.
Elementele de tip protected i public devin de tip protected, respectiv private dac
modificatorul de protecie referitor la clasa de baz este protected respectiv private, i rmn
neschimbate dac modificatorul de protecie referitor la clasa de baz este public. Din acest
motiv n general datele membru se declar de tip protected i modificatorul de protecie
referitor la clasa de baz este public. Astfel datele membru pot fi accesate, dar rmn
protejate i n clasa derivat.

2.1.2.3. Funcii virtuale

Noiunea de polimorfism ne conduce n mod firesc la problematica determinrii
funciei membru care se va apela n cazul unui obiect concret. S considerm urmtorul
exemplu. Declarm clasa de baz baza, i o clas derivat din acest clas de baz, clasa
derivata. Clasa de baz are dou funcii membru: functia_1 i functia_2. n interiorul funciei
membru functia_2 se apeleaz functia_1. n clasa derivat se suprancarc funcia membru
functia_1, dar funcia membru functia_2 nu se suprancarc. n programul principal se declar
un obiect al clasei derivate i se apeleaz funcia membru functia_2 motenit de la clasa de
baz. n limbajul C++ acest exemplu se scrie n urmtoarea form.
Fiierul virtual1.cpp:

#include <iostream>

using namespace std;

class baza {
public:
void functia_1();
void functia_2();
};
36

class derivata : public baza {
public:
void functia_1();
};

void baza::functia_1()
{
cout << "S-a apelat functia membru functia_1"
<< " a clasei de baza" << endl;
}

void baza::functia_2()
{
cout << "S-a apelat functia membru functia_2"
<< " a clasei de baza" << endl;
functia_1();
}

void derivata::functia_1()
{
cout << "S-a apelat functia membru functia_1"
<< " a clasei derivate" << endl;
}

int main() {
derivata D;
D.functia_2();
}


Prin execuie se obine urmtorul rezultat:

S-a apelat functia membru functia_2 a clasei de baza
S-a apelat functia membru functia_1 a clasei de baza

ns acest lucru nu este rezultatul dorit, deoarece n cadrul funciei main s-a apelat funcia
membru functia_2 motenit de la clasa de baz, dar funcia membru functia_1 apelat de
functia_2 s-a determinat nc n faza de compilare. n consecin, dei funcia membru
functia_1 s-a suprancrcat n clasa derivat nu s-a apelat funcia suprancrcat ci funcia
membru a clasei de baz.
Acest neajuns se poate nltura cu ajutorul introducerii noiunii de funcie membru virtual.
Dac funcia membru este virtual, atunci la orice apelare a ei, determinarea funciei membru
corespunztoare a ierarhiei de clase nu se va face la compilare ci la execuie, n funcie de
natura obiectului pentru care s-a fcut apelarea. Aceast proprietate se numete legare
dinamic, iar dac determinarea funciei membru se face la compilare, atunci se vorbete de
legare static.
Am vzut c dac se execut programul virtual1.cpp se apeleaz funciile membru
functia_1 i functia_2 ale clasei de baz. ns funcia membru functia_1 fiind suprancrcat
n clasa derivat, ar fi de dorit ca funcia suprancrcat s fie apelat n loc de cea a clasei de
baz.
Acest lucru se poate realiza declarnd functia_1 ca funcie membru virtual. Astfel, pentru
orice apelare a funciei membru functia_1, determinarea acelui exemplar al funciei membru
37
din ierarhia de clase care se va executa, se va face la execuie i nu la compilare. Ca urmare,
funcia membru functia_1 se determin prin legare dinamic.
n limbajul C++ o funcie membru se declar virtual n cadrul declarrii clasei respective n
modul urmtor: antetul funciei membru se va ncepe cu cuvntul cheie virtual.
Dac o funcie membru se declar virtual n clasa de baz, atunci suprancrcrile ei se vor
considera virtuale n toate clasele derivate ale ierarhiei.
n cazul exemplului de mai sus declararea clasei de baz se modific n felul urmtor.

class baza {
public:
virtual void functia_1();
void functia_2();
};

Rezultatul obinut prin execuie se modific astfel:

S-a apelat functia membru functia_2 a clasei de baza
S-a apelat functia membru functia_1 a clasei derivate

Deci, ntr-adevr se apeleaz funcia membru functia_1 a clasei derivate.
Prezentm n continuare un alt exemplu n care apare necesitatea introducerii funciilor
membru virtuale. S se defineasc clasa fractie referitoare la numerele raionale, avnd ca
date membru numrtorul i numitorul fraciei. Clasa trebuie s aib un constructor, valoarea
implicit pentru numrtor fiind zero iar pentru numitor unu, precum i dou funcii membru:
produs pentru a calcula produsul a dou fracii i inmulteste pentru nmulirea obiectului
curent cu fracia dat ca i parametru. De asemenea, clasa fractie trebuie s aib i o funcie
membru pentru afiarea unui numr raional. Folosind clasa fractie ca i clas de baz se va
defini clasa derivat fractie_scrie, pentru care se va suprancrca funcia produs, astfel nct
concomitent cu efectuarea nmulirii s se afieze pe stdout operaia respectiv. Funcia
inmulteste nu se va suprancrca, dar operaia efectuat trebuie s se afieze pe dispozitivul
standard de ieire i n acest caz. Fiierul fvirt1.cpp:

#include <iostream>

using namespace std;

class fractie {
protected:
int numarator;
int numitor;
public:
fractie(int numarator1 = 0, int numitor1 = 1);
fractie produs(fractie& r); //calculeaza produsul a doua
//fractii, dar nu simplifica
fractie& inmulteste(fractie& r);
void afiseaza();
};

fractie::fractie(int numarator1, int numitor1)
{
numarator = numarator1;
numitor = numitor1;
}
38

fractie fractie::produs(fractie& r)
{
return fractie(numarator * r.numarator, numitor * r.numitor);
}

fractie& fractie::inmulteste(fractie& q)
{
*this = this->produs(q);
return *this;
}

void fractie::afiseaza()
{
if ( numitor )
cout << numarator << " / " << numitor;
else
cerr << "Fractie incorecta";
}

class fractie_scrie: public fractie{
public:
fractie_scrie( int numarator1 = 0, int numitor1 = 1 );
fractie produs( fractie& r);
};

inline fractie_scrie::fractie_scrie(int numarator1, int numitor1) :
fractie(numarator1, numitor1)
{
}

fractie fractie_scrie::produs(fractie& q)
{
fractie r = fractie(*this).produs(q);
cout << "(";
this->afiseaza();
cout << ") * (";
q.afiseaza();
cout << ") = ";
r.afiseaza();
cout << endl;
return r;
}

int main()
{
fractie p(3,4), q(5,2), r;
r = p.inmulteste(q);
p.afiseaza();
cout << endl;
r.afiseaza();
cout << endl;
fractie_scrie p1(3,4), q1(5,2);
fractie r1, r2;
r1 = p1.produs(q1);
r2 = p1.inmulteste(q1);
p1.afiseaza();
cout << endl;
r1.afiseaza();
cout << endl;
r2.afiseaza();
39
cout << endl;
return 0;
}

Prin execuie se obine:

15 / 8
15 / 8
(3 / 4) * (5 / 2) = 15 / 8
15 / 8
15 / 8
15 / 8

Observm c rezultatul nu este cel dorit, deoarece operaia de nmulire s-a afiat numai o
singur dat, i anume pentru expresia r1 = p1.produs(q1). n cazul expresiei r2 =
p1.inmulteste(q1) ns nu s-a afiat operaia de nmulire. Acest lucru se datoreaz
faptului c funcia membru inmulteste nu s-a suprancrcat n clasa derivat. Deci s-a apelat
funcia motenit de la clasa fractie. n interiorul funciei inmulteste s-a apelat funcia
membru produs, dar deoarece aceast funcie membru s-a determinat nc n faza de
compilare, rezult c s-a apelat funcia referitoare la clasa fractie i nu cea referitoare la clasa
derivat fractie_scrie. Deci, afiarea operaiei s-a efectuat numai o singur dat.
Soluia este, ca i n exemplul anterior, declararea unei funcii membru virtuale, i anume
funcia produs se va declara ca funcie virtual. Deci declararea clasei de baz se modific n
felul urmtor:

class fractie {
protected:
int numarator;
int numitor;
public:
fractie(int numarator1 = 0, int numitor1 = 1);
virtual fractie produs(fractie& r); //calculeaza produsul a doua
//fractii, dar nu simplifica
fractie& inmulteste(fractie& r);
void afiseaza();
};

Dup efectuarea acestei modificri prin executarea programului obinem:

15 / 8
15 / 8
(3 / 4) * (5 / 2) = 15 / 8
(3 / 4) * (5 / 2) = 15 / 8
15 / 8
15 / 8
15 / 8

Deci, se observ c afiarea operaiei s-a fcut de dou ori, pentru ambele expresii. Funciile
virtuale, ca i alte funcii membru de fapt, nu trebuie neaprat suprancrcate n clasele
derivate. Dac nu sunt suprancrcate atunci se motenete funcia membru de la un nivel
superior.
Determinarea funciilor membru virtuale corespunztoare se face pe baza unor tabele
construite i gestionate n mod automat. Obiectele claselor care au funcii membru virtuale
40
conin i un pointer ctre tabela construit. De aceea gestionarea funciilor membru virtuale
necesit mai mult memorie i un timp de execuie mai ndelungat.

2.1.2.4. Clase abstracte

n cazul unei ierarhii de clase mai complicate, clasa de baz poate avea nite proprieti
generale despre care tim, dar nu le putem defini numai n clasele derivate. De exemplu s
considerm ierarhia de clase din figura 1.
Observm c putem determina nite proprieti referitoare la clasele derivate. De exemplu
greutatea medie, durata medie de via i viteza medie de deplasare. Aceste proprieti se vor
descrie cu ajutorul unor funcii membru. n principiu i pentru clasa animal exist o greutate
medie, durat medie de via i vitez medie de deplasare. Dar aceste proprieti ar fi mult
mai greu de determinat i ele nici nu sunt importante pentru noi ntr-o generalitate de acest
fel. Totui pentru o tratare general ar fi bine, dac cele trei funcii membru ar fi declarate n
clasa de baz i definite n clasele derivate. n acest scop s-a introdus noiunea de funcie
membru virtual pur.

Figura 1. Ierarhie de clase referitoare la animale

Funcia virtual pur este o funcie membru care este declarat, dar nu este definit n clasa
respectiv. Ea trebuie definit ntr-o clas derivat. Funcia membru virtual pur se declar
n modul urmtor. Antetul obinuit al funciei este precedat de cuvntul cheie virtual, i
antetul se termin cu = 0. Dup cum arat numele i declaraia ei, funcia membru virtual
pur este o funcie virtual, deci selectarea exemplarului funciei din ierarhia de clase se va
face n timpul execuiei programului.
Clasele care conin cel puin o funcie membru virtual pur se vor numi clase abstracte.
Deoarece clasele abstracte conin funcii membru care nu sunt definite, nu se pot crea obiecte
aparinnd claselor abstracte. Dac funcia virtual pur nu s-a definit n clasa derivat atunci
i clasa derivat va fi clas abstract i ca atare nu se pot defini obiecte aparinnd acelei
clase.
S considerm exemplul de mai sus i s scriem un program, care referitor la un porumbel,
urs sau cal determin dac el este gras sau slab, rapid sau ncet, respectiv tnr sau btrn.
Afiarea acestui rezultat se va face de ctre o funcie membru a clasei animal care nu se
suprancarc n clasele derivate. Fiierul abstract1.cpp:

#include <iostream>
41

using namespace std;

class animal {
protected:
double greutate; // kg
double virsta; // ani
double viteza; // km / h
public:
animal( double g, double v1, double v2);
virtual double greutate_medie() = 0;
virtual double durata_de_viata_medie() = 0;
virtual double viteza_medie() = 0;
int gras() { return greutate > greutate_medie(); }
int rapid() { return viteza > viteza_medie(); }
int tanar()
{ return 2 * virsta < durata_de_viata_medie(); }
void afiseaza();
};

animal::animal( double g, double v1, double v2)
{
greutate = g;
virsta = v1;
viteza = v2;
}

void animal::afiseaza()
{
cout << ( gras() ? "gras, " : "slab, " );
cout << ( tanar() ? "tanar, " : "batran, " );
cout << ( rapid() ? "rapid" : "incet" ) << endl;

}

class porumbel : public animal {
public:
porumbel( double g, double v1, double v2):
animal(g, v1, v2) {}
double greutate_medie() { return 0.5; }
double durata_de_viata_medie() { return 6; }
double viteza_medie() { return 90; }
};


class urs: public animal {
public:
urs( double g, double v1, double v2):
animal(g, v1, v2) {}
double greutate_medie() { return 450; }
double durata_de_viata_medie() { return 43; }
double viteza_medie() { return 40; }
};

class cal: public animal {
public:
cal( double g, double v1, double v2):
animal(g, v1, v2) {}
double greutate_medie() { return 1000; }
double durata_de_viata_medie() { return 36; }
double viteza_medie() { return 60; }
42
};

int main() {
porumbel p(0.6, 1, 80);
urs u(500, 40, 46);
cal c(900, 8, 70);
p.afiseaza();
u.afiseaza();
c.afiseaza();
return 0;
}

Observm c dei clasa animal este clas abstract, este util introducerea ei, pentru c multe
funcii membru pot fi definite n clasa de baz i motenite fr modificri n cele trei clase
derivate.

43

2.2. Diagrame de clase i interaciuni ntre obiecte n UML

Limbajul de modelare unificat UML (Unified Modelling Language) [UML11]
definete un set de elemente de modelare i notaii grafice asociate acestora. Elementele de
modelare pot fi folosite pentru descrierea oricror sisteme software. n particular, UML
conine elemente ce pot fi folosite i pentru cele orientate pe obiecte.
Aceast seciune conine cteva elemente de baz folosite pentru descrierea structurii
i comportamentului unui sistem software orientat pe obiecte - diagrame de clase i de
interaciuni ntre obiecte. Aceste elemente corespund seleciei facute n [Fowler03],
capitolele 3 i 4. Subseciunea Error! Reference source not found. prezint elementele
structurale selectate, iar subseciunea Error! Reference source not found. pe cele
comportamentale.
nainte de a trece la prezentarea acestor elemente selectate, o s indicm contextul n
care acestea se folosesc pentru dezvoltarea unui sistem software. ntrebrile principale la care
trebuie s rspundem n acest sens sunt: (A) ce tipuri de modele construim, (B) cnd sunt
construite modelele n diferite procese de dezvoltare i (C) care este legtura dintre modele
i codul scris.
Pentru a rspunde pe scurt acestor ntrebri, vom da exemple ce se refer la o aplicaie
folosit de un casier pentru nregistrarea vnzrilor la un punct de vnzare ntr-un magazin.
Aplicaia este numit POS (Point of Sale) i presupune implementarea unui singur caz de
utilizare, nregistrarea unei vnzri.
A. Tipuri de modele
Privind tipurile de modele pe care le construim, cel mai potrivit este s folosim termenii
i conceptele introduse de arhitecturile dirijate de modele, n principal Model-Driven
Architecture - MDA [MDA03]. Conform ghidului MDA, modele pe care le putem construi
sunt prezentate n continuare.
CIM - Modele independente de calcule (Computational Independent Models).
Aceste modele descriu ce face sistemul i nu cum furnizeaz acest comportament. Ele se
mai numesc i modele ale domeniului (sau modele de afaceri - business models) i descriu
spaiul problemei. Din perspectiv structural, diagramele de clase sunt folosite pentru a
defini conceptele domeniului. Diagramele de interaciune sunt rar folosite n cazul acestor
modele. Pentru a exprima comportamentul dorit al sistemului, se folosesc alte elemente ca i
cazuri de utilizare, procese de afaceri (business processes), etc - dar acestea nu sunt discutate
n aceast seciune.
Primul model din Figur 1 prezint un extras din modelul conceptual pentru aplicaia
POS. Modelul este construit pentru a surprinde conceptele folosite de utilizatori. Aceste
concepte sunt folosite pentru a exprima comportamentul dorit, folosind alte elemente de
modelare.
PIM - Modele independente de platform (Platform Independent Models). Aceste
modele descriu cum funcioneaz sistemul, ntr-o manier independent de posibilele
platforme concrete n care va fi implementat. La acest nivel se introduc elemente
arhitecturale, iar diagramele de clase i de interaciuni ntre obiecte constituie dou
instrumente de baz pentru descrierea detaliat a sistemului (proiectare detaliat). Desigur,
44
se folosesc si alte elemente de modelare, structurale i comportamentale, dar acestea nu sunt
discutate aici, de exemplu - colaborri, maini cu stri, activiti, etc.
Al doilea model din Figur 1 prezint un extras din modelul PIM pentru POS. Att
modelele CIM ct i cele PIM conin doar construcii UML (ex. tipuri de date definite n
specificaia UML) i eventual extensii ale acestui limbaj (independente de platform) - alte
detalii vor fi date n seciunea Error! Reference source not found..

Figur 1 Tipuri de modele
PSM - Modele specifice unor platforme (Platform Specific Models). Acestea sunt o
transformare a celor PIM ctre diferite platforme alese. Arhitectul poate decide construirea
unui astfel de model pentru a exprima diferite elemente folosite ale platformelor alese, de
exemplu tipuri de date specifice. Diagramele de clase i de interaciune ntre obiecte sunt de
asemenea folosite pentru aceste modele.
Ultimul model prezentat n Figur 1 reprezint o transformare a modelului PIM n
contextul implementrii sistemului n Java. Tipurile de date din acest model sunt tipuri Java
(ex. String, double), iar modelul include i un tip de date din pachetul java.sql.

Conform ghidului MDA, definim modele astfel nct n final s generm cod ctre
anumite platforme alese. Codul poate fi generat pornind de la modele PIM sau PSM. n
procesul de generare se folosesc corespondene ntre elementele modelelor i elementele
platformei alese.
B. Procese de dezvoltare i instrumente CASE
45
Diferite procese de dezvoltare indic folosirea unor modele de diferite tipuri, la diferite
momente pe parcursul dezvoltrii.
Procesele de dezvoltare dirijate de modele subscriu n general ghidului [MDA03] i
creaz modele PIM, opional derivate din modele CIM. Apoi, din modele PIM, genereaz
cod, folosind n mod opional un modele intermediare PSM. Aceste procese de dezvoltare
presupun folosirea unor instrumente de proiectare (CASE - Computer Aided Software
Engineering) care suport aceast infrastructur de transformare a modelelor. Exemple n
acest sens sunt toate procesele dirijate de modele pentru aplicaii orientate pe servicii folosesc
limbaje/extensii ale UML independente de platform, de exemplu SoaML
1
.
Exist procese dirijate de modele care nu folosesc modele PIM ci direct modele
PSM. Acestea se bazeaz pe specificaii elaborate pentru anumite platforme, de exemplu
arhitecturi bazate pe componente ce ofer servicii, SCA
2
.
Procesele de dezvoltare mai elaborate de tipul RUP
3
(pentru sisteme mari),
recomand folosirea tuturor modelelor CIM, PIM i PSM, n contextul folosirii
instrumentelor CASE.
Procesele de dezvoltare de tip agil nu recomand n general folosirea instrumentelor
CASE, de exemplu dezvoltarea dirijat de teste
4
sau dezvoltarea agil dirijat de modele
5
, dar
recomand construirea unor modele nainte de a ncepe codificarea. Modelele sunt de fapt
schie (scrise pe hrtie sau pe tabl) i sunt folosite pentru a comunica idei despre proiectarea
sistemului.
Indiferent de procesul de dezvoltare folosit, majoritatea instrumentelor de dezvoltare
moderne permit sincronizarea imediat ntre codul scris i modelele asociate codului.
Aceast sincronizare este de fapt ntre cod i modele PSM. De exemplu, un instrument CASE
care sincronizeaz modelele cu codul scris n Java, o face ntre cod i modele PSM conform
platformei Java.
O ultim i recent categorie de procese de dezvoltare care propune folosirea modelelor
PIM i generarea direct i complet a codului este categoria proceselor ce se bazeaz pe
modele executabile. Astzi, adoptarea standardului pentru modele executabile UML (fUML
- Foundational UML)
6
este n curs de finalizare. Conform acestor procese, n viitorul apropiat
ne ateptm la adoptarea unui stil nou de dezvoltare n care vom construi doar modele i
vom scrie cod ntr-un limbaj textual
7
definit pe elementele din aceste modele. Astfel,
modelele PSM i codul scris n limbaje ca i Java, C++ sau C# vor fi lsate n grija
instrumentelor CASE care le vor genera automat.
C. Corespondena dintre modele i cod
Corespondenele dintre modele i cod sunt importante dup cum relev punctele (A) i
(B). Dac generm cod din modele PIM, respectiv dac folosim un instrument CASE care

1
OMG. Service Oriented Architecture Modeling Language, 2009. http://www.omg.org/spec/SoaML/
2
Open SOA. Service Component Architecture Specifications, 2007.
http://www.osoa.org/display/Main/Service+Component+Architecture+Specifications
3
IBM. IBM Rational Unified Process, 2007. http://www-01.ibm.com/software/awdtools/rup/
4
Beck, K. Test-Driven Development by Example, Addison Wesley, 2003.
5
Ambler, S.W. Agile Model Driven Development (AMDD): The Key to Scaling Agile Software Development,
2008. http://www.agilemodeling.com/essays/amdd.htm
6
OMG. Semantics Of A Foundational Subset For Executable UML Models (FUML), 2010.
http://www.omg.org/spec/FUML/
7
OMG. Concrete Syntax For UML Action Language (Action Language For Foundational UML - ALF), 2010.
http://www.omg.org/spec/ALF/
46
sincronizeaz modele PSM cu codul, e important sa tim ce elemente se vor genera din
modelele construite. Chiar dac lucrm agil i folosim "schie" de modele (fr a folosi
instrumente CASE), se pune aceeai problem.
innd cont i de modelele executabile amintite anterior (care sunt la nivel PIM), n
seciunile care urmeaz vom discuta numai corespondenele dintre modele PIM i
limbajele C++, Java i C#. Modelele PSM conin n plus fa de cele PIM i tipuri de date
specifice anumitor limbaje, astfel corespondenele dintre modele PSM i cod sunt aceleai,
doar c sunt prezente n modele i extensii UML conform tipurilor specifice.

2.2.1. Diagrame de clase

Diagramele sunt reprezentri grafice (n general 2D) ale unor elemente dintr-un model.
Diagramele de clase reprezint tipurile de obiecte folosite n sistem i relaiile dintre acestea.
Elementele structurale selectate n aceast seciune sunt (a) tipuri de obiecte: clase,
interfee, enumerri; (b) gruparea elementelor folosind pachete i (c) relaii ntre aceste
elemente: asocieri, generalizri, realizri i dependene.

Figur 2 Model conceptual
Figur 2 prezint un model conceptual iniial pentru POS. Clasele sunt folosite pentru a
identifica conceptele acestui domeniu. Acolo unde nu e relevant, compartimentul cu
atributele claselor este ascuns. Proprietile claselor sunt definite prin atribute i asocieri, iar
tipurile de date pentru atribute nu sunt precizate.
Modelele conceptuale sunt de tip CIM i sunt folosite pentru a genera modele PIM. Ca
i modele CIM, ele pot s nu conin detalii privind reprezentarea atributelor. Dac procesul
de dezvoltare folosit nu presupune folosirea unui model CIM (ci PIM sau PSM), atunci
modelul din Figur 2 este un model PIM sau PSM incomplet.
n context PIM, arhitectura sistemului din perspectiv structural este descris folosind
pachete (organizate ierarhic) i dependene ntre acestea - a se vedea Figur 3 pentru POS.
Pachetele sunt definite cu responsabiliti coezive, de exemplu interaciunea cu utilizatorul
(ui), faad peste domeniu (service), entiti (model) i depozite de obiecte sau obiecte de
acces la date (repository, inmemory repository).
47

Figur 3 Arhitectur stratificat
Grija principal pe care o avem atunci cnd stabilim arhitectura sistemului este s
respectm principiile orientate pe obiecte SOLID
8,9
. Pachetele din Figur 3 sunt proiectate
conform principiului responsabilitii unice (Single Responsibility), conform cruia obiectele
ar trebui s aib o singur responsabilitate, iar obiectele cu responsabiliti nrudite ar trebui
grupate logic.
Dependena dintre dou elemente software (A depinde de B) indic faptul c atunci
cnd un element se va modifica (B), este posibil ca elementul dependent (A) s trebuiasc de
asemenea modificat. Dependenele dintre pachetele din Figur 3 respect recomandrile
arhitecturilor stratificate, adic elementele de pe straturile superioare sunt dependente de cele
de pe straturile inferioare, de exemplu ui depinde de service i model, service depinde de
model i repository, ns service nu depinde de implementarea concret pentru repository,
anume repository inmemory. Inversarea acestei ultime dependene urmeaz un alt principiu
SOLID, anume inversarea dependenelor (Dependency Inversion). Figur 4 prezint detalii
privind aceast inversare a dependenelor dintre service i repository inmemory. n loc ca
StoreService s fie dependent de implementarea concret InmemorySaleRepository, a fost
introdus interfaa SaleRepository pentru a decupla aceste dou elemente. De fapt
SaleRepository abstractizeaz accesul la obiectele de tip Sale, fcnd posibil astfel
nlocuirea pachetului repository inmemory din sistem cu o alt implementare, fr a afecta
celelalte pachete din sistem.

8
Robert C. Martin. Design Principles and Design Patterns, 2004.
http://www.objectmentor.com/resources/articles/Principles_and_Patterns.pdf
9
SOLID Design Principles: Single responsibility, Open-closed, Liskov substitution, Interface segregation and
Dependency inversion, http://en.wikipedia.org/wiki/SOLID_(object-oriented_design)
48

Figur 4 Arhitectur stratificat - justificare dependene
La nivel PIM sau PSM, diagramele de clase sunt folosite pentru a rafina entitile
i relaiile dintre acestea - a se vedea Figur 5. Aceste elemente vor fi discutate n
subseciunile care urmeaz.

Figur 5 Entitile POS
A. Pachete
Pachetele UML [UML11, sect. 7.3.38; Fowler03, cap. 7] grupeaz elemente din model
i ofer un spaiu de nume pentru elementele grupate. Din perspectiva elementelor discutate
n acest document, pachetele pot conine tipuri de date i alte pachete. Un tip de date sau un
pachet poate fi parte a unui singur pachet.
n termeni ai limbajelor de programare, pachetele UML corespund pachetelor Java i
spaiilor de nume C++ i C#. Pachetele UML sunt referite folosind operatorul de rezoluie ::,
la fel ca i in C++ i C#. De exemplu, numele complet al pachetului ui din Figur 3 sau
Figur 4 este pos::ui.
Diagramele de clase ce indic cu preponderen pachetele unui sistem sunt folosite
pentru a descrie arhitectura acestuia - a se vedea Figur 3 pentru sistemul POS. Dependenele
ntre pachete indic un sumar al dependenelor dintre elementele coninute i elementele din
49
alte pachete. Din perspectiv arhitectural, buna gestionare a acestor dependene este crucial
n procesul de construire i ntreinere a sistemului.

B. Clase
O clas UML [UML11, sect. 7.3.7; Fowler03, cap. 3] reprezint o mulime de obiecte
cu aceleai elemente structurale (proprieti) i comportamentale (operaii). Clasele UML
sunt tipuri de date i corespund claselor din limbajele Java, C++ i C#. O clas poate fi
declarat abstract i n acest caz nu poate fi instaniat la fel ca i n Java, C++ i C#.
O clas UML poate fi derivat din mai multe clase, la fel ca i n C++. Folosirea
motenirii multiple n model nu duce la o coresponden direct ntre model i cod n cazul
limbajelor Java sau C#.
O clas UML poate realiza/implementa mai multe interfee la fel ca i n Java sau C#.
Corespondena ntre modelele ce conin clase ce implementeaz mai multe interfee i C++
este realizat via clase C++ pur abstracte i motenire multipl.
Toate clasele din Figur 5 sunt concrete, iar AbstractSaleRepository din Figur 4 este
clas abstract (numele scris italic).
Principiul substituiei este aplicabil pentru instanele de tipul unor clase i interfee, la
fel ca i n Java, C++ i C#. Adic, instanele din program pot fi nlocuite cu instane ale
tipurilor derivate fr s alterm semantic programul.

C. Interfee
O interfa UML [UML11, sect. 7.3.24; Fowler03, cap. 7] este un tip de date ce
declar un set de operaii, adic un contract pe care clasele pot s-l realizeze. Acest concept
corespunde aceluiai concept din Java/C# i claselor pur abstracte din C++.
SaleRepository din Figur 4 este o interfa. Atunci cnd evidenierea metodelor
interfeei nu este relevant, notaia grafic pentru interfee este cea din Error! Reference
source not found..

Figur 6 Interfa, enumerare i tipuri structurate

D. Enumerri i obiecte valorice
Enumerrile UML [UML11, sect. 7.3.17, Fowler03, cap. 5] descriu un set de
simboluri care nu au asociate valori aa cum aceleai concepte se regsesc n C++, Java i C#
- Error! Reference source not found..
Tipurile structurate [UML11, sect. 7.3.11; Fowler03, cap. 5] se modeleaz folosind
stereotipul datatype i corespund structurilor din C++/C# i tipurilor primitive din Java - a se
vedea Error! Reference source not found.. Instanele acestor tipuri sunt identificate doar
prin valoarea lor. Ele sunt folosite pentru a descrie proprietile claselor i corespund
obiectelor valorice (ablonul value object
10
), cu deosebirea c nu pot avea identitate.

10
Martin Fowler. Patterns of Enterprise Application Architecture. Addison-Wesley, 2002.
50

E. Generalizri i realizri de interfee
Generalizarea [UML11, sect. 7.3.20; Fowler03, cap. 5] este o relaie ntre un tip de
date mai general (de baz) i unul mai specializat (derivat). Aceast relaie poate fi aplicat
ntre dou clase sau dou interfee, corespunznd relaiilor de motenire din Java i C++/C#
dintre clase, respectiv interfee (clase pur abstracte n cazul C++).
Realizarea unei interfee n UML [UML11, sect. 7.3.25; Fowler03, cap. 5] reprezint
o relaie ntre o clas i o interfa prin care se indic faptul c clasa este conform
contractului specificat de interfa. Aceste realizri corespund implementrilor interfeelor
din Java i C#, respectiv motenirii n C++. A se vedea notaiile grafice dintre
AbstractSaleRepository i SaleRepository n Figur 4 i Figur 6.

F. Proprietai
Proprietile [UML11, sect. 7.3.45; Fowler03, cap. 3] reprezint aspecte structurale ale
unui tip de date. Proprietile unei clase sunt introduse prin atribute i asocieri. Un atribut
descrie o proprietate a clasei n al doilea compartiment al ei, sub forma:
vizibilitate nume: tip multiplicitate = valoare {proprietati}
Numele este obligatoriu, la fel ca i vizibilitatea care poate fi publica (+), privat (-),
protetejat (#) sau la nivel de pachet (fr specificator). Vizibilitatea UML corespunde
specificatorilor de acces cu acelai nume din Java, avnd aceeai semantic. Vizibilitatea la
nivel de pachet nu se regasete n C++, iar n C# are o coresponden prin specificatorul
internal din C# dar care are i conotaii de distribuire a elementelor software (elementele
declarate internal n C# fiind accesibile doar n distribuia binar dll sau exe din care acestea
fac parte).
Celelalte elemente folosite la declararea unei proprieti sunt opionale. Tipul
proprietii poate fi oricare: clas, interfa, enumerare, tip structurat sau tip primitiv.
Tipurile primitive n UML sunt tipuri valorice [UML11, sect. 7.3.44]. UML definete
urmtoarele tipuri primitive: String, Integer, Boolean i UnlimitedNatural. Primele trei tipuri
primitive sunt n coresponden cu tipurile cu acelai nume din limbajele Java, C++ i C#, dar
cu observaiile:
- Tipul String este clas n Java i C#, instanele de tip String fiind nemodificabile, spre
deosebire de C++ unde irurile de caractere sunt modificabile. Codificarea
caracterelor nu este precizat n UML, n timp ce n Java i C# ea este Unicode, iar n
C++ ASCII.
- Tipul Integer n UML este n precizie nelimitat, n timp ce n cele 3 limbaje plaja de
valori este limitat.
Multiplicitatea poate fi 1 (valoare implicit, atunci cnd multiplicitatea nu e precizat),
0..1 (optional), 0..* (zero sau mai multe valori), 1..* (unu sau mai multe valori), m..n (ntre m
i n valori, unde m i n sunt constante, n putnd fi *). Pentru o proprietate cu multiplicitate
m..* putem preciza n plus dac:
- Valorile se pot repeta sau nu - implicit valorile sunt unice (adic mulime), n caz
contrar precizm explicit prin nonunique (adic container cu valori posibil
duplicate).
- Valorile pot fi referite prin indici sau nu - implicit nu (deci colecie), n caz contrar
precizm explicit ordered (deci list).
Exemple de proprieti:
multime : Integer[0..*] - mulime de valori ntregi (unice)
51
lista : Integer[0..*] {ordered} - list cu valori ntregi i distincte (unice)
lista : Integer[0..*] {ordered, nonunique} - list de ntregi
colectie : Integer[0..*] {nonunique} - colecie de ntregi
Proprietilor din UML le corespund cmpuri sau variabile de tip obiect n Java i C++,
respectiv proprieti n C#. Dificulti de interpretare se ridic n ceea ce privete proprietile
cu multiplicitate m..*. Pentru exemplele de mai sus putem considera urmtoarele
corespondene cu Java (in mod similar i cu C++/C#):
- mulimi de ntregi:
o int[] multime sau Integer[] multime, urmnd s asigurm prin operaii c
multime va conine valori distincte, sau cel mai potrivit
o java.util.Set multime
- liste cu valori ntregi i distincte:
o int[] lista, Integer[] lista sau java.util.List lista, urmnd s asigurm prin
operaii c lista va conine valori distincte
- liste de ntregi:
o int[] lista, Integer[] lista, sau java.util.List lista
- colecii de ntregi:
o int[] colectie, Integer[] colectie, sau java.util.Collection colectie
Asocierile UML [UML11, sect. 7.3.3; Fowler03, cap. 3] reprezint un set de tuple,
fiecare tuplu fcnd legtura ntre dou instane ale unor tipuri de date. n acest sens, o
asociere este un tip de date care leag proprieti ale altor tipuri de date.

Figur 7 Asocieri unidirecionale
Figur 7 (a) prezint modelul rezultat dup adugarea atributelor quantity i product n
clasa SaleItem reprezentat grafic n diagrama (b). Codul (d) scris n Java/C# corespunde
acestei situaii. Dac considerm c e mai potrivit o reprezentare grafic pentru relaia dintre
clasele SaleItem i Product, atunci n loc s adugm product ca i atribut, folosim o asociere
unidirecional de la SaleItem spre Product. Atunci cnd se adaug asocierea unidirecional,
n model se creeaz o asociere i o proprietate n clasa SaleItem, avnd numele rolului, adic
product. Astfel, codul (d) corespunde reprezentrii grafice (c) a modelului (a) care mai
conine o asociere neartat n figur. Asocierile unidirecionale introduc proprieti n
clasa surs, de tipul clasei destinaie. Numele proprietii coincide cu numele rolului
asocierii, iar forma general de definire a proprietilor (prezentat la nceputul acestei
subseciuni) se aplic i n acest caz.
Decizia folosirii asocierilor n locul atributelor este luat n funcie de context. De
exemplu, atunci cnd modelm entitile unui aplicaii folosim asocieri pentru a indica
relaiile dintre entiti i folosim atribute atunci cnd descriem entitile folosind obiecte
valorice/descriptive. n general, folosim asocieri cnd dorim s evideniem importana
tipurilor i a legturilor dintre ele.
Asocierile bidirecionale leag dou proprieti din dou clase diferite sau din aceeai
clas. Figur 8 prezint o asociere bidirecional ntre SaleItem i Product, precum i codul
Java/C# corespunztor acestei situaii.
52

Figur 8 Asocieri bidirecionale
Modelele conceptuale conin asocieri bidirecionale. Pstrarea asocierilor bidirecionale
n modelele PIM/PSM poate conduce la o execuie ineficient datorat reprezentrii
obiectelor. Un pas obligatoriu ce trebuie fcut n cadrul proiectrii detaliate este rafinarea
asocierilor, n primul rnd prin transformarea celor bidirecionale n unidirecionale.
Figur 5 prezint rezultatul rafinrii asocierilor din Figur 2.
Relaiile ntreg-parte sunt modelate n UML folosind agregri i conineri. O agregare
este o asociere prin care indicm c un obiect este parte a unui alt obiect. De exemplu, Figur
4 indic prin agregarea dintre InmemorySaleRepository i Sale c primul obiect memoreaz
toate obiectele de tip Sale (vnzrile sunt parte a acestui depozit). O coninere este o
agregare prin care se indic n plus c obiectele coninute pot fi pri a unui singur ntreg, de
exemplu, un element al vnzrii (SaleItem) n Figur 5 poate fi parte doar dintr-o singur
vnzare (Sale). Rafinarea asocierilor include i stabilirea relaiilor de agregare i
coninere.
Ca i n Java, C++ i C#, putem defini proprieti statice sau de tip clas, n diagrame
acestea fiind reprezentate prin subliniere.

G. Dependene
ntre dou elemente software, client i furnizor, exist o dependen [UML11, sect.
7.3.12; Fowler03, cap. 3] dac schimbarea definiiei furnizorului poate duce la schimbarea
clientului. De exemplu dac o clas C trimite un mesaj altei clase F, atunci C este dependent
de F deoarece schimbarea definiiei mesajului n F va implica schimbri n C privind modul
de transmitere. Ca regul general, ar trebui s minimizm dependenele n model, n timp ce
pstrm coezive aceste elemente.
n UML se pot indica explicit dependenele ntre orice elemente din model. Prezentarea
lor explicit ns poate face modelul greu de citit. Din acest motiv, dependenele se prezint
explicit n mod selectiv, evideniind elementele principale i arhitecturale - a se vedea Figur
3 i Figur 4.

H. Operaii
Operaiile n UML [UML11, sect. 7.3.37; Fowler03, cap. 3] definesc comportamentul
obiectelor i corespund metodelor din limbajele de programare orientate obiect. De fapt,
operaiile specific comportamentul (reprezint antetul), iar corpul/implementarea este
definit de elemente comportamentale ca i interaciuni, maini cu stri i activiti -
implementrile sunt numite metode n UML. Sintaxa specificrii operaiilor este:
vizibilitate nume (lista-parametri) : tip-returnat {proprieti}
unde vizibilitatea, tipul-returnat i proprietile sunt definite ca i n cazul proprietilor
claselor. n lista proprietilor operaiei se poate preciza dac este doar o operaie de
interogare {query}, adic o operaie ce nu modific starea obiectului apelant - implicit,
operaiile sunt considerate comenzi, adic modific starea obiectelor. Parametrii n lista-
parametrilor sunt separai prin virgul, un parametru fiind de forma:
53
direcie nume: tip = valoare-implicit,
direcia putnd fi: in, out i in-out, implicit fiind in.
Ca i n Java, C++ i C#, putem defini operaii statice sau de tip clas, n diagrame
acestea fiind reprezentate prin subliniere.

2.2.2. Diagrame de interaciune

Interaciunile UML [UML11, sect. 14.4; Fowler03, cap. 4] descriu comportamentul
sistemului, indicnd cum colaboreaz mai muli participani ntr-un anume scenariu. Exist
mai multe tipuri de interaciuni, dar n aceast seciune vom discuta numai despre diagrame
de secvene, un tip de interaciuni care descriu mesajele transmise ntre participani.
n general diagramele de secven descriu un singur scenariu. De exemplu, diagrama
din Figur 9 pune fa n fa casierul i sistemul POS, descriind fluxul normal de desfurare
pentru singurul caz de utilizare discutat aici, nregistrarea unei vnzri. O astfel de diagram
ajut la identificarea interfeei publice a sistemului. Pornind de la descrierea cazurilor de
utilizare, aciunile utilizatorilor sunt modelate ca i mesaje la care sistemul trebuie s
rspund. Mesajele 1, 2, 4 i 6 din Figur 9 indic faptul c sistemul va trebui s fac anumite
calcule i s rspund utilizatorului.
Bara vertical asociat unui participant reprezint o axa temporal. Pe aceast ax se
plaseaz bare de activare pentru a indica cnd anume acel participant este implicat n
interaciune. Mesajele au nume, sunt n general numerotate i pot indica un rspuns returnat.
Toate mesajele din figurile acestei seciuni sunt sincrone (cele asincrone nu intr n scopul
acestui document). Interaciunile pot conine fragmente: cicluri i alternative.
54

Figur 9 Interfaa sistemului

Diagrame de tipul celei prezentate n Figur 9 pot fi definite n context CIM, nainte de
stabilirea unei arhitecturi. La nivel PIM, odat identificat ceea ce trebuie s fac sistemul, se
folosesc diagrame de secven pentru a detalia cum vor colabora obiectele din sistem,
conform responsabilitilor precizate prin arhitectura stabilit. Figur 10 prezint detaliat
colaborarea n cazul sistemului POS.
Participanii din Figur 9 nu indic instane ale unor tipuri din model. De ast dat,
participanii principali din Figur 10 sunt obiecte controller, service i repository, conform
arhitecturii POS. Diagrama prezint mesaje adresate ctre controller (1, 3, 6 i 9) deoarece n
diagram nu e prezent i elementul de interfa utilizator.
Participanii fiind obiecte, mesajele transmise vor fi apeluri de metode ale obiectelor
spre care sunt trimise mesajele. Astfel, diagrama ne conduce la identificarea metodelor
obiectelor. Figur 11 prezint metodele identificate pe baza interaciunilor din Figur 10.
55

Figur 10 Proiectare detaliat - interaciuni ntre obiecte

Figur 11 Proiectare detaliat - diagram de clase

2.2.3. Detalii despre subiecte propuse

Subiectele vizeaz cunoaterea notaiilor grafice UML pentru diagrame de clase i de
interaciune, respectiv corespondena ntre aceste notaii i cod.
Astfel, subiectul va prezenta o diagram de clase i una de interaciuni ntre obiecte
din aceste clase i se va cere scrierea unui program care corespunde diagramelor. Diagrama
de clase va conine:
56
- Clase i interfee (un element UI, un controller C, o interfa R(epository), o clas
abstract AR ce implementeaza R, dou clase concrete derivate din AR ce in obiectele
n memorie; i dou entiti);
- Proprieti i operaii;
- Asocieri, moteniri i realizri de interfee.
Programul va putea fi scris n orice limbaj orientat pe obiecte, ex. Java, C++ sau C#.
Operaiile vor fi simple, n medie 3 linii de cod fiecare operaie (cel mult un ciclu).

Bibliografie
[UML11] OMG. UML Superstructure, 2011.
http://www.omg.org/spec/UML/2.4.1/Superstructure/PDF/
[Fowler03] Martin Fowler. UML Distilled: A Brief Guide to the Standard Object Modeling
Language (3rd Edition). Addison-Wesley Professional, 2003.
[MDA03] OMG. MDA Guide Version 1.0.1, 2003. http://www.omg.org/cgi-bin/doc?omg/03-
06-01.pdf
57

3. Structuri de date

3.1. Cozi, stive, Liste, Arbori binari

In cele ce urmeaz vom prezenta cteva dintre containerele des folosite in programare
i anume listele, stivele, cozile i arborii. Vom specifica tipurile abstracte de date
corespunztoare, indicnd i specificnd operaiile caracteristice. Pentru fiecare operaie din
interfaa unui tip de date, vom da specificarea operaiei n limbaj natural, indicnd datele i
precondiiile operaiei (pre), precum i rezultatele i postcondiiile operaiei (post).

3.1.1. Liste

In limbajul uzual cuvntul list refer o nirare, ntr-o anumit ordine, a unor
nume de persoane sau de obiecte, a unor date etc. Exemple de liste sunt multiple: list de
cumprturi, list de preuri, list de studeni, etc. Ordinea n list poate fi interpretat ca un
fel de legtur ntre elementele listei (dup prima cumprtur urmeaz a doua
cumprtur, dup a doua cumprtur urmeaz a treia cumprtur, etc) sau poate fi vzut
ca fiind dat de numrul de ordine al elementului n list (1-a cumprtur, a 2-a
cumprtur, etc). Tipul de date List care va fi definit n continuare permite
implementarea n aplicaii a acestor situaii din lumea real.
Ca urmare, o list o putem vedea ca pe o secven de elemente > <
n
l l l ,.., ,
2 1
de un
acelai tip (TElement) aflate ntr-o anumit ordine, fiecare element avnd o poziie bine
determinat n cadrul listei. Ca urmare, poziia elementelor n cadrul listei este esenial,
astfel accesul, tergerea i adugarea se pot face pe orice poziie n list. Lista poate fi vzut
ca o colecie dinamic de elemente n care este esenial ordinea elementelor. Numrul n de
elemente din list se numete lungimea listei. O list de lungime 0 se va numi lista vid.
Caracterul de dinamicitate al listei este dat de faptul c lista i poate modifica n timp
lungimea prin adugri i tergeri de elemente n/din list.
In cele ce urmeaz, ne vom referi la listele liniare. O list liniar, este o structur care
fie este vid (nu are nici un element), fie
- are un unic prim element;
- are un unic ultim element;
- fiecare element din list (cu excepia ultimului element) are un singur succesor;
- fiecare element din list (cu excepia primului element) are un singur predecesor.
Ca urmare, ntr-o list liniar se pot insera elemente, terge elemente, se poate
determina succesorul (predecesorul) unui element, se poate accesa un element pe baza
poziiei sale n list.
O list liniar se numete circular dac se consider predecesorul primului nod a fi
ultimul nod, iar succesorul ultimului nod a fi primul nod.
Conform definiiei anterioare, fiecare element al unei listei liniare are o poziie bine
determinat n list. De asemenea, este important prima poziie n cadrul listei, iar dac se
cunoate poziia unui element din list atunci pe baza aceastei poziii se poate identifica
elementul din list, poziia elementului predecesor i poziia elementului succesor n list
58
(dac acestea exist). Ca urmare, ntr-o list se poate stabili o ordine ntre poziiile
elementelor n cadrul listei.
Poziia unui element n cadrul listei poate fi vzut n diferite moduri:
1. ca fiind dat de rangul (numrul de ordine al) elementului n cadrul listei. n acest
caz este o similitudine cu tablourile, poziia unui element n list fiind indexul
acestuia n cadrul listei. ntr-o astfel de abordare, lista este vzut ca un tablou
dinamic n care se pot accesa/aduga/terge elemente pe orice poziie n list.
2. ca fiind dat de o referin la locaia unde se stocheaz elementul listei (ex:
pointer spre locaia unde se memoreaz elementul).
Pentru a asigura generalitatea, vom abstractiza noiunea de poziie a unui element n
list i vom presupune c elementele listei sunt accesate prin intermediul unei poziii
generice.

Vom spune c o poziie p ntr-o list este valid dac este poziia unui element al
listei. Spre exemplu, dac p ar fi un pointer spre locaia unde se memoreaz un element al
listei, atunci p este valid dac este diferit de pointerul nul sau de orice alt adres care nu
reprezint adresa de memorare a unui element al listei. n cazul n care p ar fi rangul (numrul
de ordine al) elementului n list, atunci p este valid dac nu depete numrul de elemente
din list.
Ca urmare, dac ne gndim la o list liniar n care operaiile de
acces/inserare/tergere s se fac pe baza unei poziii generice n list, se ajunge la urmtorul
tip abstract de date.
Lista vid o vom nota n ceea ce urmeaz cu |.

Tipul Abstract de Date LISTA

domeniu
L={l | l este o list cu elemente de tip TElement}

operaii (interfaa minimal)

creeaz(l)
descriere: se creeaz o list vid
pre: adevrat
post: leL, | = l
adaugSfarsit (l, e)
descriere: se adaug un element la sfritul listei
pre: leL, eeTElement
post: leL, l se modific prin adugarea lui e la sfritul su
adaugInceput(l, e)
descriere: se adaug un element la nceputul listei
59
pre: leL, eeTElement
post: leL, l se modific prin adugarea lui e la nceputul su

valid(l, p)
descriere: funcie care verific dac o poziie n list este valid
pre: leL, p e o poziie n l
post: valid= adevrat dac p este o poziie valid n l
fals n caz contrar
adaugnainte(l, p, e)
descriere: se adaug un element naintea unei anumite poziii n list
pre: leL, eeTElement, p e o poziie n l, valid(l, p)
post: leL, l se modific prin inserarea lui e n l nainte de poziia p
adaugDup(l, p, e)
descriere: se adaug un element dup o anumit poziie n list
pre: leL, eeTElement, p e o poziie n l, valid(l, p)
post: leL, l se modific prin inserarea lui e n l dup poziia p
terge (l, p, e)
descriere: se terge elementul din list situat pe o anumit poziie
pre: leL, eeTElement, p e o poziie n l, valid(l, p)
post: eeTElement, leL, l se modific prin tergerea elementului de pe poziia
p din l, e este elementul ters
element (l, p, e)
descriere: accesarea elementului din list de pe o anumit poziie
pre: leL, eeTElement, p e o poziie n l, valid(l, p)
post: eeTElement, e este elementul de pe poziia p din l
modifica (l, p, e)
descriere: modificarea elementului din list de pe o anumit poziie
pre: leL, eeTElement, p e o poziie n l, valid(l, p)
post: leL, l se modific prin nlocuirea elementulului de pe poziia p din l cu e
prim(l)
descriere: funcie care returneaz poziia primului element n list
pre: leL
post: prim= poziia primului element din l sau o poziie care nu e valid
dac l e vid

ultim(l)
descriere: funcie care returneaz poziia ultimului element n list
pre: leL
post: ultim= poziia ultimului element din l sau o poziie care nu e valid
dac l e vid

urmtor(l, p)
descriere: funcie care returneaz poziia n list urmtoare unei poziii
date
pre: leL, p e o poziie n l, valid(l, p)
60
post: urmator= poziia din l care urmeaz poziiei p sau o poziie care nu e
valid dac p e poziia ultimului element din list

precedent(l, p)
descriere: funcie care returneaz poziia n list precedent unei poziii
date
pre: leL, p e o poziie n l, valid(l, p)
post: precedent= poziia din l care precede poziia p sau o poziie care nu
e valid dac p e poziia primului element din list
caut(l, e)
descriere: funcie care caut un element n list
pre: leL, eeTElement
post: caut = prima poziie pe care apare e n l sau o poziie care nu e
valid dac l e e

apare(l, e)
descriere: funcie care verific apartenena unui element n list
pre: leL, eeTElement
post: apare = adevrat l e e
fals contrar

vid(l)
descriere: funcie care verific dac lista este vid
pre: leL
post: vid = adevrat n cazul n care l e lista vid
fals n caz contrar
dim(l)
descriere: funcie care returneaz numrul de elemente din list
pre: leL
post: dim=numrul de elemente din list
iterator(l, i)
descriere: se construiete un iterator pe list
pre: leL
post: i este un iterator pe lista l
distruge(l)
descriere: distruge o list
pre: leL
post: lista l a fost distrus

Reamintim modul n care va putea fi tiprit o list (ca orice alt container care poate fi
iterat) folosind iteratorul construit pe baza operaiei iterator din interfaa listei.

Subalgoritmul tiprire(l) este:
{pre: l este o list}
{post: se tipresc elementele listei}
iterator(l, i) {se obine un iterator pe lista l}
Cttimp valid(i) execut {ct timp iteratorul e valid}
element(i, e) {e este elementul curent referit de iterator}
@ tiprete e {se tiprete elementul curent}
urmtor(i) {iteratorul refer urmtorul element}
61
sfct
sf-tiprire

3.1.2. Stiva

In limbajul uzual cuvntul stiv refer o grmad n care elementele constitutive
sunt aezate ordonat unele peste altele. Un element nou se adaug n stiv deasupra
elementului cel mai recent adugat n stiv. Din stiv se poate accesa i extrage doar
elementul cel mai recent introdus. Exemple de stive sunt multiple: stiv de farfurii, stiv de
lemne, etc. Tipul de date Stiv permite implementarea n aplicaii a acestor situaii din
lumea real.
Stiva este o list liniar n care adugrile, tergerile i accesul se fac la un singur
capt al stivei, numit vrf. ntr-o stiv nu este permis accesul la elemente pe baza poziiei.
Accesul ntr-o stiv este prespecificat (se poate accesa doar elementul cel mai recent
introdus n stiv din vrful stivei). Dintr-o stiv se poate terge elementul cel mai recent
introdus n stiv cel din vrful stivei. Ca urmare, stiva implementeaz principiul ultimul
sosit, primul servit LIFO (Last In First Out).
Se poate considera i o capacitate iniial a stivei (numr maxim de elemente pe care le
poate include), caz n care dac numrul efectiv de elemente atinge capacitatea maxim,
spunem c avem o stiv plin. O stiv fr elemente o vom numi stiv vid. Dac se ncearc
extragerea unui element din stiva vid, vom spune c stiva are depire inferioar, iar n
cazul n care se ncearc adugarea unui element n stiva plin, vom spune c stiva are
depire superioar.
Vom da n continuare specificaia tipului abstract de date STIVA. Stiva vid o vom
nota cu |.

Tipul Abstract de Date STIVA

domeniu
S={s | s este o stiv cu elemente de tip TElement, s implementeaz principiul LIFO }

operaii (interfaa minimal)

creeaz(s)
descriere: creeaz o stiv vid
pre: adevrat
post: seS, | = s
adaug (s, e)
descriere: se adaug un element n vrful stivei
pre: seS, eeTelement, s nu e plin
post: seS, e a fost adugat n vrful stivei s (e va fi cel mai recent element
introdus n s)
terge (s, e)
descriere: se scoate un element din vrful stivei
pre: seS, | = s
62
post: seS, eeTElement, e este cel mai recent element introdus n s, s se
modific prin tergerea elementului din vrf
element (s, e)
descriere: se acceseaz elementul din vrful stivei
pre: seS, | = s
post: eeTElement, e este cel mai recent element introdus n s
vid(s)
descriere: funcie care verific dac stiva este vid
pre: seS
post: vid = adevrat n cazul n care s e stiva vid
fals n caz contrar
plin(s)
descriere: funcie care verific dac stiva este plin
pre: seS
post: plin = adevrat n cazul n care s e plin
fals n caz contrar
distruge(s)
descriere: distruge o stiv
pre: seS
post: stiva s a fost distrus

Avnd n vedere c nu este permis accesul la elementele din interiorul stivei, afiarea
coninutului stivei poate fi fcut doar dac privim stiva ca o list, adic: scoatem valorile din
stiv, afindu-le i punndu-le pe o stiv auxiliar, apoi repunndu-le pe stiva iniial. Ca
urmare, stiva nu este potrivit pentru aplicaiile care necesit traversarea ei, deoarece nu
avem acces direct la valorile interioare ale stivei.

3.1.3. Coada

n limbajul uzual cuvntul coad se refer la o niruire de oameni, maini, etc.,
aranjai n ordinea sosirii i care ateapt un eveniment sau serviciu. Noii sosii se
poziioneaz la sfritul cozii. Pe msur ce se face servirea, oamenii se mut cte o poziie
nainte, pn cnd ajung n fa i sunt servii, asigurndu-se astfel respectarea principiului
primul venit, primul servit. Exemple de cozi sunt multiple: coada de la benzinrii, coada
pentru cumprarea unui produs, etc. Tipul de date Coad permite implementarea n aplicaii
a acestor situaii din lumea real.
Coada este o list liniar n care adugrile se fac la un capt al cozii (numit spate),
iar accesul i tergerile se fac la cellat capt al cozii (numit fa). ntr-o coad nu este permis
accesul la elemente pe baza poziiei.
Accesul ntr-o coad este prespecificat (se poate accesa doar elementul cel mai
devreme introdus n coad elementul din fa). Dintr-o coad se poate terge elementul cel
mai devreme introdus n coad elementul din fa). Ca urmare, coada implementeaz
principiul primul sosit, primul servit FIFO (First In First Out).
Se poate considera i o capacitate iniial a cozii (numr maxim de elemente pe care le
poate include), caz n care dac numrul efectiv de elemente atinge capacitatea maxim,
63
spunem c avem o coad plin. O coad fr elemente o vom numi coad vid. Dac se
ncearc extragerea unui element din coada vid, vom spune c avem o depire inferioar,
iar n cazul n care se ncearc adugarea unui element n coada plin, vom spune c avem
depire superioar.
Vom da n continuare specificaia tipului abstract de date COADA. Coada vid o vom
nota cu |.

Tipul Abstract de Date COADA

domeniu

C={c | c este o coad cu elemente de tip TElement, c implementeaz principiul FIFO }

operaii (interfaa minimal)

creeaz(c)
descriere: creeaz o coad vid
pre: adevrat
post: ceC, | = c
adaug (c, e)
descriere: se adaug un element la sfritul cozii
pre: ceC, eeTelement,c nu e plin
post: ceC, e a fost adugat la sfritul cozii c, e va fi cel mai recent element
introdus n c
terge (c, e)
descriere: se extrage primul element din coad
pre: ceC, | = c
post: ceC , eeTElement, e este cel mai devreme element introdus n c, c se
modific prin tergerea acestui elementul
element (c, e)
descriere: se acceseaz elementul cel mai devreme introdus n coad
pre: ceC, | = c
post: eeTElement, e este elementul introdus n c cel mai devreme
vid(c)
descriere: funcie care verific dac n coad nu sunt elemente (este vid)
pre: ceC
post: vid = adevrat n cazul n care c e coada vid
fals n caz contrar
plin(c)
descriere: funcie care verific dac n coad nu se mai pot aduga
elemente (este plin)
pre: ceC
post: plin = adevrat n cazul n care c e plin
fals n caz contrar
distruge(c)
descriere: distruge o coad
64
pre: ceC
post: coada c a fost distrus



Avnd n vedere c nu este permis accesul la elementele din interiorul cozii, afiarea
coninutului cozii poate fi fcut doar dac privim coada ca o list, adic: scoatem valorile
din coad, punndu-le ntr-o coad auxiliar, apoi repunndu-le n coada iniial i afindu-
le. Ca urmare, coada nu este potrivit pentru aplicaiile care necesit traversarea ei, deoarece
nu avem acces direct la valorile interioare cozii.

3.1.4. Arbori

Arborii i variantele lor sunt printre cele mai comune i cele mai frecvent utilizate
structuri de date, fiind folosite ntr-o gam foarte variat de aplicaii cum ar fi teoria
compilrii, prelucrarea de imagini, etc., oferind o modalitate eficient de memorare i
manipulare a unei colecii de date.
In teoria grafurilor, un arbore este un graf neorientat conex i fr cicluri. Arborii
reprezint grafurile cele mai simple ca structur din clasa grafurilor conexe, ei fiind cel mai
frecvent utilizai n practic.
n informatic, cei mai utilizai sunt arborii cu rdcin. De aceea, termenul arbore
este asociat n informatic arborelui cu rdcin.
Dm n continuare o definiie recursiv a arborelui cu rdcin.

Un arbore cu rdcin este o mulime finit T cu 0 sau mai multe elemente numite
noduri, care are urmtoarele caracteristici:
- Dac T este vid, atunci arborele este vid.
- Dac T este nevid, atunci:
o Exist un nod special R numit rdcin.
o Celelalte noduri sunt partiionate n k (>0) arbori disjunci
k
T T T ,... ,
2 1
, nodul
R fiind legat de rdcina fiecrui
i
T ( k i s s 1 ) printr-o muchie. Arborii
k
T T T ,... ,
2 1
se numesc subarbori (fii) ai lui R, iar R se numete printele
subarborilor
i
T ( k i s s 1 ).

n contextul arborilor, avem o categorie special, numit arbori ordonai, care se
deosebete de arborii simpli prin faptul c fiii fiecrui nod se consider a forma o list i nu
doar o mulime, adic ordinea fiilor este bine definit i relevant.
Din categoria arborilor, o clas foarte important o constituie clasa arborilor binari.

Un arbore binar este un arbore ordonat n care fiecare nod poate s aib cel mult doi
subarbori. Mai exact, putem defini arborele binar ca avnd urmtoarele proprieti:
- Un arbore binar poate fi vid.
- ntr-un arbore binar nevid, fiecare nod poate avea cel mult doi fii (subarbori).
Subarborii sunt identificai ca fiind subarborele stng, respectiv subarborele
drept.

65
Deoarece un arbore oarecare ordonat poate fi transformat ntr-un arbore binar
echivalent, ne vom limita n ceea ce urmeaz la arborii binari. Foarte important este faptul c
ntr-un arbore binar se face o distincie clar ntre subarborele stng i cel drept.

Traversarea unui arbore binar const n parcurgerea, pe rnd, a nodurilor arborelui i
punerea n eviden a fiecrui nod al arborelui (spunem c vizitm nodul respectiv, prin
aceasta nelegnd efectuarea unor prelucrri ale informaiilor ataate nodului).
Amintim aici dou posibiliti de traversare a arborilor binari:
- n adncime;
- n lime (pe niveluri).
Traversarea n adncime poate fi specializat n parcurgerile cunoscute sub
denumirile:
- inordine;
- preordine;
- postordine.
Aceste denumiri sugereaz poziia rdcinii (n traversare) fa de cei doi descendeni
(respectiv ntre ei, naintea lor sau dup ei).
Pentru a parcurge n inordine (ordine simetric) un arbore binar nevid, se parcurge n
inordine subarborele stng, se viziteaz rdcina, apoi se parcurge n inordine subarborele
drept.
Pentru a parcurge n preordine un arbore binar nevid, se viziteaz rdcina, se
parcurge n preordine subarborele stng, apoi se parcurge n preordine subarborele drept.
Pentru a parcurge n postordine un arbore binar nevid, se parcurge n postordine
subarborele stng, se parcurge n postordine subarborele drept, apoi se viziteaz rdcina.
Pentru a parcurge n lime un arbore binar, se viziteaz nodurile pe niveluri, n ordine
de la stnga la dreapta: nodurile de pe nivelul 0, apoi nodurile de pe nivelul 1, nodurile de pe
nivelul 2, etc.

Vom da n continuare specificaia tipului abstract de date ArboreBinar. Arborele
binar vid l vom nota cu |.

Tipul Abstract de Date ArboreBinar

domeniu
AB={ab | ab este un arbore binar cu noduri care conin informaii de tip TElement}

operaii (interfaa minimal)

creeaz(ab)
descriere: se creeaz un arbore binar vid
pre: adevrat
post: abeAB, | = ab
creeazFrunz (ab, e)
descriere: se creeaz un arbore binar cu informaia din nodul rdcin dat i cei
doi subarbori vizi.
pre: eeTElement
post: abeAB, rdcina lui ab are informaia e, subarborii lui ab sunt vizi
creeazArb (ab, st, e, dr)
66
descriere: se creeaz un arbore binar cu informaia din nodul rdcin i cei doi
subarbori dai.
pre: eeTElement, steAB, dreAB
post: abeAB, rdcina lui ab are informaia e, subarborele stng al lui ab este
st, subarborele drept al lui ab este dr
adaugStng (ab, st)
descriere: se adaug subarborele stng al unui arbore.
pre: abeAB, steAB
post: abeAB, subarborele stng al lui ab devine st
adaugDrept (ab, dr)
descriere: se adaug subarborele drept al unui arbore.
pre: abeAB, dreAB
post: abeAB, subarborele drept al lui ab devine dr
element (ab)
descriere: funcie care returneaz informaia din rdcina unui arbore binar
pre: abeAB, | = ab
post: element= informaia din rdcina lui ab
stng(ab)
descriere: funcie care returneaz subarborele stng al unui arbore binar
pre: abeAB, | = ab
post: stang= subarborele stng al lui ab
drept(ab)
descriere: funcie care returneaz subarborele drept al unui arbore binar
pre: abeAB, | = ab
post: drept= subarborele drept al lui ab
vid(ab)
descriere: funcie care verific dac un arbore binar este vid
pre: abeAB
post: vid = adevrat n cazul n care ab e arborele vid
fals n caz contrar
iterator(ab, ordine, i)
descriere: se construiete un iterator pe arbore ntr-o ordine dat (preordine,
inordine, postordine, lime)
pre: abeAB, ordine={pre, in, post, lat}
post: i este un iterator pe arborele ab n ordinea dat de ordine
distruge(ab)
descriere: distruge un arbore binar
pre: abeAB
post: arborele ab a fost distrus

67

3.2. Identificarea structurilor de date potrivite n aplicaii

Pentru urmtoarele probleme, identificai cel mai potrivit tip abstract de date pentru
rezolvarea problemei (STIVA, COADA, LISTA, ArboreBinar). Folosind doar
operaiile din interfaa tipului identificat (fcnd abstracie de implementarea sa propriu-zis),
scriei o aplicaie pentru rezolvarea problemei.

1. Evaluarea unei expresii aritmetice din forma polonez postfixat. Forma polonez
postfixat este o form de reprezentare a expresiilor aritmetice n care fiecare operator
aritmetic este scris dup operanzii si.

Fie EPost o expresie aritmetic corect n forma postfixat, coninnd operatorii binari:
+, -, *, /, iar ca operanzi cifrele de la 0 la 9 (ex: EPost=1 2 + 3 * 4 /). Se cere s se
determine valoarea expresiei (ex: valoarea este 2.25).

Indicaie: Se va folosi o STIV n care se vor aduga operanzii. n final, stiva va conine
valoarea expresiei.

Vom putea folosi urmtorii pai n rezolvare.

- Pentru fiecare EPost e e (n ordine de la stnga la dreapta)
i. Dac e este operand, atunci se adaug n stiv
ii. Dac e este operator, atunci se scot din stiv doi operanzi (
1
op i
2
op ), se
efectueaz operaia e ntre cei doi operanzi (
1 2
op e op v = ), dup care se
adaug v n stiv.
- n presupunerea noastr c expresia n forma postfixat este valid, n final, stiva va
conine o singur valoare, care se va extrage din stiv. Aceast valoare reprezint
valoarea expresiei.

2. Translatarea unei expresii aritmetice din forma polonez infixat n forma polonez
postfixat. Forma polonez infixat este forma uzual de reprezentare a expresiilor
aritmetice n care fiecare operator aritmetic binar este scris ntre operanzii si.

Fie E o expresie aritmetic corect n forma infixat, fr paranteze, coninnd
operatorii binari: +, -, *, /, iar ca operanzi cifrele de la 0 la 9 (ex: E=1 + 2 * 3). Se cere s
se determine forma postfixat EPost a expresiei (ex: EPost=1 2 3 * +).

Indicaie: Se va folosi o STIV n care se vor aduga operatorii i o COAD EPost care
va conine n final forma postfixat a expresiei.

Vom putea folosi urmtorii pai n rezolvare.

- Pentru fiecare E e e (n ordine de la stnga la dreapta)
i. Dac e este operand, atunci se adaug n coada EPost.
68
ii. Dac e este operator, atunci se scot din stiv operatorii avnd prioritatea de
evaluare mai mare sau egal dect a lui e i se adaug n coada Epost, dup
care se adaug e n stiv
- Se scot din stiv operatorii rmai i se adaug n coada EPost.
- In final, EPost va conine forma postfixat a expresiei.

3. Aceeai problem ca i cea anterioar, dar expresia n forma infixat conine paranteze
(ex: E= (1+2)*3).

Indicaie: Ideea/algoritmul de baza este aceeai ca i n cazul n care expresia nu ar
conine paranteze. Paranteza deschis ( se va aduga n stiv. Vor trebui identificai
paii care vor trebui efectuai la ntlnirea unei paranteze nchise ).

4. ntr-o bibliotec sunt mai multe teancuri de reviste. Bibliotecarul vrea s pun pe un raft
doar revistele cu anul de apariie > 1970. El va lua pe rnd revistele din vrful fiecrui
teanc i va pune revistele cu anul de apariie > 1970 pe raft, una lng cealalt,
completnd raftul de la stnga spre dreapta. Afiai revistele n ordinea n care
bibliotecarul le va pune pe raft.

Indicaie: Pentru a memora un teanc de reviste vom folosi o STIV, iar pentru
memorarea raftului nou creat vom folosi o COAD.

5. Un profesor dorete s dea un test gril unei grupe de studeni. Ca urmatre, introduce
testul gril constnd dintr-o list de ntrebri. Fiecare ntrebare are trei variante de rspuns
(a, b, c). Scriei o aplicaie care s ofere urmtoarele:

- Studenii vin i dau testul.
- Profesorul corecteaz testul.
- Vizualizeaz rezultatele evalurii.

Indicaie: Pentru a memora datele vom folosi LISTA.


6. Se dorete gestionarea informaiilor despre studenii din diferite faculti ale UBB. Scriei
o aplicaie care s ofere urmtoarele:

- Lista celor mai buni 100 studeni (considernd media lor general).
- Lista coninnd studentul cu media cea mai mare din fiecare facultate a
universitii.

Indicaie: Pentru a memora datele vom folosi LISTA.


7. S se construiasc un arbore genealogic care reprezint strmoii unei persoane pn la
generaia a n-a, arborescena stng reprezentnd linia matern, iar cea dreapt linia
patern. S se afieze toi strmoii de ordin k ai persoanei din rdcina arborelui.

Indicaie: Pentru a memora datele vom folosi ArboreBinar.

69
8. S se construiasc arborele binar ataat unei expresii aritmetice coninnd operatorii
binari: +, -, *, /, pornind de la forma polonez postfixat corect EPost.

Exemplu: Expresia 5*(7-2)+(4*3-1)/6 are forma postfixat:

5 7 2 - * 4 3 * 1 6 / +

i arborele binar ataat:



Indicaie: Se va folosi un ArboreBinar care se va construi ntr-o manier bottom-
up, adic pornind de la frunze spre rdcin. Se va folosi o STIV n care se vor aduga
(sub)arborii pe msur ce se vor construi. n final, n stiv va fi ntreg arborele.

Vom putea folosi urmtorii pai n rezolvare.

- Pentru fiecare EPost e e (n ordine de la stnga la dreapta)
i. Dac e este operand, atunci se construiete un arbore a crui rdcin l
conine pe e , iar cei doi fii sunt arbori nuli. Se adaug arborele construit n
stiv.
ii. Dac e este operator, atunci se va construi un arbore a crui rdcin l
conine pe e , fiul drept este ultimul arbore introdus n stiv, iar fiul stng este
penultimul arbore introdus n stiv. Se adaug arborele construit n stiv.
- In presupunerea noastr c expresia n forma postfixat este corect, n final, stiva va
conine arborele binar corespunztor expresiei aritmetice.

9. Se d un ir de paranteze. Se cere s se verifice dac parantezele se nchid corect. De
exemplu: (()()) se nchid corect, ())(() nu se nchid corect.

Indicaie: Se va folosi o STIVA.

10. Se d un text care conine litere, paranteze rotunde, paranteze drepte i acolade. Se cere s
se verifice dac n text parantezele se nchid corect. De exemplu n textul {a= (2 +
b[3])*5;} parantezele se nchid corect. n textul { a = (b[0) . 1]; } parantezele nu se nchid
corect.

Indicaie: Se va folosi o STIVA.


70
11. Un server HTTP primete cereri de la diveri clieni. S se simuleze procesul de rezolvare
a cererilor. Se vor afia cererile n ordinea n care serverul le rezolv.

Indicaie: Se va folosi o COADA.

12. S se simuleze urmtorul joc de cri. Doi juctori primesc iniial
2
n
cri de joc (fiecare
carte poate avea culoarea roie sau neagr). Juctorii pun alternativ cte o carte pe mas
(din vrful teancului lor de cri), pn se pune o carte roie (caz n care teancul de pe
mas va fi luat de ctre adversarul juctorului care a pus cartea roie i adugat sub
teancul su de cri). Pierde juctorul care nu mai are cri.

Indicaie: Teancurile celor doi juctori sunt COZI, iar teancul de pe mas este o
STIVA.

13.
n acest labirint. Robotul se poate deplasa n 4 direcii: N, S, E, V.
a). Testai dac R poate iei din labirint (poate ajunge la margine).
b). Determinai un drum pentru ieire (dac exist).

Indicaie:

Fie T mulimea poziiilor n care robotul poate ajunge pornind de la poziia iniial.
Notm cu S mulimea poziiilor n care robotul a ajuns pn la un moment dat i din care
s-ar putea deplasa. Un algoritm pentru determinarea mulimilor T i S ar putea fi:

T := {poziia iniial}
S := {poziia iniial}
Cttimp S =| execut
Fie p un element din S
S := S \ { p}
Pentru fiecare poziie q alturat poziiei p, q = 'X' i q eT
execut
S := S {q}
T := T {q}
Sfpentru
Sfct

- Pentru a rspunde la punctul a), algoritmul s-ar putea termina dac poziia q care
satisface condiiile este pe frontiera labirintului.
- Mulimea T poate fi memorat printr-o matrice asociat labirintului (ex: 0 pentru
poziiile neatinse nc, respectiv 1 pentru poziiile n care robotul a ajuns).
- Structura S poate fi o STIVA sau o COADA.

14. Se d o secven ce conine numere raionale sub forma x/y i caracterele (, ,, ;, ),
$ cu semnificaia:
- numrul x/y reprezint informaia din nod;
- ( definete un nivel inferior;
- , separ arborescena stng de cea dreapt;
- ) sfrit nivel inferior;
- $ lipsete ramura corespunztoare.
71
S se construiasc arborele binar ataat secvenei:

Exemplu: Pentru secvena ( ) ( ) ( ) 1/9 , 3/2 $, 1/6 3/4, 2/3 1/2 se creeaz arborele binar:


Indicaie: Se va folosi ArboreBinar.
72

4. Baze de date

- Baze de date relaionale. Primele trei forme normale ale unei relaii
- Gestiunea bazelor de date relaionale cu SQL
- Interogarea bazelor de date cu operatori din algebra relaional
- Interogarea bazelor de date relaionale cu SQL

4.1. Baze de date relaionale

4.1.1. Modelul relaional

Modelul relaional de organizare a bazelor de date a fost introdus de E.F.Codd n 1970
i este cel mai studiat i mai mult folosit model de organizare a bazelor de date. In continuare
se va face o scurt prezentare a acestui model.
Fie A
1
, A
2
, ..., A
n
o mulime de atribute (coloane, constituani, nume de date, etc.) i
{?} )
i
Dom(A
i
D = domeniul valorilor posibile pentru atributul A
i
, unde prin ? s-a
notat valoarea de nedefinit (null). Valoarea de nedefinit se folosete pentru a verifica dac
unui atribut i s-a atribuit o valoare sau el nu are valoare (sau are valoarea nedefinit).
Aceast valoare nu are un anumit tip de dat, se pot compara cu aceast valoare atribute de
diferite tipuri (numerice, iruri de caractere, etc.).
Plecnd de la mulimile astfel introduse, se poate defini o relaie de gradul n sub
forma urmtoare:
, ...
2 1 n
D D D R _
i poate fi considerat ca o mulime de vectori cu cte n valori, cte o valoare pentru fiecare
din atributele A
i
. O astfel de relaie se poate memora printr-un tabel de forma:

R A
1
... A
i
.. A
n
r
1
a
11
... a
1j
... a
1n
... ... ... ... ... ...
r
i
a
i1
... a
ij
... a
in
... ... ... ... ... ...
r
m
a
m1
... a
mj
... a
mn

unde liniile din acest tabel formeaz elementele relaiei, sau tupluri, sau nregistrri, care
n general sunt distincte, i . ,..., 1 , ,..., 1 , m i n j D a
j ij
= = e Deoarece modul n care se
evideniaz elementele relaiei R de mai sus seamn cu un tabel, relaia se mai numete i
73
tabel. Pentru a pune n eviden numele relaiei (tabelului) i lista atributelor vom nota
aceast relaie cu:
| |
n
A A A R ,..., ,
2 1
.
Modelul relaional al unei baze de date const dintr-o colecie de relaii ce variaz n
timp (coninutul relaiilor se poate schimba prin operaii de adugare, tergere i actualizare).
O baz de date relaional const din trei pri:
1. Datele (relaii sau tabele, legturi ntre tabele) i descrierea acestora;
2. Reguli de integritate (pentru a memora numai valori corecte n relaii);
3. Operatori de gestiune a datelor.
Exemplul 1. STUDENTI [NUME, ANUL_NASTERII, ANUL_DE_STUDIU],
cu urmtoarele valori posibile:

NUME ANUL_NASTERII ANUL_DE_STUDIU
Pop Ioan 1979 4
Barbu Ana 1981 2
Dan Radu 1980 3
Exemplul 2. CARTE [AUTORI, TITLU, EDITURA, AN_APARITIE],
cu valorile:
AUTORI TITLU EDITURA AN_APARITIE
Date, C.J. An Introduction to Database
Systems
Addison-Wesley
Publishing Comp.
1995
Ghosh, S.P. Data Base Organization for
Data Management
Academic Press 1977
Helman, P. The Science of Database
Management
Irwin, SUA 1994
Ramakrishnan, R. Database Management
Systems
McGraw-Hill 1998
Pentru fiecare relaie se poate preciza un atribut sau o colecie de atribute, din cadrul
relaiei, numit cheie, cu rol de identificare a elementelor relaiei (cheia ia valori diferite
pentru nregistrri diferite din relaie, deci fiecare nregistrare se poate identifica prin
valoarea cheii). Dac se d cte o valoare pentru atributele din cheie, se poate determina linia
(una singur) n care apar aceste valori. Se presupune c nici o submulime de atribute din
cheie nu este cheie. Deoarece toate elementele relaiei sunt diferite, o cheie exist totdeauna
(n cel mai ru caz cheia este format din toate atributele relaiei). Pentru exemplul 1 se poate
alege NUME ca i cheie (atunci n baza de date nu pot exista doi studeni cu acelai nume),
iar pentru exemplul 2 se poate alege grupul de atribute {AUTORI, TITLU, EDITURA,
AN_APARITIE} ca i cheie.
Pentru anumite relaii pot fi alese mai multe chei. Una dintre chei (un atribut sau un
grup de atribute) se alege cheie principal (primar), iar celelalte se vor considera chei
secundare (chei candidat). Sistemele de gestiune a bazelor de date nu permit existena a
dou elemente distincte ntr-o relaie cu aceeai valoare pentru oricare cheie (principal sau
secundar), deci precizarea unei chei constituie o restricie pentru baza de date.
Exemplul 3. ORAR [ZI, ORA, SALA, PROFESOR, CLASA, DISCIPLINA],
74
cu orarul pe o sptmn. Se pot alege ca i chei urmtoarele mulimi de atribute:
{ZI, ORA, SALA}; {ZI, ORA, PROFESOR}; {ZI, ORA, CLASA}.

4.1.2. Primele trei forme normale ale unei relai

In general anumite date se pot reprezenta n mai multe moduri prin relaii (la modelul
relaional). Pentru ca aceste date s se poat prelucra ct mai simplu (la o operaie de
actualizare a datelor s nu fie necesare teste suplimentare) este necesar ca relaiile n care se
memoreaz datele s verifice anumite condiii (s aib un anumit nivel de normalizare).
Pn n prezent se cunosc mai multe forme normale pentru relaii, dintre care cinci
sunt mai cunoscute: 1NF, 2NF, 3NF, 4NF, 5NF. Aceste forme normale au fost definite de
ctre Codd (primele trei) i Fagin (formele 4NF i 5NF). Avem urmtoarele incluziuni pentru
relaii n diferite forme normale:


Dac o relaie nu este de o anumit form normal, atunci ea se poate descompune n
mai multe relaii de aceast form normal respectiv.
Definiie. Pentru descompunerea unei relaii se folosete operatorul de proiecie. Fie
| |
n
A A A R ,..., ,
2 1
o relaie i { }
p
i i i
A A A ,..., ,
2 1
= o o submulime de atribute,
{ }
n
A A A ,..., ,
2 1
c o . Prin proiecia relaiei R pe se nelege relaia:
| |
{ }
, ) ( ) ( ,..., , '
,..., ,
2 1
2 1
[ [
= =
p
i i i
p A A A
i i i
R R A A A R
o
,
unde:
( ) | | ( ) ' ,..., , ) ( ,..., ,
2 1
2 1
R a a a r r R a a a r
p
i i i n
e = = e =
[
o
o
,
i toate elementele din R' sunt distincte.
Definiie. Pentru compunerea relaiilor se folosete operatorul de join natural. Fie
| | | o , R , | | | , S dou relaii peste mulimile de atribute | o , , , = o . Prin joinul
natural al relaiilor R i S se nelege relaia:
( ) { }. ) ( ) ( , ) ( , ) ( ), ( ] , , [
[ [ [ [ [
= e e = -
| | o
| o s r si S s R r s r r S R
1NF
2NF
3NF
4NF
5NF
75
O relaie R se poate descompune n mai multe relaii noi
m
R R R ,..., ,
2
1
. Aceast
descompunere este bun dac
m
R R R R - - - = ...
2
1
, deci datele din R se pot regsi din datele
memorate n relaiile
m
R R R ,..., ,
2
1
i nu apar date noi prin aceste operaii de compunere.
Exemplu de descompunere care nu este bun: fie relaia:
ContracteStudiu[Student,CadruDidactic, Disciplina],
i dou noi relaii obinute prin proiecia acestei relaii: SC[Student,CadruDidactic] i
CD[CadruDidactic, Disciplina]. Presupunem c pentru relaia iniial avem urmtoarele
valori:

R Student CadruDidactic Disciplina
r
1
s1 c1 d1
r
2
s2 c2 d2
r
3
s1 c2 d3
Folosind definiia proieciei se obin urmtoarele valori pentru cele dou relaii obinute
din R i pentru joinul natural al acestor relaii:
SC Student CadruDidactic
r
1
s1 c1
r
2
s2 c2
r
3
s1 c2

CD CadruDidactic Disciplina
r
1
c1 d1
r
2
c2 d2
r
3
c2 d3

SC*CD Student CadruDidactic Disciplina

s1 c1 d1

s2 c2 d2

s2 c2 d3

s1 c2 d2

s1 c2 d3
Se observ c n relaia SC*CD se obin nregistrri suplimentare fa de relaia iniial, deci
descompunerea sugerat nu este bun.
Observaie. Prin atribut simplu vom nelege un atribut oarecare din relaie, iar prin
atribut compus vom nelege o mulime de atribute (cel puin dou) din relaie.
Este posibil ca n diverse aplicaii practice s apar atribute (simple sau compuse) ce
iau mai multe valori pentru un element din relaie. Aceste atribute formeaz un atribut
repetitiv.
Exemplul 4. Fie relaia:
STUDENT [NUME, ANULNASTERII, GRUPA, DISCIPLINA, NOTA],
76
cu atributul NUME ca i cheie. In acest exemplu perechea {DISCIPLINA, NOTA} este un
grup repetitiv. Putem avea urmtoarele valori n aceast relaie:
NUME ANULNASTERII GRUPA DISCIPLINA NOTA
Pop Ioan 1982 221 Baze de date
Sisteme de operare
Probabiliti
10
9
8
Murean Ana 1981 222 Baze de date
Sisteme de operare
Probabiliti
Proiect individual
8
7
10
9
Exemplul 5. Fie relaia:
CARTE [Cota, NumeAutori, Titlu, Editura, AnApariie, Limba, CuvinteCheie],
cu atributul Cota ca i cheie i atributele repetitive NumeAutori i CuvinteCheie. Atributul
COTA poate avea o semnificaie efectiv (s existe o cot asociat la fiecare carte) sau s fie
introdus pentru existena cheii (valorile, distincte, s fie generate automat).
Grupurile repetitive creaz foarte multe greuti n memorarea diverselor relaii i din
aceast cauz se ncearc evitarea lor, fr ns a pierde date. Dac R[A] este o relaie, unde
A este mulimea atributelor, iar formeaz un grup repetitiv (atribut simplu sau compus),
atunci R se poate descompune n dou relaii fr ca s fie atribut repetitiv. Dac C este o
cheie pentru relaia R, atunci cele dou relaii n care se descompune relaia R sunt:
| | ( )
[

=
o
o
C
R C R' i | | ( )
[

=
o
o
A
R A R ' ' .
Exemplul 6. Relaia STUDENT din exemplul 4 se descompune n urmtoarele dou
relaii:
DATE_GENERALE [NUME, ANULNASTERII, GRUPA],
REZULTATE [NUME, DISCIPLINA, NOTA].
Exemplul 7. Relaia CARTE din exemplul 5 se descompune n urmtoarele trei relaii
(n relaia CARTE exist dou grupuri repetitive):
CARTI [Cota, Titlu, Editura, AnApariie, Limba],
AUTORI [Cota, NumeAutori],
CUVINTE_CHEIE [Cota, CuvntCheie].
Observaie. Dac o carte nu are autori sau cuvinte cheie asociate, atunci ea va avea
cte o nregistrare n relaiile AUTORI sau CUVINTE_CHEIE n care al doilea atribut are
valoarea null. Dac se dorete eliminarea acestor nregistrri, atunci relaia CARTE nu se va
putea obine din cele trei relaii numai prin join natural (sunt necesari operatori de join
extern).
Definiie. O relaie este de prima form normal (1NF) dac ea nu conine grupuri
(de atribute) repetitive.
Sistemele de gestiune a bazelor de date relaionale permit descrierea numai a relaiilor
ce se afl n 1NF. Exist i sisteme de gestiune ce permit gestiunea relaiilor non-1NF
(exemplu Oracle, unde o coloan poate fi un obiect sau o colecie de date).
Urmtoarele dou forme normale ale unei relaii utilizeaz o noiune foarte important,
i anume dependena funcional dintre diverse submulimi de atribute. Stabilirea
dependenelor funcionale este o sarcin a administratorului bazei de date i depinde de
77
semnificaia (semantica) datelor ce se memoreaz n relaie. Operaiile de actualizare a
datelor din relaie (nserare, tergere, modificare) nu trebuie s modifice dependenele
funcionale (dac pentru relaie exist astfel de dependene).
Definiie. Fie | |
n
A A A R ,..., ,
2 1
o relaie i { }
n
A A A ,..., , ,
2 1
c | o dou submulimi de
atribute. Atributul (simplu sau compus) | este dependent funcional de atributul o (simplu
sau compus), notaie: | o , dac i numai dac fiecare valoare a lui o din R are asociat
o valoare precis i unic pentru | (aceast asociere este valabil tot timpul existenei
relaiei R). O valoare oarecare a lui o poate s apar n mai multe linii ale lui R i atunci
fiecare dintre aceste linii conine aceeai valoare pentru atributul | , deci ( ) ( )
[ [
=
o o
' r r
implic ( ) ( )
[ [
=
| |
' r r .
Valoarea o din implicaia (dependena) | o se numete determinant, iar | este
determinat.
- Dependena funcional se poate folosi ca o proprietate (restricie) pe care baza de date
trebuie s o ndeplineasc pe perioada existenei acesteia: se adaug elemente n relaie
numai dac dependena funcional este verificat.
Existena unei dependene funcionale ntr-o relaie nseamn c anumite asocieri de
valori se memoreaz de mai multe ori, deci apare o redundan. Pentru exemplificarea unor
probleme care apar vom lua relaia urmtoare, care memoreaz rezultatele la examene pentru
studeni:
Exemplul 8. EXAMEN [NumeStudent, Disciplina, Nota, CadruDidactic],
unde cheia este {NumeStudent, Disciplina}. Deoarece unei discipline i corespunde un singur
cadru didactic, iar unui cadru didactic pot s-i corespund mai multe discipline, putem cere ca
s fie ndeplinit restricia (dependena) {Disciplina} {CadruDidactic}.
Examen NumeStudent Disciplina Nota CadruDidactic
1

Alb Ana Matematic 10 Rus Teodor
2

Costin Constantin Istorie 9 Popa Horea
3

Alb Ana Istorie 8 Popa Horea
4

Enisei Elena Matematic 9 Rus Teodor
5

Frian Florin Matematic 10 Rus Teodor
Dac pstrm o astfel de dependen funcional, atunci pot apare urmtoarele probleme:
- Risip de spaiu: aceleai asocieri se memoreaz de mai multe ori. Legtura dintre
disciplina de Matematic i profesorul Rus Teodor este memorat de trei ori, iar dintre
disciplina Istorie i profesorul Popa Horea se memoreaz de dou ori.
- Anomalii la actualizare: schimbarea unei date ce apare ntr-o asociere implic efectuarea
acestei modificri n toate asocierile (fr a se ti cte astfel de asocieri exist), altfel baza
de date va conine erori (va fi inconsistent). Dac la prima nregistrare se schimb
valoarea atributului CadruDidactic i nu se face aceeai modificare i la nregistrrile 4 i
5, atunci modificarea va introduce o eroare n relaie.
- Anomalii la nserare: la adugarea unei nregistrri trebuie s se cunoasc valorile
atributelor, nu se pot folosi valori nedefinite pentru atributele implicate n dependenele
funcionale.
78
- Anomalii la tergere: la tergerea unor nregistrri se pot terge i asocieri (ntre valori)
ce nu se pot reface. De exemplu, dac se terg nregistrrile 2 i 3, atunci asocierea dintre
Disciplina i CadruDidactic se pierde.
Anomaliile de mai sus apar datorit existenei unei dependene funcionale ntre
mulimi de atribute. Pentru a elimina situaiile amintite trebuie ca aceste dependene
(asocieri) de valori s se pstreze ntr-o relaie separat. Pentru aceasta este necesar ca relaia
iniial s se descompun, fr ca prin descompunere s se piard date sau s se introduc
date noi prin compunerea de relaii (trebuie ca descompunerea "s fie bun"). O astfel de
descompunere se face n momentul proiectrii bazei de date, cnd se pot stabili dependenele
funcionale.
Observaii. Se pot demonstra uor urmtoarele proprieti simple pentru dependenele
funcionale:
1. Dac C este o cheie pentru | |
n
A A A R ,..., ,
2 1
, atunci { }
n
A A A C ,..., , ,
2 1
c | | .
2. Dac o | _ , atunci | o , numit dependena funcional trivial sau refelxivitatea.
| o
| |
o |
o o
H = H H = H
c
) ( ) ( ) ( ) (
2 1 2 1
r r r r
3. Dac | o , atunci | , cu o c .
|
| |
| o
o o
o

H = H H = H H = H
c
) ( ) ( ) ( ) ( ) ( ) (
2 1 2 1 2 1
r r r r r r
4. Dac | o i | , atunci o , care este proprietatea de tranzitivitate a
dependenei funcionale.
o

|
| |
| o
o o
H = H H = H H = H

) ( ) ( ) ( ) ( ) ( ) (
2 1 2 1 2 1
r r r r r r
5. Dac | o i A c , atunci | o , unde o o = .
) ( ) (
) ( ) (
) ( ) ( ) ( ) (
) ( ) (
2 1
2 1
2 1 2 1
2 1
r r
r r
r r r r
r r
| |

| | o o
o o
H = H
H = H
H = H H = H
H = H
Relativ la o relaie R[A] i o mulime F de dependene funcionale apar urmtoarele trei
probleme:
I. Determinarea nchiderii mulimii F de dependene funcionale. Pentru mulimea
F de dependene funcionale se cere determinarea mulimii F
+
, numit nchiderea mulimii
F, i care conine toate dependenele funcionale obinute logic din F. Mulimea F de
dependene funcionale implic logic o dependen funcional f dac pentru orice relaie n
care F este ndeplinit rezult c i f este ndeplinit.
Pentru determinarea nchiderii F
+
se pot aplica repetat urmtoarele trei reguli (axiomele
lui Armstrong):
1. Reflexivitatea: dac A c o i o | c , atunci | o .
2. Mrirea: dac | o i A c , atunci | o (unde s-a notat o o = ).
3. Tranzitivitatea: dac | o i | , atunci o .
Aceste reguli sunt complete (determin nchiderea) i logice (nu determin dependene
funcionale eronate).
Plecnd de la aceste reguli se poate demonstra c i urmtoarele reguli sunt adevrate:
4. Reuniunea: dac | o i o , atunci | o .
79
| o
| o| o
o| oo | o
o



=
tate tranzitivi
marire
marire

5. Descompunerea: dac | o , atunci | o i o .
| o
| |
| o

)
`


tate tranzitivi
ate reflexivit ) (

6. Pseudotranzitivitatea: dac | o i o | , atunci o o .
o o
o |
| o | o

)
`


tate tranzitivi

Exemplul 9. Fie A={A, B, C, D, E, F}, F={A B, A C, CD E, CD F, D E}.
In F
+
mai trebuie incluse, pe lng elementele din F, cel puin urmtoarele dependene:
A E (prin tranzitivitate),
CD EF (prin regula 4),
AD F (A C, AD CD din regula 2, CD F, i tranzitivitate),
AD E (analog ca mai sus),
A BC (prin regula 4).
II. Inchiderea unei mulimi de atribute sub o mulime de dependene funcionale.
Fie o submulime de atribute i F o mulime de dependene funcionale. Se pune problema
determinrii nchiderii lui (notat
+
) sub F i care conine mulimea atributelor
dependente funcional de atribute din . Pentru determinarea acestei nchideri se poate folosi
urmtorul algoritm:
inchidere := ;
while (inchidere se schimb) do
for fiecare dependen funcional | din F do
if c | inchidere then inchidere := inchidere .
Se poate demonstra c algoritmul este corect i determin
+
. Acest algoritm are o
complexitate foarte mare, proporional cu exponeniala lui |F| (|F| = numrul de elemente din
F).
Exemplul 10. Pentru { } D A, = o i F dat n exemplul precedent se obine:
A B
+
e o B ;
A C
+
e o C ;
CD E
+
e o E ;
CD F
+
e o F ;
deci { } { } F E D C B A D A , , , , , , = =
+ +
o .
III. Acoperire minimal de dependene funcionale.
Definiie. Dou mulimi de dependene funcionale F i G sunt echivalente (notaie
F G) dac F
+
=G
+
(deci nchiderile lor coincid).
80
Definiie. Fie F o mulime de dependene funcionale. Prin acoperirea minimal a
mulimii F se nelege o mulime de dependene funcionale, notat cu F
M
, care verific
urmtoarele condiii:
1. F
M
F;
2. Partea dreapt a fiecrei dependene funcionale din F
M
este format dintr-un singur
atribut;
3. Partea stng a fiecrei dependene funcionale din F
M
este redus ct mai mult posibil:
dac F e | o i o o c ' , atunci { } ( ) ( ) | o | o = '
'
F F
M
nu este echivalent
cu F
4. Nici o dependen funcional f din F
M
nu este redundant, deci (F
M
-f) nu este echivalent
cu F
M
.
Exemplul 11. Considerm relaia R [A, B, C, D, E, F] i mulimea de dependene
F={A B, B C, AB D, B EF}. Pentru a determina acoperirea minimal a mulimii F
vom analiza dependenele din F care nu se pot include n F
M
i dependenele noi care se obin
din cele deja determinate:
- B EF nu ndeplinete condiia 2, aceast dependen se nlocuiete cu B E i B F;
- A B, AB D implic prin pseudotranzitivitate dependena A D;
- Dependena anterioar (A D) implic faptul c AB D nu ndeplinete condiia 3;
- Dependena A C nu ndeplinete condiia 4 deoarece se obine din A B i B C.
Definiie. Un atribut A (simplu sau compus) se numete prim dac exist o cheie C i
Ac C (C este o cheie compus, sau A este chiar o cheie a relaiei). Dac un atribut nu este
inclus n nici o cheie, atunci se numete neprim.
Definiie. Fie | |
n
A A A R ,..., ,
2 1
i { }
n
A A A ,..., , ,
2 1
c | o . Atributul | este complet
dependent funcional de o dac | este dependent funcional de o (deci | o ) i nu
este dependent funcional de nici o submulime de atribute din o ( | o o c , nu este
adevrat).
Observaie. Dac atributul | nu este complet dependent funcional de o , atunci
o este un atribut compus.
Definiie. O relaie este de a doua form norml (2NF) dac:
- este de prima form normal,
- orice atribut neprim (simplu sau compus) (deci care nu este inclus ntr-o cheie) este
complet dependent funcional de oricare cheie a relaiei.
Observaie. O relaie ce este de prima form normal (1NF) i nu este de a doua form
normal (2NF), atunci are o cheie compus. Dac o relaie nu este de a doua form normal,
atunci exist o dependen funcional | o cu o atribut (simplu sau compus) inclus ntr-
o cheie.
Pentru a preciza modul de descompunere pentru cazul general, fie | |
n
A A A R ,..., ,
2 1
o
relaie i { }
n
A A A A C ,..., ,
2 1
= c o cheie. Presupunem c exist A c | , = C | ( | este
un atribut necheie), | dependent funcional de C c o ( | este complet dependent
funcional de o submulime strict de atribute din cheie). Dependena | o se poate
elimina dac relaia R se descompune n urmtoarele dou relaii:
81
| | ( )
| |
[

=
| o
| o R R' i | | ( )
[

=
|
|
A
R A R ' ' .
Vom analiza relaia din exemplul 8:
EXAMEN [NumeStudent, Disciplina, Nota, CadruDidactic],
unde cheia este {NumeStudent, Disciplina} i exist dependena funcional (restricia)
{Disciplina} {CadruDidactic}. De aici deducem c atributul CadruDidactic nu este
complet dependent funcional de o cheie, deci relaia EXAMEN nu este de a doua form
normal. Eliminarea acestei dependene funcionale se poate face prin descompunerea relaiei
n urmtoarele relaii:
APRECIERI [NumeStudent, Disciplina, Nota];
STAT_FUNCTII [Disciplina, CadruDidactic].
Exemplul 12. Presupunem c pentru memorarea contractelor de studiu se folosete
relaia:
CONTRACTE[CNP, Nume, Prenume, CodDisciplina, DenumireDisciplina].
Cheia relaiei este {CNP,CodDisciplina}. In relaie mai exist dou dependene funcionale:
{CNP} {Nume, Prenume} i {CodDisciplina} {DenumireDisciplina}. Pentru eliminarea
acestor dependene se descompune relaia n urmtoarele:
STUDENTI [CNP, Nume, Prenume],
INDRUMATORI [CodDisciplina, DenumireDisciplina],
CONTRACTE [CNP, CodDisciplina].
Pentru a treia form normal este necesar noiunea de dependen tranzitiv.
Definiie. Un atribut Z este tranzitiv dependent de atributul X dac - Y nct X Y,
Y Z, iar Y X nu are loc i Z nu este inclus n Y X .
Definiie. O relaie este de a treia form normal (3NF) dac este 2NF i orice
atribut neprim nu este tranzitiv dependent de oricare cheie a relaiei.
Dac C este o cheie i | un atribut tranzitiv dependent de cheie, atunci exist un
atribut o care verific: o C (dependen care este verificat totdeauna) i | o .
Deoarece relaia este 2NF, obinem c | este complet dependent de C, deci C . o . De aici
deducem c o relaie ce este 2NF i nu este 3NF are o dependen | o , iar o este atribut
neprim. Aceast dependen se poate elimina prin descompunerea relaiei R n mod
asemntor ca la eliminarea dependenelor de la 2NF.
Exemplul 13. Rezultatele obinute de absolveni la lucrarea de licen sunt trecute n
relaia:
LUCRARI_LICENTA [NumeAbsolvent, Nota, CadruDidIndr, Catedra].
Aici se memoreaz numele cadrului didactic ndrumtor i denumirea catedrei la care se afl
acesta. Deoarece se introduc date despre absolveni, cte o nregistrare pentru un absolvent,
putem s stabilim c NumeAbsolvent este cheia relaiei. Din semnificaia atributelor incluse n
relaie se observ urmtoarea dependen funcional:
{CadruDidIndr} {Catedra}.
Din existena acestei dependene funcionale se deduce c relaia nu este de 3NF.
Pentru a elimina dependena funcional, relaia se poate descompune n urmtoarele dou
relaii:
82
REZULTATE [NumeAbsolvent, Nota, CadruDidIndr]
INDRUMATORI [CadruDidIndr, Catedra].
Exemplul 14. Presupunem c adresele unui grup de persoane se memoreaz n urmtoarea
relaie:
ADRESE [CNP, Nume, Prenume, CodPostal, DenumireLocalitateDomiciliu, Strada, Nr].
Cheia relaiei este {CNP}. Deoarece la unele localiti codul potal se stabilete la nivel de
strad, sau chiar poiuni de strad, exist dependena funcional:
{CodPostal} {DenumireLocalitateDomiciliu}. Deoarece exist aceast dependen
funcional, deducem c relaia ADRESE nu este de a treia form normal, deci este necesar
descompunerea ei.
Exemplul 15. S considerm urmtoarea relaie care memoreaz o eventual planificare a
studenilor pentru examene:
PLANIFICARE_EX [Data, Ora, Cadru_did, Sala, Grupa],
cu urmtoarele restricii (cerine care trebuie respectate) care se transpun n definirea de chei
sau de dependene funcionale:
1. Un student d maximum un examen ntr-o zi, deci {Grupa, Data} este cheie.
2. Un cadru didactic are examen cu o singur grup la o anumit or, deci {Cadru_did, Data,
Ora} este cheie.
3. La un moment dat ntr-o sal este planificat cel mult un examen, deci {Sala, Data, Ora}
este cheie.
4. Intr-o zi cadrul didactic nu schimb sala, n sala respectiv pot fi planificate i alte
examene, dar la alte ore, deci exist urmtoarea dependen funcional:
{Cadru_did, Data} {Sala}
Toate atributele din aceast relaie apar n cel puin o cheie, deci nu exist atribute
neprime. Avnd n vedere definiia formelor normale precizate pn acuma, putem spune c
relaia este n 3NF. Pentru a elimina i dependenele funcionale de tipul celor pe care le
avem n exemplul de mai sus s-a introdus o nou form normal:
Definiie. O relaie este n 3NF Boyce-Codd, sau BCNF, dac orice determinant
(pentru o dependen funcional) este cheie, deci nu exist dependene funcionale | o
astfel nct o s nu fie cheie.
Pentru a elimina dependena funcional amintit mai sus trebuie s facem urmtoarea
descompunere pentru relaia PLANIFICARE_EX:
PLANIFICARE_EX [Data, Cadru_did, Ora, Student],
REPARTIZARE_SALI [Cadru_did, Data, Sala].
Dup aceast descompunere nu mai exist dependene funcionale, deci relaiile sunt de
tipul BCNF, dar a disprut cheia asociat restriciei precizate la punctul 3 de mai sus: {Sala,
Data, Ora}. Dac se mai dorete pstrat o astfel de restricie, atunci ea trebuie verificat
altfel (de exemplu, prin program).

83

4.2. Gestiunea BD relaionale

4.2.1. Atribute, legturi, operatii

Pentru definirea bazelor de date relaionale, n diferitele sisteme de gestiune se folosesc
fie comenzi cu aceast destinaie (de definire), fie un limbaj sau interfa grafic specializat.
Plecnd de la aceast definire, pentru o baz de date se construiesc tabele (dicionare,
containere, fiiere) ce descriu, ntr-o form codificat, toate atributele, informaiile necesare
despre atribute, relaiile ce formeaz baza de date, precum i anumite proprieti pe care
trebuie s le verifice atributele, nregistrrile i legturile dintre relaii, pentru a pstra
corectitudinea bazei de date. Aceast definire poate s cuprind urmtoarele etape:
a) Definirea tipurilor de date pentru diferite atribute - o definire asemntoare cu tipurile din
diferite limbaje de programare. Este posibil ca aceast definire de tipuri s nu se poat
face, la definirea atributelor urmnd s se aleag numai dintre anumite tipuri standard
permise.
b) Definirea relaiilor ce formeaz baza de date. Pentru fiecare relaie se stabilete un nume
i o mulime de atribute (schema relaiei). Pentru fiecare atribut trebuie precizate, printre
alte informaii, i tipul valorilor acestui atribut.
c) Pentru ca datele memorate ntr-o baz de date relaional s fie corecte trebuie ca relaiile
componente s verifice anumite condiii (restricii). Prin aceste condiii sunt memorate i
unele elemente de semantic (se ine seama de semnificaia atributelor). Corectitudinea
datelor dintr-o baz de date se poate strica la efectuarea operaiilor de: adugare, tergere,
modificare, deci la execuia acestor operaii trebuie verificate astfel de condiii.
In continuare se amintesc cteva dintre condiiile (restriciile) ce pot apare n unele
sisteme.
1. Un atribut ia valori dintr-o anumit mulime, stabilit n momentul definirii atributului.
De exemplu, un atribut DATA_NASTERII trebuie s fie o dat calendaristic, un atribut
CLASA poate fi un ir de caractere dintr-o mulime stabilit {'9A', '9B', '10A', '12C', ...}.
In momentul efecturii diferitelor operaii n baza de date este necesar ca s fie ndeplinite
aceste condiii pentru fiecare valoare a atributului.
2. Mai multe atribute pot lua fiecare valori corecte, dar mpreun s produc o nregistrare
eronat. Sunt necesare condiii suplimentare ce trebuie verificate de valori ale mai multor
atribute dintr-o nregistrare. De exemplu, dou coloane ce memoreaz data naterii i data
curent pot fi corecte independent, dar trebuie ca diferena dintre data curent i data
naterii s fie cu cel puin 6 mai mare dect numrul clasei n care este un elev (ntr-o
eventual relaie ce memoreaz date despre elevii unei coli).
3. Inregistrrile dintr-o relaie sunt toate distincte. Pentru identificarea nregistrrilor se
poate stabili o cheie (sau mai multe). Dac C este o cheie, se cere s fie ndeplinit
restricia (condiia) | | | | j i C r C r
j i
= = , (realizrile cheii sunt distincte), numit
restricia de unicitate a cheii. Aceast condiie trebuie verificat de fiecare dat cnd se
84
v v
R1 R2 cheie
A=cheie extern
adaug o nregistrare nou la relaie sau la modificarea atributelor din cheie pentru o
anumit nregistrare.
4. Un atribut poate lua valori dintr-o anumit mulime, n care se include i valoarea de
'nedefinit'. Pentru ca s se poat verifica unicitatea valorilor pentru o cheie este necesar ca
toate valorile pentru cheie s fie distincte. La aceast verificare se poate cere s se ia n
considerare toate nregistrrile relaiei, sau numai cele care pentru atributele din cheie iau
valori diferite de 'nedefinit'. Restricia entitii sau integritatea entitii cere ca valorile
pentru atributele din cheie s fie (toate) diferite de 'nedefinit'.
5. Intre dou relaii se pot stabili anumite
legturi, prin valorile unui atribut
(simplu sau compus). Plecnd de la o
relaie R1 se pot cuta nregistrrile
dintr-o relaie R2 dup valorile unui
astfel de atribut. In relaia R2 (relaie
care este referit de legtur) se
stabilete un atribut A, numit cheie
extern. Valorile atributului A se caut
printre valorile cheii din relaia R1
(care se numete relaie ce refer, sau
printe n legtura stabilit). Cele dou
relaii R1 i R2 nu este obligatoriu s
fie distincte. Restricia referenial
(sau integritatea referirii) cere ca
valorile cheii externe (A din R2) s fie nedefinite sau s se regseasc printre valorile
cheii relaiei R1.
Un exemplu de astfel de legtur se poate da pentru dou relaii:
CLASE [Cod, Profil] i ELEVI [NrMatricol, Nume, Clasa, DataNasterii].
Legtura o putem stabili ntre relaia CLASE (considerat ca printe pentru relaie) i
relaia ELEVI (ca membru pentru legtur) prin egalitatea CLASE.Cod=ELEVI.Clasa.
Unei anumite clase (memorat n relaia CLASE), identificat printr-un cod, i corespund
toi elevii din clasa cu codul respectiv. Restricia referenial presupune c nu se poate
pune un elev ntr-o clas pentru care nu exist o nregistrare n relaia CLASE.
6. Pentru o legtur stabilit ntre dou relaii se pot preciza condiii (restricii) ce
trebuie respectate n momentul efecturii operaiilor de adugare, tergere sau modificare.
La efectuarea uneia dintre aceste operaii o legtur poate fi tratat n unul din modurile:
- S fie ignorat, deci operaia se efectueaz ca i cum legtura nu ar exista.
- Operaia de adugare a unei nregistrri n R2 se poate efectua dac valoarea ce
rezult pentru cheia extern din R2 se regsete printre valorile cheii din relaia R1.
Dac n R1 nu exist o astfel de nregistrare ce s-ar pune n coresponden cu
nregistrarea ce se adaug n R2, atunci operaia de adugare (n R2) nu se va efectua.
Pentru exemplul de mai sus, nu se poate aduga un elev ntr-o clas dac nu exist o
nregistrare pentru aceast clas.
- Operaia de tergere a unei nregistrri n R1 poate fi tratat n felul urmtor:
Nu se poate efectua dac n relaia R2 exist nregistrri care i corespund prin
legtura stabilit. Pentru exemplul precedent, nu se poate terge o clas (memorat
n CLASE) dac exist elevi ce aparin acestei clase (n ELEVI).
85
Se permite efectuarea acestei tergeri n R1, dar ea genereaz tergerea tuturor
nregistrrilor din R2 care sunt puse n coresponden prin legtur. Pentru
exemplul de mai sus, la tergerea unei clase (o nregistrare n relaia CLASE) se
terg i elevii din clasa respectiv (nregistrri n relaia ELEVI).
- Operaia de modificare a valorilor cheii pentru unele nregistrri din R1 poate fi
tratat n felul urmtor:
Nu se poate efectua aceast modificare dac n relaia R2 exist nregistrri care i
corespund prin legtura stabilit pentru valoarea veche a cheii. Pentru exemplul
precedent, nu se poate schimba codul pentru o clas (memorat n CLASE) de la
valoarea '9A' la '9E' dac exist elevi ce aparin clasei '9A' (n ELEVI).
Se permite efectuarea acestei modificri n R1, dar ea genereaz modificarea
tuturor nregistrrilor din R2 care sunt puse n coresponden prin legtur. Pentru
exemplul de mai sus, la modificarea unei clase (o nregistrare n relaia CLASE) de
la valoarea '9A' la '9E' se modific i n relaia ELEVI codul clasei de la valoarea
'9A' la valoarea '9E'.
Dup ce o baz de date a fost definit, este necesar existena unor comenzi ce permit
gestiunea acesteia. Dintre comenzile de baz necesare amintim:
- Adugarea unei noi relaii la baza de date;
- Eliminarea unei relaii din baza de date;
- Modificarea schemei unei relaii: adugarea de atribute, eliminarea unor atribute,
schimbarea numelui unui atribut, modificarea tipului valorilor pentru un atribut,
modificarea condiiilor de validare asociate unui atribut sau unei nregistrri, etc.
- Gestiunea legturilor dintre tabele: eliminarea/adugarea de legturi, modificarea
proprietilor asociate legturilor.

4.2.2. Gestiunea BD relaionale cu SQL

Pentru gestiunea bazelor de date relaionale s-a construit limbajul SOL (Structured
Query Language), ce permite gestiunea componentelor unei baze de date (tabele, index,
utilizatori, proceduri memorate, etc.).
- Scurt istoric:
- 1970 - E.F. Codd formalizeaz modelul relaional
- 1974 - la IBM (din San Jose) se definete limbajul SEQUEL (Structured English
Query Language)
- 1975 - se definete limbajul SQUARE (Specifying Queries as Relational
Expressions).
- 1976 - la IBM se definete o versiune modificat a limbajului SEQUE, cu numele
SEQUEL/2. Dup o revizuire devine SQL
- 1986 - SQL devine standard ANSI (American National Standards Institute)
- 1987 - SQL este adoptat de ISO (International Standards Organization)
- 1989 - se public extensia SQL89 sau SQL1
- 1992 - se face o revizuire i se obine SQL2 sau SQL92
86
- 1999 - se complecteaz SQL cu posibiliti de gestiune orientate obiect, rezultnd
SQL3 (sau SQL1999)
- 2003 - se adaug noi tipuri de date noi funcii, rezultnd SQL2003.
Comenzile (instruciunile) din SQL pot fi grupate n diverse clase:
- definirea diverselor componente: create, alter, drop;
- gestiunea datelor: insert, update, delete, truncate;
- regsirea datelor: select;
- gestiunea tranzaciilor: start transaction, commit, rollback;
- gestiunea diverselor componente dintr-o baz de date.
Din limbajul SQL amintim n continuare numai comenzile Create Table, Alter,
Insert, Update, Delete, Select.
Pentru crearea unui tabel se folosete comanda:
CREATE TABLE nume_tabel
(definire_coloana [,definire_coloana] ...[, restricii_tabel])
Pentru definirea unei coloane din tabel se precizeaz:
un nume pentru coloan
un tip al valorilor din aceast coloan, cu eventuale precizri ale dimensiunii coloanelor.
Putem avea urmtoarele tipuri de date (o astfel de list depinde de sistemul de gestiune a
bazelor de date cu care se lucreaz):
- Integer, Smallint, Byte - pentru numere ntregi reprezentate pe 4, 2, sau 1 octet
- Double, Float (sau Real)- pentru numere fracionare reprezentate n virgul mobil
(dubl precizie sau simpl precizie)
- Decimal(m,n) sau Numeric(m,n) - pentru date zecimale cu m numrul total de cifre,
din care n sunt pentru partea fracionar
- Char(n) sau Text(n) - iruri de n caractere (lungime fix)
- Varchar(n) - iruri caractere de lungime variabil
- Date, Time, DateTime (sau TimeStamp) - pentru dat calendaristic, timp, dat
calendaristic i timp
- Object - pentru valori binare sau iruri lungi de caractere (date LOB): imagini, sunet,
iruri de caractere, etc.
- alte tipuri de date (se va vedea http://www.w3schools.com/SQL/sql-data-types.asp
pentru tipurile de date de la Access, MySQL, SQLServer).
restricii asociate coloanei. Dintre tipurile de restricii amintim:
- Default valoare - valoarea implicit asociat coloanei dac la adugarea unei linii
coloanei nu i se atribuie valoare
- Not Null - nu poate s primeasc valori nedefinite
- Unique - valorile coloanei sunt unice
- Primary Key - dac se definete cheia primar ca i coloana curent
- Check(condiie) - pentru a preciza condiia pe care trebuie s o ndeplineasc valorile
coloanei (condiii simple, care au valoarea true sau false)
- Foreign Key REFERENCES tabel_parinte [(nume_coloana)] [On Update
actiune] [On Delete actiune] - pentru a defini coloana curent ca o cheie extern.
Dac pentru tabelul_parinte s-a definit cheia primar, atunci nu este necesar
87
precizarea coloanei ce formeaz aceast cheie primar. La efectuarea unei operaii de
tergere sau modificare n tabelul_parinte se poate asocia o aciune ce se execut n
tabelul curent (o explicaie a situaiilor ce pot apare este dat mai sus). Aceste aciuni
apar n clauzele On Delete sau On Update. Aciuni posibile ce se pot asocia la operaii
n tabelul referit ar putea fi:
o Restrict - operaia nu se poate executa dac se ncalc restriciile de integritate
o Set Null - valoarea pentru cheia extern va fi nlocuit cu null
o Set Default - valoarea pentru cheia extern va fi nlocuit cu valoarea implicit
o Cascade - se permite tergerea sau modificarea n tabelul printe, dar aceste
operaii genereaz tergeri sau modificri i n tabelul fiu
o No Action - pentru unele SGBD-uri, are semnificaia de la RESTRICT (se verific
dup efectuarea operaiei)
Dintre tipurile de restricii asociate tabelului amintim:
Unique(lista coloane) - valorile sunt unice pentru lista de coloane precizat
Check(condiie) - pentru a preciza condiia pe care trebuie s o ndeplineasc valorile
unei linii
- Primary key(lista coloane) - definirea cheii primare pentru tabel
- Foreign Key nume_cheie_externa(lista_coloane) REFERENCES tabel_parinte
[(lista_coloane)] [On Update actiune] [On Delete actiune] - pentru a defini o cheie
extern i a preciza legtura cu o cheie primar de la un tabel_parinte
Pentru modificarea structurii unui tabel deja definit se poate folosi instruciunea:
ALTER TABLE nume_tabel operaie [operaie]...
Amintim cteva dintre operaiile posibile:
- adugarea de coloane, modificarea coloanelor:
ADD(definire_coloana [,definire_coloana] ...)
MODIFY(definire_coloana [,definire_coloana] ...)
- eliminarea unei coloane: DROP nume_coloana;
- adaugarea/tergerea unei restricii, ex.: ADD PRIMARY KEY (cod);
- adugarea/modificarea valorii implicite: ADD(nume_coloana DEFAULT null)
Stergerea unui tabel din baza de date:
DROP TABLE nume_tabel
Pentru adugarea de nregistri ntr-un tabel se folosete comanda INSERT cu una din
formatele:
INSERT INTO nume_tabel [(lista_coloane)] VALUES (lista_valori)
INSERT INTO nume_tabel [(lista_coloane)] subinterogare
unde prin "subinterogare" se precizeaz o mulime de nregistrri (precizat cu ajutorul
comenzii SELECT).
Modificarea datelor dintr-un tabel se poate realiza prin comanda:
UPDATE nume_tabel SET coloana=expresie [,coloana=expresie] ... [WHERE condiie]
Se modific acele nregistrri din tabel pentru care condiia din clauza WHERE are valoarea
adevrat. Prin lipsa clauzei WHERE se iau toate nregistrrile din tabel. Valorile coloanelor
precizate n SET se schimb la valoarea expresiilor asociate.
88
Pentru tergerea de nregistrri dintr-un tabel se folosete comanda:
DELETE FROM nume_tabel [WHERE condiie]
Inregistrrile pentru care condiia din WHERE este adevrat se vor elimina din tabel. Dac
aceast clauz lipsete, atunci se terg toate nregistrrile tabelului.

4.2.3. Interogri ale BD

Pentru interogarea bazelor de date, deci pentru cererea de date, poate exista un limbaj
specializat numit limbaj al ntrebrilor, ca o parte a unui limbaj de gestiune a bazelor de
date. In afara regsirii datelor, un astfel de limbaj mai trebuie s conin comenzi pentru
tergerea de nregistrri dintr-o relaie, adugarea de noi nregistrri ntr-o relaie i
modificarea nregistrrilor.
Dintre limbajele de interogare a bazelor de date relaionale se pot aminti:
- Limbaj bazat pe algebra relaiilor. Acest limbaj este bazat pe o mulime de operatori ce
acioneaz asupra unei relaii (operatori unari) sau a dou relaii (operatori binari), iar
rezultatul este tot o relaie. In paragraful urmtor sunt precizai operatorii acestui limbaj.
- Limbajul SQL (Structured Query Language). Diferite versiuni ale acestui limbaj au fost
incluse n majoritatea SGBD-urilor comerciale.

89

4.3. Interogarea BD cu operatori din algebra relaional

Pentru a explica limbajul de interogare bazat pe algebra relaiilor vom preciza la
nceput tipurile de condiii ce pot apare n cadrul diferiilor operatori relaionali.
1. Pentru a verifica dac un atribut ndeplinete o condiie simpl se face compararea acestuia
cu o anumit valoare, sub forma:
nume atribut

>=
>
<=
<
<>
=
valoare
2. O relaie cu o singur coloan poate fi considerat ca o mulime. Urmtoarea condiie
testeaz dac o anumit valoare aparine sau nu unei mulimi:
nume_atribut
)
`

IN NOT IS
IN IS
relaie_cu_o_coloan
3. Dou relaii se pot compara prin operaiile de egalitate, diferit, incluziune, neincluziune.
Intre dou relaii cu acelai numr de coloane i cu aceleai tipuri de date pentru
coloane (deci ntre dou mulimi comparabile) putem avea condiii de tipul urmtor:
relaie

<>
=
IN NOT IS
IN IS
relaie
4. Tot condiie este i oricare din construciile urmtoare:
(condiie)
NOT condiie
condiie1 AND condiie2
condiie1 OR condiie2
unde condiie, condiie1, condiie2 sunt condiii de tipurile 1-4.
In primul tip de condiie apare construcia 'valoare', care poate fi una din tipurile
urmtoare. Pentru fiecare construcie se ia n valoare o anumit relaie curent, care rezult
din contextul n care apare aceasta.
- nume_atribut - care precizeaz valoarea atributului dintr-o nregistrare curent. Dac
precizarea numai a numelui atributului creaz ambiguitate (exist mai multe relaii
curente care conin cte un atribut cu acest nume), atunci se va face o calificare a
atributului cu numele relaiei sub forma: relaie.atribut.
90
- expresie - dac se evalueaz expresia, iar dac apar i denumiri de atribute, atunci acestea
se iau dintr-o nregistrare curent.
- COUNT(*) FROM relaie - precizeaz numrul de nregistrri din relaia specificat.
- | | ( ) atribut nume DISTINCT
MIN
MAX
AVG
SUM
COUNT
_

- care determin o valoare plecnd de la toate


nregistrrile din relaia curent. La determinarea acestei valori se iau toate valorile
atributului precizat ca argument (din toate nregistrrile), sau numai valorile distincte,
dup cum lipsete sau apare cuvntul DISTINCT. Valorile astfel determinate sunt:
numrul de valori (pentru COUNT), suma acestor valori (apare SUM, valorile trebuie s
fie numerice), valoarea medie (apare AVG, valorile trebuie s fie numerice), valoarea
maxim (apare MAX), respectiv valoarea minim (apare MIN).
In continuare se vor preciza operatorii care se pot folosi pentru interogarea bazelor
de date relaionale.
- Selecia (sau proiecia orizontal) a unei relaii R - determin o nou relaie ce are aceeai
schem cu a relaiei R. Din relaia R se iau numai nregistrrile care ndeplinesc o
condiie c. Notaia pentru acest operator este: ) ( R
c
o .
- Proiecia (sau proiecia vertical) - determin o relaie nou ce are atributele precizate
printr-o mulime de atribute. Din fiecare nregistrare a unei relaii R se determin numai
valorile atributelor incluse n mulimea . Mulimea de atribute se poate extinde la o
mulime de expresii (n loc de o mulime de atribute), care precizeaz coloanele relaiei
care se construiete. Notaia pentru acest operator este:
[
o
) ( R .
- Produsul cartezian a dou relaii: R
1
R
2
- care determin o relaie nou ce are ca
atribute concatenarea atributelor din cele dou relaii, iar fiecare nregistrare din R
1
se
concateneaz cu fiecare nregistrare din R
2
.
- Reuniunea, diferena i intersecia a dou relaii: R
1
R
2
, R
1
-

R
2
, R
1
R
2
. Cele dou
relaii trebuie s aib aceeai schem.
- Exist mai muli operatori join.
Joinul condiional sau theta join, notat prin R
1
O

R
2
- care determin acele
nregistrri din produsul cartezian al celor dou relaii care ndeplinesc o anumit
condiie. Din definiie se observ c avem: R
1
O

R
2=
) (
2 1
R R
O
o .
Joinul natural, notat prin R
1 -
R
2
, care determin o relaie nou ce are ca atribute
reuniunea atributelor din cele dou relaii, iar nregistrrile se obin din toate perechile
de nregistrri ale celor dou relaii care au aceleai valori pentru atributele comune.
Dac cele dou relaii au schemele | | | | | o
2 1
, R R , i { }
n
A A A ,..., ,
2 1
= | o , atunci
joinul natural se poate calcula prin construcia urmtoare:
R
1 -
R
2
=
[

|
|
.
|

\
|
= =

| o
2 1
.
2
.
1
...
1
.
2 1
.
1
R
m
A R
m
A R and and A R A R
R
91
r
1
r
2
r
2

R1

r
2

R2

r
Joinul extern stnga, notat (n acest material) prin
2 1
R R
C
, determin o relaie nou
ce are ca atribute concatenarea atributelor din cele dou relaii, iar nregistrrile se obin
astfel: se iau nregistrrile care se obin prin joinul condiional R
1
c

R
2,
la care se
adaug nregistrrile din R
1
care nu s-au folosit la acest join condiional combinate cu
valoarea null pentru toate atributele corespunztoare relaiei R
2
.
Joinul extern dreapta, notat prin
2 1
R R
C
, se obine asemntor ca joinul extern
stnga, dar la nregistrrile din R
1
c

R
2
se adaug nregistrrile din R
2
care nu s-au
folosit la acest join condiional combinate cu valoarea null pentru toate atributele
corespunztoare relaiei R
1
.
- Ctul pleac de la dou relaii | | | | | o 2 ,
1
R R ,
cu o | c , i se noteaz prin R
1
R
2
| | | o
.
Deducem c atributele din ct sunt date de
mulimea | o . O nregistrare re R
1
R
2

dac
2 2
R r e ,
1 1
R r e - ce ndeplinete
condiiile:
1.
[

=
| o
r r ) (
1
;
2.
[
=
|
2 1
) ( r r .
Semnificaia relaiei ct se vede i din figura
alturat. O nregistrare r
1
aparine ctului dac
n relaia R
1
apar toate concatenrile dintre
aceast nregistrare i fiecare nregistrare din R
2
.
O problem important legat de operatorii descrii mai sus const n determinarea unei
submulimi independente de operatori. O mulime M de operatori este independent dac
eliminnd un operator oarecare op din M se diminueaz puterea mulimii, adic va exista o
relaie obinut cu operatori din M i care nu se poate obine cu operatori din mulimea M -
{op}.
Pentru limbajul de interogare descris mai sus, cu operatorii:
{ }
[
- , , , , , , , , o
o mulime independent este format din submulimea: { }
[
, , , , o . Ceilali operatori se
obin dup regulile urmtoare (unele expresii au fost deja deduse mai sus):
- ) (
2 1 1 2 1
R R R R R = ;
- R
1
c

R
2=
) (
2 1
R R
c
o ;
- | | | | | o 2 ,
1
R R , i { }
n
A A A ,..., ,
2 1
= | o , atunci
- R
1 -
R
2
=
[

|
|
.
|

\
|
= =

| o
2 1
.
2
.
1
...
1
.
2 1
.
1
R
m
A R
m
A R and and A R A R
R ;
- Fie | | | | | o 2 ,
1
R R , i R
3
| | | = (null, ... , null), R
4
| | o = (null, ... , null).
92
2 1
R R
C
= (R
1
c

R
2
) [R
1
- ( )
[

2 1
R R
C
o
]
3
R .
2 1
R R
C
= (R
1
c

R
2
)
4
R [R
2
- ( )
[

2 1
R R
C
|
].
- Dac | | | | | o 2 ,
1
R R , cu o | c , atunci re R
1
R
2
dac

2 1 2
R R r e ,
1 1
R r e - ce
ndeplinete condiiile:
[

=
| o
r r ) (
1
i
[
=
|
2 1
) ( r r .
De aici deducem c r este din
[
| o
) (
1
R . In
2 1
) ( R R |
.
|

\
|
[
| o
sunt toate elementele
ce au o parte n
[
| o
) (
1
R i a doua parte n R
2
. Din relaia astfel obinut vom elimina
pe R
1
i rmn acele elemente ce au o parte n [
| o
)
1
( R i nu au cealalt parte n
[
|
) (
1
R . De aici obinem:
( ) ( )
[ [ [

=
| o | o | o
1 2 1 1 2 1
) ( ) ( R R R R R R .
Pentru a putea da cteva exemple de utilizare a acestui limbaj de interogare vom
introduce urmtoarele instruciuni:
- Atribuirea: unei variabile R[lista] (care va desemna o relaie i denumirea coloanelor) i
vom atribui o relaie dat printr-o expresie construit cu operatorii de mai sus.
- Eliminarea duplicrilor unei relaii: ) ( R o
- Sortarea nregistrrilor dintr-o relaie: ) (
} {
R s
lista

- Gruparea: ) (
} 2 { } 1 {
R
lista groupby lista
, care este o extensie pentru proiecie. Inregistrrile din R
sunt grupate dup coloanele din lista2, iar pentru un grup de nregistrri cu aceleai valori
pentru lista2 se evalueaz lista1 (unde pot apare funcii de grupare).

93

4.4. Interogarea BD relaionale cu SQL

Comanda SELECT este folosit pentru interogarea bazelor de date (obinerea de
informaii). Aceast comand este cea mai complex din cadrul sistemelor ce conin comenzi
SQL. Comanda permite obinerea de date din mai multe surse de date. Ea are, printre altele,
funciile de selectie, proiectie, produs cartezian, join i reuniune din limbajul de interogare a
bazelor de date relaionale bazat pe algebra relaiilor. Sintaxa comenzii este dat n
continuare.
SELECT
| | | | | |
)
`

(
(
(

... cmp AS exp cmp AS exp


*
[PERCENT] n TOP
DISTINCT
ALL

FROM sursa1 [alias] [,sursa2 [alias]]...
[WHERE condiie]
[GROUP BY lista_cmpuri [HAVING condiie]]
[
(
(
(

LECT comanda_SE
EXCEPT
INTERSECT
[ALL] UNION


(
(

(
(

)
`

)
`

)
`

)
`

...
DESC
ASC
nrcmp
cmp
BY ORDER ,
DESC
ASC
nrcmp
cmp
BY ORDER
Aceast comand selecteaz date din sursele de date precizate n clauza FROM. Pentru
precizarea (calificarea) cmpurilor (dac este necesar, deci dac folosirea numai a numelui
cmpului produce ambiguitate, adic exist mai multe cmpuri cu acest nume n sursele de
date) se poate folosi numele tabelului sau un nume sinonim (alias local numai n comanda
SELECT) stabilit n FROM dup numele sursei de date. Dac se definete un "alias", atunci
calificarea se face numai cu el (nu se va mai face cu numele tabelului).
O construcie numit sursa poate fi:
1. un tabel sau view din baza de date
2. (instruciune_select)
3. expresie_join, sub forma:
o sursa1 [alias] operator_join sursa2 [alias] ON condiie_legatur
o (expresie_join)
O cond_elementara de legtur dintre dou surse de date (precizate prin expresie_tabel)
sunt de forma:
[alias_sursa1.]cmp1 operator [alias_sursa2.]cmp2
Condiiile de legtur sunt de forma:
o cond_elementara [AND cond_elementara] ...
- (condiie)
94

unde operator poate fi: =, <>, >, >=, <, <=.
Cei doi termeni ai comparatiei trebuie s aparin la tabele diferite.
O expresie join are ca rezultat un tabel i este de forma:
Sursa1
(
(
(
(
(

[OUTER] FULL
[OUTER] RIGHT
[OUTER] LEFT
INNER
JOIN Sursa2 ON conditie
Joinul condiional, din algebra relaional, notat prin Sursa1
c

Sursa2, este precizat


prin Sursa1 INNER JOIN sursa2 ON condiie, i determin acele nregistrri din produsul
cartezian al celor dou surse care ndeplinesc condiia din ON.
Joinul extern stnga, precizat prin Sursa1 LEFT [OUTER] JOIN sursa2 ON
condiie, determin o surs nou ce are ca atribute concatenarea atributelor din cele dou
surse, iar nregistrrile se obin astfel: se iau nregistrrile care se obin prin joinul condiional
Sursa1
c

Sursa2
,
la care se adaug nregistrrile din sursa1 care nu s-au folosit la acest join
condiional combinate cu valoarea null pentru toate atributele corespunztoare din Sursa2.
Joinul extern dreapta, precizat prin Sursa1 RIGHT [OUTER] JOIN sursa2 ON
condiie, determin o surs nou ce are ca atribute concatenarea atributelor din cele dou
surse, iar nregistrrile se obin astfel: se iau nregistrrile care se obin prin joinul condiional
Sursa1
c

Sursa2
,
la care se adaug nregistrrile din sursa2 care nu s-au folosit la acest join
condiional combinate cu valoarea null pentru toate atributele corespunztoare din Sursa1.
Joinul extern total, precizat prin Sursa1 FULL [OUTER] JOIN sursa2 ON condiie,
se obine prin reuniunea rezultatelor obinute de joinul extern stnga i joinul extern dreapta.
Alte tipuri de expresii join:
- Sursa1 JOIN Sursa2 USING (lista_coloane)
- Sursa1 NATURAL JOIN Sursa2
- Sursa1 CROSS JOIN Sursa2
Dac n clauza FROM apar mai multe surse de date (care se vor evalua la un tabel),
atunci ntre un astfel de tabel - pe care Il vom numi tabel principal, i celelalte tabele este
indicat s existe anumite legturi (stabilite prin condiii). Plecnd de la fiecare nregistrare a
tabelului principal se determin nregistrrile din celelalte tabele asociate prin astfel de
legturi (deci nregistrrile ce verific o condiie). Dac legtura (condiia) nu se stabilete,
atunci se consider c ea asociaz toate nregistrrile din celelalte tabele pentru fiecare
nregistrare a tabelului principal (se consider c valoarea condiiei este true atunci cnd ea
lipsete). Aceast condiie de legtur dintre sursele de date se precizeaz prin:
FROM sursa1[, sursa2] ... WHERE condiie_legtur
Folosind sursele de date din FROM i eventuala condiie de legtur (dac exist mai
multe surse de date) va rezulta un tabel_rezultat, cu coloanele obinute prin concatenarea
coloanelor din sursele de date, iar nregistrrile sunt determinate dup cum sunt explicate mai
sus.
In tabel_rezultat se pot pstra toate nregistrrile obinute din sursele de date, sau se
95
poate face o filtrare prin utilizarea unei condiii de filtrare. Aceasta condiie de filtrare va fi
trecut n clauza WHERE n continuarea condiiei de legtur. Cu o condiie de filtrare
condiia din WHERE este de forma:
WHERE condiie_filtrare
WHERE condiie_legtur AND condiie_filtrare
Condiia de filtrare din clauza WHERE poate fi construit dup urmtoarele reguli.
Condiiile elementare de filtrare pot fi de una din formele urmtoare:
- expresie operator_relational expresie
- expresie [NOT] BETWEEN valmin AND valmax
pentru a verifica dac valoarea unei expresii este cuprins ntre dou valori (valmin i
valmax) sau nu este cuprins ntre aceste valori (apare NOT)
- cmp (NOT) LIKE ablon
Dup LIKE apare un ablon (ca un ir de caractere) ce precizeaz o mulime de valori. In
funcie de sistemul de gestiune folosit, exist un caracter n ablon ce precizeaz locul unui
singur caracter necunoscut n cmp, sau un caracter n ablon ce precizeaz un ir neprecizat
de caractere n cmp.
- | |
| |
( )
)
`

e subselecti
... valoare valoare
IN NOT expresie
Se verific dac valoarea expresiei apare (sau nu - cu NOT) ntr-o list de valori sau ntr-o
subselecie. O subselecie este o surs de date generat cu comanda SELECT i care are
numai un singur cmp - cu valori de acelai tip cu valorile expresiei. Aceast condiie
corespunde testului de "apartenen" al unui element la o mulime.
- cmp operator_relational

SOME
ANY
ALL
(subselectie)
Valorile cmpului din stnga operatorului relaional i valorile singurului cmp din
subselecie trebuie s fie de acelai tip. Se obine valoarea adevrat pentru condiie dac
valoarea din partea stng este n relaia dat de operator pentru:
o toate valorile din subselectie (apare ALL),
o cel puin o valoare din subselectie (apare ANY sau SOME).
Condiii echivalente:
"expresie IN (subselecie)" echivalent cu "expresie = ANY (subselecie)"
"expresie NOT IN (subselecie)" echivalent cu "expresie <> ALL (subselecie)"
- [NOT] EXISTS (subselectie)
Cu EXISTS se obtine valoarea adevrat dac n subselecie exist cel puin o nregistrare, i
fals dac subselecia este vid. Prezena lui NOT inverseaz valorile de adevr.
- O condiie de filtrare poate fi:
o condiie elementar
96
o (condiie)
o not condiie
o condiie1 and condiie2
o condiie1 or condiie2
O condiie elementar poate avea una din valorile: true, false, null. Valoarea null se
obine dac unul din operazii utilizai are valoarea null. Valorile de adevr pentru operatorii
not, and, or sunt date n continuare:
true false null
not false true null

and true false null or true false null
true true false null true true true true
false false false false false true false null
null null false null null true null

Din aceast succesiune de valori se pot selecta toate cmpurile din toate tabelele (apare
"*" dup numele comenzii), sau se pot construi cmpuri ce au ca valoare rezultatul unor
expresii. Cmpurile cu aceeai denumire n tabele diferite se pot califica prin numele sau
alias-ul tabelelor surs. Numelecmpului sau expresiei din tabelul rezultat este stabilit
automat de sistem (n functie de expresia ce-l genereaz), sau se poate preciza prin clauza AS
ce urmeaz expresiei (sau cmpului). In acest fel putem construi valori pentru o nou
nregistrare ntr-un tabel_final.
Expresiile se precizeaz cu ajutorul operanzilor (cmpuri, rezultatul unor funcii) i a
operatorilor corespunztori tipurilor de operanzi.
In tabelul final se pot include toate sau numai o parte din nregistrri, dup cum e
precizat printr-un predicat ce apare n faa listei de coloane::
- ALL - toate nregistrrile
- DISTINCT - numai nregistrrile distinte
- TOP n - primele n nregistrri
- TOP n PERCENT - primele n% nregistrri
Inregistrrile din "tabelul final" se pot ordona cresctor (ASC) sau descresctor
(DESC) dup valorile unor cmpuri, precizate n clauza ORDER BY. Cmpurile se pot
preciza prin nume sau prin poziia lor (numrul cmpului) n lista de cmpuri din comanda
SELECT (precizarea prin poziie este obligatorie atunci cnd se dorete sortarea dup
valorile unei expresii). Ordinea cmpurilor din aceast clauz precizeaz prioritatea cheilor
de sortare.
Mai multe nregistrri consecutive din "tabelul final* pot fi grupate ntr-o singur
nregistrare, deci un grup de nregistrri se nlocuiete cu o singur nregistrare. Un astfel de
grup este precizat de valorile comune ale cmpurilor ce apar n clauza GROUP BY.
"Tabelul nou" se sorteaz (automat de ctre sistem) creasctor dup valorile cmpurilor din
97
GROUP BY. Inregistrrile consecutive din fiierul astfel sortat, ce au aceeai valoare pentru
toate cmpurile din GROUP BY, se nlocuiesc cu o singur nregistrare. Prezena unei astfel
de nregistrri poate fi condiionat de valoarea adevrat pentru o condiie ce se trece n
clauza HAVING.
Pentru grupul de nregistrri astfel precizat (deci pentru o mulime de valori) se pot
folosi urmtoarele funcii:
-
|
|
.
|

\
|
(

)
`

cmp
DISTINCT
ALL
AVG sau AVG([ALL]) expresie)
Pentru grupul de nregistrri se iau toate valorile (cu ALL, care este i valoarea implicit) sau
numai valorile distincte (apare DISTINCT) ale cmpului sau expresiei numerice precizate i
din aceste valori se determin valoarea medie.
-
|
|
|
.
|

\
|

)
`

cmp
DISTINCT
ALL
*
COUNT
Aceast funcie determin numrul de nregistrri din grup (apare '*'), numrul de valori ale
unui cmp (apare ALL, identic cu '*'), sau numrul de nregistrri distincte din grup (cu
DISTINCT).
-
|
|
.
|

\
|
(

)
`

cmp
DISTINCT
ALL
SUM sau SUM([ALL]) expresie)
Pentru nregistrrile din grup se face suma valorilor unui cmp sau ale unei expresii numerice
(deci numrul de termeni este dat de numrul de nregistrri din grup) sau suma valorilor
distincte ale cmpului.
-
|
|
.
|

\
|
(

)
`

)
`

cmp
DISTINCT
ALL
MIN
MAX
sau
)
`

MIN
MAX
([ALL]) expresie)
Pentru fiecare nregistrare din grup se determin valoarea unei expresii sau cmp i se afl
valoarea maxim sau minim dintre aceste valori.
Cele cinci funcii amintite mai sus (AVG, COUNT, SUM, MIN, MAX) pot apare att
n expresiile ce descriu cmpurile din fiierul rezultat, ct i n clauza HAVING. Deoarece
aceste funcii se aplic unui grup de nregistrri, n comada SELECT acest grup trebuie
generat de clauza GROUP BY. Dac aceast clauz lipsete, atunci ntregul "tabel final"
constituie un grup, deci tabelul rezultat va avea o singur nregistrare.
In general nu este indicat selectarea cmpurilor singure (fr rezultat al funcilor
amintite) dect numai dac au fost trecute n GROUP BY. Dac totui apar, i aceast
folosire nu produce eroare, atunci se ia o valoare oarecare, pentru o nregistrare din grup.
Dou tabele cu acelai numr de cmpuri (coloane) i cu acelai tip pentru valorile
cmpurilor aflate pe aceleai poziii se pot reuni ntr-un singur tabel obinut cu ajutorul
operatorului UNION. Din tabelul rezultat obinut se pot pstra toate nregistrrile (apare
ALL) sau numai cele distincte (nu apare ALL). Clauza ORDER BY poate apare numai
pentru ultima selecie. Nu se pot combina subselecii prin clauza UNION.
Intre dou rezultate obinute cu instruciuni SELECT se poate folosi operatorul
INTERSEC sau EXCEPT (sau MINUS).
98
Clauzele din instruciunea SELECT trebuie s fie n ordinea: lista_expresii FROM ...
WHERE ... HAVING ... ORDER BY ...
O comand se poate memora n baza de date ca o component numit view. Definirea
este:
CREATE VIEW nume_view AS comanda_SELECT

Bibliografie
[Da04] Date C. J., An Introduction to Database Systems, Addison-Wesley, 2004.
[[Mo08] Molima H.G., Ullman J., Widom J., Database Systems: The Complete Book,
Addison-Wesley + Prentice-Hall, 2008
(http://infolab.stanford.edu/~ullman/dscb.html)
Ra98] Ramakrishnan R,. Database Management Systems, WCB McGraw-Hill, 1998.
[Si02] Silberschatz A., Kortz H., Sudarshan S., Database System Concepts, McGraw-Hill,
2002.
[Ta03] mbulea L., Baze de date, Facultatea de Matematica i Informatic, Centrul de
Formare Continu i nvmnt la Distan, Cluj-Napoca, 2003.

99

5. Sisteme de operare

5.1. Structura i funciile SO

5.1.1. Strile unui proces i principalele funcii ale SO

Menirea unui SO, indiferent de tipul lui, este pe de o parte de a facilita accesul la sistem a
unuia sau mai multor utilizatori, iar pe de alt parte de a asigura o exploatare eficient a
echipamentului de calcul. Vom ncerca s artm mai n detaliu care sunt funciile posibile
ale unui sistem, independent de tipul acestuia. Desigur, dependent de tip va fi ponderea n
cadrul sistemului a uneia sau alteia dintre funcii. Printr-un proces vom nelege un calcul
care poate fi efectuat concurent cu alte calcule.

S-au proiectat i se proiecteaz nc multe tipuri de SO. Fiecare dintre acestea trebuie s aib
ca obiective fundamentale:
- optimizarea utilizrii resurselor;
- minimizarea efectului uman de programare i exploatare;
- automatizarea operaiilor manuale n toate etapele de pregtire i exploatare a SC;
- creterea eficienei utilizrii SC prin scderea preului de cost al prelucrrii datelor.

Sintetiznd strile proceselor sub diverse sisteme de operare, putem defini strile unui proces
ntr- un sistem de operare. Aceste stri sunt:
- HOLD proces pregtit pentru intrarea n sistem;
- READY procesul este n memorie i este gata de a fi servit de (un) procesor;
- RUN un procesor execut efectiv instruciuni (main) ale procesului;
- WAIT procesul ateapt terminarea unei operaii de intrare / ieire;
- SWAP imaginea procesului este evacuat temporar pe disc;
- FINISH procesul s-a terminat, trebuie livrate doar rezultatele.

HOLD este starea unui proces la un sistem serial n care procesului i sunt citite datele de
lansare din cadrul lotului din care face parte, se face o analiz preliminar a corectitudinii lor
i apoi procesul este depus ntr-o coad pe disc (numit HOLD) spre a fi preluat spre
prelucrare. De obicei, aceste sisteme au o component specializat pentru astfel de prelucrri
SPOOL-ing de intrare (Simultaneous Peripheral Operations OnLine).

FINISH este, de asemenea, stare a unui proces la un sistem serial. Procesul se execut i
rezultatele lui sunt plasate pe disc ntr-o coad FINISH. Dup terminare, acestea vor fi listate,
fie pe o imprimant local, fie pe una aflat la distan. Componenta din SO care preia din
coada FINISH i listeaz se numete SPOOL-ing de ieire.

READY este starea n care un proces se afl n memoria intern dar nu este servit de
procesor. Este posibil ca el s fi fost servit parial, dar pe moment e suspendat n favoarea
altui proces, urmnd s i se continue execuia mai trziu.
100

SWAP este starea n care un proces este evacuat temporar ntr-un spaiu rezervat pe disc
(SWAP) pentru a face temporar loc altui proces n memoria intern. Ulterior procesul va fi
rencrcat n memoria intern i i se va continua execuia.

WAIT este starea n care un proces a cerut executarea unei operaii de intrare / ieire. Ct
timp procesul ateapt s se termine operaia, ced altor procese procesorul.

RUN este starea principal, aceea n care procesorul execut efectiv instruciuni main ale
programului procesului. Intr-un sistem monoprocesor doar un singur proces se afl n starea
RUN. Dac sistemul are n procesoare, atunci maximum n procese se vor afla n starea RUN.

Aceste stri nu se vor ntlni la toate tipurile de sisteme de operare. De exemplu, la un sistem
monoutilizator (vezi 8.1)nu va fi starea SWAP, numai sistemele seriale au strile HOLD i
FINISH etc.

Principalele funcii ale SO sunt legate de aciunile acestuia pentru tranziia ntre diverse stri
ale procesului. In figura alturat sunt schematizate strile unui proces. In dreptul fiecrei
tranziii sunt trecute principalele aciuni efectuate de ctre SO. Caracteristicile fiecreia dintre
cele ase stri posibile (HOLD, READY, RUN, SWAP, WAIT, FIHISH) le-am prezentat n
seciunea precedent.

Figura 5.1 Strile unui proces i aciunile SO aferente

Aciunile SO sunt executate de ctre componenta nucleu a sistemului de operare. La nivelul
componentei user, o mare parte dintre aciunile SO sunt focalizate mai ales n sprijinul
utilizatorului pentru dezvoltarea de programe, adic de asistare a userului la trecerea
programului prin diverse faze.

101
5.1.2. Structura general a unui SO

In aceast seciune ncercm s oferim o imagine asupra structurii unui SO ipotetic. Un astfel
de sistem nu va fi regsit nicieri n practic, ns structura fiecrui SO real va fi apropiat de
a acestuia. Evident, n funcie de tipul de SO real, unele dintre prezentele componente vor fi
atrofiate sau vor lipsi cu desvrire, iar altele vor putea fi eventual mult mai dezvoltate dect
aici. Fr pretenia de "gen-proxim" i "diferen-specific", ncercm s definim principalele
noiuni, structuri i componente cu care opereaz orice SO.

S trecem acum la structura propriu-zis.

5.1.2.1. Structura unui SO

Schema general a unui SO este ilustrat n figura de mai jos.

Figura 5.2 Structura general a unui SO

Orice SO conine dou pri mari: partea de control i partea de servicii.

PARTEA DE CONTROL este n legtur direct cu operatorul uman i indirect cu
utilizatorul. SO execut n mod master componentele acestei pri. Principalul ei rol este de a
realiza legtura cu SC, deci cu echipamentul hard.

PARTEA DE SERVICIU lucreaz n mod slave, folosind facilitile prii de control. Este n
legtur direct cu utilizatorul i indirect cu operatorul uman. Sarcina de baz a ei este de a
ine legtura cu utilizatorul, facilitndu-i acestuia accesul la resursele SC i SO.

In continuare vom descrie succint rolul fiecrei componente.

102
5.1.2.2. Partea de control

INTRERUPERI. Un ansamblu de rutine, fiecare dintre ele fiind activat la apariia unui
anumit semnal fizic de ntrerupere. Corespunztor, SO efectueaz aciunile aferente
ntreruperii respective. Semnificaia conceptului de ntrerupere este descris n fiecare manual
de arhitectura calculatoarelor.

Funcionarea concret a componentei (sistemului) de ntreruperi depinde foarte mult de
particularitile SC, deci nu se preteaz prea bine la abordri cu caracter general. Pe de alt
parte, detalii despre aceste componente intereseaz n primul rnd pe programatorii i
inginerii de sistem, mai puin pe utilizatorii obinuii., crora ne adresm noi. Din aceste
motive vom schia numai mecanismul de funcionare a ntreruperilor.
Fiecare tip de ntrerupere are asociat o locaie fix de memorie. In aceast locaie se afl o
adres. Aceast adres indic locul din memorie la care se afl o secven de instruciuni,
numit handler, secven care deservete ntreruperea respectiv.

La apariia semnalului de ntrerupere, dup ce instruciunea main n curs s-a executat, se
execut, n aceast ordine, urmtoarele activiti:
- se salveaz ntr-o zon de memorie starea programului n curs de desfurare;
- se activeaz handlerul asociat ntreruperii respective;
- handlerul execut aciunile necesare servirii ntreruperii;
- se restaureaz starea programului care a fost ntrerupt.

GESTIUNE PROCESE. Creeaz procese i rezolv problemele privind cooperarea i
concurena acestora. La terminarea unui proces, acesta este ters din sistem.

DISPECER PROCESOARE. La sistemele multiprocesor, repartizeaz sarcinile de calcul
solicitate de procese, procesoarelor care sunt libere i care pot executa sarcinile cerute.

GESTIUNEA MEMORIEI. Aloc necesarul de memorie intern solicitat de procese i
asigur protecia memoriei interprocese. Componenta este parial realizat prin hard i parial
este realizat soft, de ctre o component a SO.

I/O LA NIVEL FIZIC. Asigur efectuarea operaiilor elementare de I/O cu toate tipurile de
periferice din sistem realiznd, acolo unde este posibil, desfurarea simultan a uneia sau
mai multor operaii I/O, cu activitatea procesorului central. Aceast component este, de
asemenea, puternic dependent hard, n special de multitudinea de echipamente periferice
conectate la sistem. Aa dup cum am vzut, exist nite rutine de interfa numite drivere,
care realizeaz compatibilizarea conveniilor de I/O ntre SC i echipamentele periferice.
Driverele printre altele, fac parte din aceast component.

GESTIUNEA FISIERELOR. O colecie de module prin intermediul crora se asigur:
deschiderea, nchiderea i accesul utilizatorului la fiierele rezidente pe diferite suporturi de
informaii. Component de baz a SO, este cel mai des invocat de ctre utilizatori i de ctre
operator.

PLANIFICAREA LUCRARILOR SI ALOCAREA RESURSELOR. Resursele unui SC se
mpart n: resurse fizice (procesoare, memorie intern, periferice etc.) i resurse logice
(proceduri comune, tabele ale sistemului etc.). Fiecare proces solicit la un moment dat
103
anumite resurse. Prin aceast component a SO se asigur planificarea proceselor astfel, nct
ele s poat obine de fiecare dat resursele necesare, n mod individual sau partajate cu alte
procese. Elemente ale planificrii se rsfrng, dup cum vom vedea mai trziu, asupra
gestiunii proceselor, gestiunii memoriei, intrrilor si ieirilor etc. Atunci cnd vom discuta
despre procese, memorie i I/O la nivel fizic vom aborda i problematica planificrilor i a
alocrilor de resurse.

GESTIUNEA TEHNICA a SO. Tine evidena erorilor hard aprute la echipamentele SC. La
cerere, furnizeaz informaii statistice asupra gradului de utilizare a componentelor SC.

GESTIUNEA ECONOMICA a SO. Tine evidena utilizatorilor care folosesc sistemul,
lucrrile executate de ctre acetia i resursele consumate de aceste lucrri (timpi de rulare,
memorie intern ocupat, echipamente i supori folosii etc). Periodic (zilnic, lunar, anual)
editeaz liste cuprinznd lucrrile rulate i facturi de plat ctre beneficiari.

5.1.2.3. Partea de servicii

COMPILATOARELE sunt programe care traduc texte surs scrise n limbaje de nivel nalt
(C, C++, Java, FORTRAN, COBOL, Pascal, Ada etc.) n limbaj main. La aceast or exist
o mare varietate de tehnici de compilare, avnd ca nucleu teoria limbajelor formale. Exist de
asemenea sisteme automate de elaborare a diverselor componente ale compilatorului.
Rezultatul unei compilri este un modul obiect memorat ntr-un fiier obiect.

ASAMBLORUL este un program care traduce texte scrise n limbajul de asamblare propriu
SC ntr-un modul obiect. Din punct de vedere al SO problemele legate de asamblor sunt
incluse n problemele compilatoarelor.

LINK-EDITORUL sau EDITORUL DE LEGATURI. Grupeaz unul sau mai multe module
obiect, mpreun cu subprograme de serviciu din diverse biblioteci, ntr-un program
executabil. De cele mai multe ori aceast component ofer posibilitatea segmentrii
programelor mari, adic posibilitatea ca dou componente diferite a programului s poat
ocupa n execuie, la momente diferite de timp, aceeai zon de memorie. Rezultatul editrii
de legturi este un fiier executabil.

LOADER (PROGRAM DE INCARCARE) este un program al SO care are trei sarcini:
- citirea unui program executabil de pe un anumit suport;
- ncrcarea acestuia n memorie;
- lansarea lui n execuie.

Dac programul executabil este segmentat, atunci loaderul ncarc la nceput numai
segmentul rdcin al programului, dup care, la cerere, n timpul execuiei, ncarc de
fiecare dat segmentul solicitat n memorie.

INTERPRETOR este un program care execut pas cu pas instruciunile descrise ntr-un
anumit limbaj. Tehnica interpretrii este aplicat la diferite limbaje de programare, cum ar fi
Java, BASIC, LISP, PROLOG etc. Pentru SO, cea mai important categorie de interpretoare
sunt "interpretoarele de comenzi". Astfel, avem interpretoarele sh si bash sub Unix i
COMMAND.COM de pe platformele Microsoft.
104

MACROPROCESOR (PREPROCESOR) este un program cu ajutorul cruia se transform o
machet de program, pe baza unor parametri, ntr-un program surs compilabil. Spre
exemplu, fie macheta:
MACRO ADUNA &1, &2, &3
LOAD &1
ADD &2
STORE &3
ENDMACRO

Dac ntr-un program (dintr-un limbaj de asamblare) se scrie:
ADUNA A, B, C

atunci prin macroprocesoare se genereaz:
LOAD A
ADD B
STORE C

Practic, macroprocesarea este tehnica prin care se realizeaz o scriere mai compact a
programelor i o posibil parametrizare a acestora pentru realizarea comod a unor
implementri nrudite.

Astfel de macroprocesoare exist la toate SO moderne. Remarcm n mod deosebit
interpretorul de comenzi "shell" de sub Unix, descris n 2.2. Acesta dispune, printre altele, de
cele mai puternice faciliti de macroprocesare dintre toate interpretoarele de comenzi
cunoscute.

Unele limbaje au prevzute n standardele lor specificaii de macroprocesare. In acest sens
amintim preprocesorul "C" care trateaz n aceast manier liniile care ncep cu "#" i
construciile "typedef", precum i facilitile generice ale limbajului ADA .

EDITORUL DE TEXTE este un program interactiv destinat introducerii i corectrii textelor
surs sau a unor texte destinate tipririi. Orice SO interactiv dispune cel puin de cte un
astfel de editor de texte. Pn vom ajunge la capitolul dedicat editoarelor de texte, s
enumerm cteva editoare "celebre" unele prin vechimea lor, iar altele prin performanele lor:
- ed i vi sub Unix;
- Notepad i EDIT sub Windows;
- xedit i emacs de sub mediul X WINDOWS.

RUTINELE DE DEPANARE (DEPANATOARELE) asist execuia unui program utilizator
i-l ajut s depisteze n program cauzele erorilor aprute n timpul execuiei lui. Intreaga
execuie a programului utilizator se face sub controlul depanatorului. La prima apariie a unui
eveniment deosebit n execuie (depire de indici, adres inexistent, cod de operaie
necunoscut etc.) depanatorul primete controlul. De asemenea, el poate primi controlul n
locuri marcate n prealabil de ctre utilizator. Un astfel de loc poart numele de breakpoint.
La primirea controlului, depanatorul poate afia valorile unor variabile sau locaii de
memorie, poate reda, total sau parial istoria de calcul, poate modifica valorile unor variabile
sau locaii de memorie etc. Unele depanatoare mai performante permit execuia reversibil,
concept tratat teoretic dar mai puin aplicat practic. La aceast or sunt cunoscute dou tipuri
de depanatoare:
105
- depanatoare main;
- depanatoare simbolice.

Depanatoarele main opereaz cu elemente cum ar fi: adrese fizice, configuraii de bii,
locaii de memorie etc. Fiecare SO dispune de cte un astfel de instrument de depanare.

Depanatoarele simbolice opereaz cu elemente ale textelor surs ale programelor. Intlnim
aici termeni ca linie surs, nume de variabil, nume de procedur, stiv de apel a procedurilor
etc. Evident, depanatoarele simbolice sunt mult mai tentante pentru utilizator, i este bine c
este aa. De obicei, un astfel de depanator nsoete implementarea unui limbaj de programare
de nivel nalt. Primul i cel mai rspndit limbaj la care au fost ataate depanatoare simbolice
este limbajul Pascal. Amintim aici depanatorul Pascal de pe lng implementarea TURBO
Pascal, un depanator simbolic complet interactiv, cu o grafic destul de bun pentru
momentul implementrii lui i cu faciliti puternice. Firma BORLAND, un adevrat vrf de
lance n acest domeniu, a realizat printre altele produsul TURBO DEBUGER, care
recunoate n vederea depanrii toate limbajele pentru care s-au realizat medii TURBO:
Pascal, "C", limbajul de asamblare TASM, Basic, PROLOG etc. Produsul lucreaz att
simbolic, ct i la nivel main.

BIBLIOTECARUL este un program cu ajutorul cruia utilizatorul poate comanda pstrarea
programelor proprii n fiiere speciale de tip bibliotec, poate copia programe dintr-o
bibliotec n alta, terge, insereaz i modific programe n aceste biblioteci. Exemple de
programe biblioteci sunt LBR sub MS-DOS, ar (archive) sub Unix etc.

MEDIILE DE PROGRAMARE sunt componente complexe destinate n principal activitii
de dezvoltare de programe. O astfel de component nglobeaz, relativ la un limbaj, cel puin
urmtoarele subcomponente:
- editor de texte;
- compilator interactiv;
- compilator serial (clasic);
- editor de legturi sau un mecanism echivalent acestuia destinat creerii de programe
executabile;
- interpretor pentru execuia rezultatului compilrii;
- depanator, de regul simbolic;
- o component de legtur cu mediul exterior, de regul cu SO sub care se lucreaz.

De regul, filozofia de manevrare a mediului are un caracter unitar, este simpl i puternic.
Facilitile grafice ale acestor medii sunt destul de mult utilizate, fcnd deosebit de agreabil
lucrul cu ele.

SUPRAFETELE DE OPERARE au aprut tot la calculatoarele IBM-PC i a celor
compatibile cu ele. Ele au rolul principal de a "mbrca" sistemul de operare (Windows sau
Unix), pentru a-i face mai uoar operarea. Iniial au fost destinate utilizatorilor
neinformaticieni. La aceast or, nici profesionitii nu se mai pot "dezlipi" de o suprafa de
operare cu care s-a obinuit s lucreze. De regul, suprafeele de operare nlocuiesc limbajul
de control (de comand) al SO respectiv. Utilizatorul, n loc s tasteze o comand a SO
respectiv, poart un dialog cu suprafaa de operare, iar la finele dialogului suprafaa
genereaz sau execut comanda respectiv. Ponderea dialogului o deine suprafaa nsi,
utilizatorul rspunde de regul prin apsarea uneia sau maximum a dou taste, sau unul sau
dou "clicuri" cu un mouse. Suprafaa deine i un mecanism deosebit de puternic de HELP,
106
conducnd utilizatorul din aproape n aproape spre scopul dorit. Dei se adreseaz n primul
rnd neinformaticienilor, ele sunt din ce n ce mai mult folosite i de ctre specialiti.

O remarc special trebuie fcut pentru WINDOWS, care deine un mecanism propriu de
dezvoltare a unor aplicaii.

Din raiuni impuse de standarde, sub Unix se folosete aproape peste tot suprafaa
X-WINDOWS.

Din scurta prezentare a componentelor principale ale unui SO rezult caracterul modular al
SO i organizarea lui ierarhic. Modularitatea este termenul prin care se descrie partiionarea
unui program mare n module mai mici, cu sarcini bine precizate. Caracterul ierarhic este
reflectat n faptul c orice component acioneaz sub controlul componentelor de nivel
inferior acesteia, apelnd primitivele oferite de acestea. Aceste faciliti asigur o
implementare mai uoar a SO, o nelegere mai facil a SO de ctre diverse categorii de
utilizatori, o ntreinere i depanare mai uoar a sistemului i creeaz premisele simulrii lui
pe alt sistem.

107

5.2. Sisteme de fiiere

Gestiunea fiierelor este serviciul cel mai vizibil oferit utilizatorului de ctre un SO. Un SO
poate memora informaii pe diverse suporturi magnetice, poate s le imprime pe hrtie, sau
poate s le afieze pe un ecran. Din punctul nostru de vedere, cea mai interesant situaie
apare atunci cnd memorarea se face pe suport magnetic. Aproape exclusiv, ne vom ocupa de
gestiunea fiierelor vis-a-vis de suporturile magnetice. Dintre acestea, accentul va fi pus
foarte mult pe suportul disc, fiind cel mai convenabil tip de suport magnetic.

Sistemul de gestiune a fiierelor, (prescurtat SGF) este un ansamblu de rutine de legtur ntre
utilizatori i componenta de I/O la nivel fizic pentru operarea cu fiiere. Utilizatorul are la
dispoziie o serie de operaii primitive pe care le poate solicita SGF pentru serviciile dorite
privitoare la fiiere.

5.2.1. Probleme generale privind fiierele

5.2.1.1. Operaii asupra fiierelor

Operaiile asupra fiierelor se execut prin intermediul unor rutine SGF activate la cererea
utilizatorului. Vom descrie pe scurt cteva astfel de operaii.

Crearea unui fiier. Pentru fiierele de organizare mai simpl, aceast operaie coincide cu
deschiderea unui fiier nou n vederea scrierii n el. Pentru fiierele cu organizare mai sofisticat,
crearea nseamn o formatare, care pregtete spaiul fizic n vederea ncrcrii lui cu informaii.

Stergerea unui fiier. Atunci cnd informaiile dintr-un fiier nu mai sunt necesare, utilizatorul
poate cere o astfel de operaie. Ca efect, se elibereaz spaiul fizic ocupat de articolele fiierului
i se elimin din director intrarea care conine descriptorul fiierului respectiv.

Copierea unui fiier n alt fiier. Prin aceast operaie se realizeaz o copie fizic a fiierului
emitor sau surs (nu n sensul de program surs!) ntr-un fiier numit receptor sau destinaie.
Cele dou fiiere se pot afla pe acelai suport sau pe suporturi diferite. In ambele cazuri,
referirile la cele dou fiiere trebuie s fie diferite. In urma copierii, fiierele surs i destinaie
vor avea acelai coninut.

Schimbarea numelui de fiier (renumirea, mutarea). Aceast operaie las neschimbat
coninutul fiierului, dar i schimb numele. Mai general, poate schimba referirea la fiier n
cadrul aceluiai suport. Dac se schimb numele sau tipul fiierului spunem c avem de-a face
cu redenumire, iar dac se schimb calea de acces spre fiier, atunci spunem c este vorba de o
mutare a fiierului dintr-un director n altul (pstrndu-se evident acelai suport).

Listarea unui fiier. Operaia este un caz particular de copiere, atunci cnd fiierul surs este de
tip text, iar fiierul destinaie este imprimanta sau ecranul unui terminal.
108

Concatenarea mai multor fiiere. Operaia este o generalizare a copierii, constnd din alipirea
coninuturilor fiierelor ntr-unul singur. Formal, o concatenare este o aciune de forma:
fd :=concat(f1, f2, ..., fn);

unde fd este fiierul rezultat, iar f1 , f2 , ..., fn sunt fiierele de intrare. Operaia de
concatenare se poate face n dou moduri:
- Cu adugarea la fiierul fd vechi, caz n care noul fiier fd va fi format din vechiul fd
la care se adaug (se alipesc) n ordine celelalte n fiiere, ca mai jos:
f : fd (vechi) f1 f2 . . . fn
- Prin crearea unui fiier fd nou care conine numai cele n fiiere surs alipite.
f : f1 f2 . . . fn

Diverse SO mai conin multe alte programe utilitare care opereaz cu fiierele ca entiti. Vom
aminti cteva astfel de operaii.

Compararea a dou fiiere. Compararea se face parcurgnd secvenial cele dou fiiere, octet
cu octet. Dup depistarea unui numr fixat de nepotriviri (de multe ori 10) comparaia se oprete
cu rezultat fals. De regul, dac cele dou fiiere nu au aceeai lungime sau nu sunt de acelai
tip, comparaia nu se lanseaz.

Fuzionarea a dou sau mai multe fiiere. Pentru a realiza aceasta, trebuie s existe un criteriu
de stabilire a ordinii de fuzionare a articolelor din fiiere. In practic, de cele mai multe ori
articolele fiierelor de fuzionat au un atribut comun i apar n fiiere ordonate dup valorile
atributului respectiv. De exemplu, exist trei fiiere cu listele alfabetice ale studenilor din trei
ani de studii. Prin fuzionare se creeaz o singur list, ordonat, de asemenea, alfabetic.

Sortarea (ordonarea) articolelor unui fiier. Este o operaie foarte des utilizat la prelucrrile
cu caracter economic. Unele limbaje de programare dispun chiar de instruciuni speciale n acest
sens.

Operaii de filtrare a unui fiier. Prin filtru pentru un fiier nelegem un program care citete
un fiier i creeaz din el un altul pe baza unor criterii. Iat cteva astfel de criterii:
- sortarea articolelor ntr-o anumit ordine;
- eliminarea liniilor care au un anumit coninut;
- eliminarea unor caractere funcionale dintr-un fiier text;
- macroprocesarea unui text surs pe baza unor machete.

Aciunile SGF desfurate asupra fiierelor naintea primului acces la un fiier sunt grupate n
operaia de deschidere (Open) a fiierului respectiv.Operaia Open informeaz SO c un anume
fiier va deveni activ. Unele SO cer ca aceast operaie s fie fcut naintea primei citiri, scrieri
sau repoziionri la nceputul fiierului. Altele consider fiierul ca fiind implicit deschis din
momentul n care s-a cerut primul acces la el.

Prima sarcin a deschiderii este de a face legtura ntre informaiile de identificare a fiierului i
variabila din program prin care utilizatorul se refer la fiier. Prin deschidere sunt efectuate o
serie de controale asupra drepturilor de acces ale utilizatorului la fiier, se fac o serie de
iniializri care vor fi necesare acceselor ulterioare etc. In funcie de deschidere, avem:
A.Pentru un fiier care exist deja pe disc:
109
- Realizeaz legtura dintre variabila din program ce indic fiierul, suportul pe care se
afl fiierul i descriptorul de fiier aflat pe disc.
- Verific, pe baza informaiilor de acces, dac utilizatorul are sau nu drept de acces la
fiier.
B.Pentru un fiier nou, ce urmeaz a fi creat:
- Aloc spaiu pe disc pentru memorarea viitoarelor articole ale fiierului. In funcie de
tehnica de alocare folosit, se poate aloca ncepnd de la o singur unitate de alocare
(sector, bloc, cluster) si terminnd cu cantitatea maximal de spaiu estimat de
utilizator pentru fiierul n cauz.
C.Att la fiier nou ct i la fiier deja existent:
- Aloc memorie intern pentru zonele tampon necesare accesului la fiier.
- Incarc rutinele de acces la articolele fiierului i execut instruciunile lor de
iniializare.

Aciunile SGF desfurate dup ultimul acces la un fiier sunt grupate n operaia de nchidere
(Close) a fiierului respectiv. Operaia de nchidere anun SO c fiierul nceteaz a mai fi
activ. Unele SO cer anunarea explicit a nchiderii, altele efectueaz automat nchiderea la
sfritul programului. Prin nchidere se pun la zi informaiile generale despre fiier (lungime,
adrese de nceput i de sfrit, data modificrii etc). Mai concret, n funcie de condiiile de
nchidere avem:
A. Pentru fiierele temporare, create n programul curent i de care nu mai este nevoie n
continuare:
- Sterge fiierul i elibereaz spaiul disc ocupat.

B. Pentru fiierele nou create i care trebuie reinute:
- Creeaz o nou intrare n directorul discului.

C. Pentru toate fiierele care trebuie reinute:
- Insereaz, dac este cazul, marcajul EOF dup ultimul articol al fiierului.
- Golete (pune pe suport), dac este cazul, ultimele informaii existente n zonele
tampon.
- Pune la zi cele patru grupe de informaii din descriptorul de fiier cu valorile
curente.
- Dac fiierul a fost modificat, marcheaz acest lucru i eventual pune numele
fiierului ntr-o list a sistemului. Acest lucru este fcut n vederea unei salvri
automate de ctre SO a tuturor fiierelor modificate.

D. Pentru toate fiierele, permanente sau temporare:
- Aduce capul de citire al discului n poziia zero. Dac suportul este band, atunci
banda este rebobinat i eventual descrcat de pe unitate.
- Elibereaz spaiul de memorie ocupat de FCB.
- Elibereaz spaiile ocupate de zonele tampon n memoria operativ.
- Elibereaz (eventual) perifericul sau perifericele pe care a fost montat suportul
fiierului.

5.2.1.2. Clasificri ale fiierelor

110
Fiierele pot fi clasificate dup destul de multe criterii. In cele ce urmeaz ne ocupm de cele
mai uzuale i mai importante din punct de vedere practic.

A. Dup lungimea unui articol, se disting:
- Fiiere cu articole de format fix, n care toate articolele au aceeai lungime.
- Fiiere cu articole de format variabil, n care fiecare articol are propria lui lungime de
reprezentare. De regul aceste articole au o parte de lungime fix i una de lungime
variabil. In partea de lungime fix exist uneori un cmp din care se poate deduce
lungimea real a articolului. Alteori, sfritul unui articol este marcat prin unul sau mai
muli octei cu coninut special.

B. Dup posibilitatea de afiare sau tiprire a coninutului se disting fiiere text i fiiere binare.

- Fiiere text, sunt cele al cror coninut poate fi afiat pe un ecran sau poate fi tiprit pe o
imprimant. El este format dintr-o succesiune de octei, fiecare coninnd codul unui
caracter tipribil: liter mare, liter mic, cifr, simbol special. Codificarea caracterelor
se face folosind unul dintre sistemele de codificare standard: ASCII, UNICODE sau
(mai vechi) EBCDIC. La acest tip de fiiere articolul este format dintr-o linie. Dou linii
sunt separate fie prin '\n' cazul Unix, fie '\r\n' cazul Windows. Un fiier text se
termin ntotdeauna cu caracterul funcional EOF (End Of File).

- Fiiere binare, formate din iruri de octei consecutivi fr nici o semnificaie pentru
afiare. Semnificaia fiecrui octet este numai intern. Spre exemplu, fisiere avi, mp3,
fiierele obiect rezultate in urma compilri i fiierele executabile rezultate din editri de
legturi sunt fiiere binare. Evident c niruirea de bii i octei este "neleas" de ctre
CPU. Incercarea de a tipri direct un astfel de fiier nu are nici un sens!

C. Dup suportul pe care este rezident fiierul, se distinge o mare varietate de fiiere:
- fiiere pe disc magnetic;
- fiiere pe disc optic (CD, DVD)
- fiiere pe band sau caset;
- fiiere pe imprimant;
- fiiere tastatur;
- fiiere pe ecran;
- fiiere pe plotter, digitizor;
- etc.

Evident, c nu toate aceste tipuri de fiiere accept orice operaii i moduri de acces. De
exemplu, numai suportul disc accept accesul direct, celelalte numai secvenial. Fiierele pe
cartele sau tastatur accept numai citire. Fiierele pe imprimant, plotter sau ecran accept
numai scrieri etc.

D. Dup modurile de acces permise de ctre un fiier, se disting dou tipuri de fiiere: fiiere
secveniale i fiiere n acces direct.
- Un fiier secvenial este acela care permite numai accesul secvenial. Fiierele care au alt
suport dect discul (sau tamburul) magnetic sunt ntotdeauna fiiere secveniale.
- Un fiier n acces direct permite accesul direct cel puin n citire.

111
Cele mai importante limbaje de programare: Java, C#, C++ dispun de mecanisme prin care se
pot realiza fiiere n acces direct prin numr de poziie. Unele limbaje, sau unele SO, dispun de
mecanisme care permit accesul direct prin coninut. Avem aici de-a face cu organizri evoluate
ale fiierelor. Dintre acestea, cele mai importante sunt fiierele organizate:
- secvenial-indexat;
- selectiv;
- multilist;
- inverse;
- B-arbori.

5.2.2. Particulariti ale sistemului de fiiere Unix

5.2.2.1. Tipuri de fiiere i sisteme de fiiere

In cadrul unui sistem de fiiere, apelurile sistem Unix gestioneaz opt tipuri de fiiere i
anume:
1. Normale (obinuite)
2. Directori
3. Legturi hard (hard links)
4. Legturi simbolice (symbolic links)
5. Socketuri (sockets)
6. FIFO - pipe cu nume (named pipes)
7. Periferice caracter
8. Periferice bloc

Pe lng aceste opt tipuri, mai exist nc patru entiti, pe care apelurile sistem le vd, din
punct de vedere sintactic, tot ca i fiiere. Aceste entiti sunt gestionate de nucleul Unix, au
suportul fizic tot n nucleu i folosite la comunicri ntre procese. Aceste entiti sunt:
9. Pipe (anonymous pipes)
10. Segmente de memorie partajat
11. Cozi de mesaje
12. Semafoare

Fiierele obinuite sunt privite ca iruri de octei, accesul la un octet putndu-se face fie
secvenial, fie direct prin numrul de ordine al octetului.

Fiierele directori. Un fiier director se deosebete de un fiier obinuit numai prin informaia
coninut n el. Un director conine lista de nume i adrese pentru fiierele subordonate lui.
Uzual, fiecare utilizator are un director propriu care puncteaz la fiierele lui obinuite, sau la
ali subdirectori definii de el.

Fiierele speciale. In aceast categorie putem include, pentru moment, ultimele 6 tipuri de
fiiere. In particular, Unix privete fiecare dispozitiv de I/O ca i un fiier de tip special. Din
punct de vedere al utilizatorului, nu exist nici o deosebire ntre lucrul cu un fiier disc
normal i lucrul cu un fiier special.

112
Fiecare director are dou intrri cu nume speciale i anume:
"." (punct) denumete generic (puncteaz spre) nsui directorul respectiv;
".." (dou puncte succesive), denumete generic (puncteaz spre) directorul printe.

Fiecare sistem de fiiere conine un director principal numit root sau /.

In mod obinuit, fiecare utilizator folosete un director curent, ataat utilizatorului la intrarea
n sistem. Utilizatorul poate s-i schimbe acest director (cd), poate crea un nou director
subordonat celui curent, (mkdir), s tearg un director (rmdir), s afieze calea de acces
de la root la un director sau fiier (pwd) etc.

Apariia unui mare numr de distribuitori de Unix a condus, inevitabil, la proliferarea unui
numr oarecare de "sisteme de fiiere extinse" proprii acestor distribuitori. De exemplu:
- Solaris utilizeaz sistemul de fiiere ufs;
- Linux utilizeaz cu precdere sistemul de fiiere ext2 i mai nou, ext3;
- IRIX utilizeaz xfs
- etc.

Actualele distribuii de Unix permit utilizatea unor sisteme de fiiere proprii altor sisteme de
operare. Printre cele mai importante amintim:
- Sistemele FAT i FAT32 de sub MS-DOS i Windows 9x;
- Sistemul NTFS propriu Windows NT i 2000.

Din fericire, aceste extinderi sunt transparente pentru utilizatorii obinuii. Totui, se
recomand pruden atunci cnd se efectueaz altfel de operaii dect citirea din fiierele
create sub alte sisteme de operare dect sistemul curent. De exemplu, modificarea sub Unix a
unui octet ntr-un fiier de tip doc creat cu Word sub Windows poate uor s compromit
fiierul aa nct el s nu mai poat fi exploatat sub Windows!

Administratorii sistemelor Unix trebuie s in cont de sistemele de fiiere pe care le
instaleaz i de drepturile pe care le confer acestora vis-a-vis de userii obinuii.

Principiul structurii arborescente de fiiere este acela c orice fiier sau director are un singur
printe. Automat, pentru fiecare director sau fiier exist o singur cale (path) de la rdcin
la directorul curent. Legtura ntre un director sau fiier i printe o vom numi legtur
natural. Evident ea se creeaz odat cu crearea directorului sau fiierului respectiv.

5.2.2.2. Legturi hard i legturi simbolice

In anumite situaii este util partajarea unei poriuni a structurii de fiiere ntre mai muli
utilizatori. De exemplu, o baz de date dintr-o parte a structurii de fiiere trebuie s fie
accesibil mai multor utilizatori. Unix permite o astfel de partajare prin intermediul
legturilor suplimentare. O legtur suplimentar permite referirea la un fiier pe alte ci
dect pe cea natural. Legturile suplimentare sunt de dou feluri: legturi hard i legturi
simbolice (soft).

113
Legturile hard sunt identice cu legturile naturale i ele pot fi create numai de ctre
administratorul sistemului. O astfel de legtur este o intrare ntr-un director care puncteaz
spre o substructur din sistemul de fiiere spre care puncteaz deja legtura lui natural. Prin
aceasta, substructura este vzut ca fiind descendent din dou directoare diferite! Deci,
printr-o astfel de legtur un fiier primete efectiv dou nume. Din aceast cauz, la
parcurgerea unei structuri arborescente, fiierele punctate prin legturi hard apar duplicate.
Fiecare duplicat apare cu numrul de legturi ctre el.

De exemplu, dac exist un fiier cu numele vechi, iar administratorul d comanda:

#ln vechi linknou

atunci n sistemul de fiiere se vor vedea dou fiiere identice: vechi si linknou, fiecare
dintre ele avnd marcat faptul c sunt dou legturi spre el.

Legturile hard pot fi fcute numai n interiorul aceluiai sistem de fiiere (detalii puin mai
trziu).

Legturile simbolice sunt intrri speciale ntr-un director, care puncteaz (refer) un fiier
(sau director) oarecare n structura de directori. Aceast intrare se comport ca i un
subdirector al directorului n care s-a creat intrarea.

In forma cea mai simpl, o legtur simbolic se creeaz prin comanda:

ln - s caleInStructuraDeDirectori numeSimbolic

Dup aceast comand, caleInStructuraDeDirectori va avea marcat o legtur n
plus, iar numeSimbolic va indica (numai) ctre aceast cale. Legturile simbolice pot fi
utilizate i de ctre userii obinuii. De asemenea, ele pot puncta i nafara sistemului de
fiiere.

A B . A C -
D E . A F .. D E . A G ..
E . G .. F . G ..
C:
D:
C: B: A:
E: D: E: F:
F: G: G:
/:

114

Structura arborescent mpreun cu legturile simbolice sau hard confer sistemului de fiiere
Unix o structur de graf aciclic. In exemplul din figura de mai sus este prezentat un exemplu
simplu de structur de fiiere. Prin literele mari A, B, C, D, E, F, G am indicat nume de
fiiere obinuite, nume de directori i nume de legturi. Este evident posibil ca acelai nume
s apar de mai multe ori n structura de directori, graie structurii de directori care elimin
ambiguitile. Fiierele obinuite sunt reprezentate prin cercuri, iar fiierele directori prin
dreptunghiuri.

Legturile sunt reprezentate prin sgei de trei tipuri:
- linie continu legturile naturale;
- linie ntrerupt spre propriul director i spre printe;
- linie punctat legturi simbolice sau hard.

In exemplul de mai sus exist 12 noduri - fiiere obinuite sau directori. Privit ca un arbore,
deci considernd numai legturile naturale, el are 7 ramuri i 4 nivele.

S presupunem c cele dou legturi (desenate cu linie punctata) sunt simbolice. Pentru
comoditate, vom nota legtura simbolic cu ultima liter din specificarea cii. Crearea celor
dou legturi se poate face, de exemplu, prin succesiunea de comenzi:
cd /A
ln -s /A/B/D/G G Prima legtur
cd /A/B/D
ln -s /A/E E A doua legtur

S presupunem acum c directorul curent este B. Vom parcurge arborele n ordinea director
urmat de subordonaii lui de la stnga spre dreapta. Urmtoarele 12 linii indic toate cele 12
noduri din structur. Pe aceeai linie apar, atunci cnd este posibil, mai multe specificri ale
aceluiai nod. Specificrile care fac uz de legturi simbolice sunt subliniate. Cele mai lungi 7
ramuri vor fi marcate cu un simbol # n partea dreapt.

/ ..
/A ../A
/A/D ../A/D #
/A/E ../A/E D/E ./D/E
/A/E/F ../A/E/F D/E/F ./D/E/F #
/A/E/G ../A/E/G D/E/G ./D/E/G #
/B .
/B/D D ./D
/B/D/G D/G ./D/G /A/G ../A/G #
/B/E E ./E #
/B/F F ./F #
/C ../C #

Ce se ntmpl cu tergerea n cazul legturilor multiple? De exemplu, ce se ntmpl cnd se
execut una dintre urmtoarele dou comenzi?

rm D/G
rm /A/G

115
Este clar c fiierul trebuie s rmn activ dac este ters numai de ctre una dintre
specificri.

Pentru aceasta, n descriptorul fiierului respectiv exist un cmp numit contor de legare.
Acesta are valoarea 1 la crearea fiierului i crete cu 1 la fiecare nou legtur. La tergere,
se radiaz legtura din directorul printe care a cerut tergerea, iar contorul de legare scade cu
1. Abia dac acest contor a ajuns la zero, fiierul va fi efectiv ters de pe disc i blocurile
ocupate de el vor fi eliberate.

5.2.2.3. Principalele directoare ale unui system de fiiere Unix

De-a lungul evoluiei sistemelor din familia Unix, partea superioar a structurii sistemului de
fiiere a avut mai mult sau mai puin o form standard. De fapt, fiecare versiune Unix i-a
fixat o structur specific a prii superioare din sistemul de fiiere. Diferenele ntre aceste
structuri nu sunt prea mari. Mai mult, din raiuni de compatibilitate, versiunile mai noi
definesc legturi suplimentare hard (nu legturi simbolice), pentru a asigura compatibilitatea
cu sistemele de fiiere mai vechi. Din aceast cauz este cel mai nimerit s se studieze o
reuniune a celor mai rspndite structuri. O astfel de structur este prezentat de noi n figura
de mai jos.

Directorul /etc conine informaii specifice mainii necesare ntreinerii sistemului. Acestea
sunt de fapt datele restrictive i periculoase din sistem. Un exemplu de fiier ce conine
informaii specifice mainii este, spre exemplu, /etc/rc2.d care este un director ce
conine programe shell executate de procesul init la schimbarea strii. Tot aici sunt plasate
fiierele /etc/passwd, /etc/group, /etc/shadow care sunt folosite pentru
administrarea utilizatorilor.

Directorul /home este folosit pentru directorii gazd ai utilizatorilor. In momentul intrrii n
sistem, fiecare utilizator indic directorul lui, care este fixat ca director curent (home
directory) in /etc/passwd. Dei se poate trece uor de la un director la altul, n mod
normal fiecare utilizator rmne n propriul lui director, unde i dezvolt propria lui structur
arborescent de directori.

Directorul /usr este folosit n mod tradiional pentru a stoca fiiere ce pot fi modificate. La
primele versiuni de Unix coninea i fiierele utilizatorilor. In prezent este punctul de montare
pentru partiia ce conine usr. El contine programe executabile dependente i independente de
sistemul de fiiere, precum i fiiere necesare acestora, dar care nu cresc dinamic. Asupra
coninutului de subdirectoare ale lui /usr vom reveni puin mai trziu.

Directorul /bin conine programele principalelor comenzi standard Unix: compilatoare,
asambloare, editoare de texte, utilitare etc. Versiunile mai noi de Unix plaseaz acest director
n /usr/bin.

Directorul /sbin (super-utilizator bin) conine comenzi critice pentru procedura de ncrare
a sistemului. Orice comenzi administrative care necesit lucrul mono-utilizator sunt n acest
director. Copii ale acestor comenzi se afl n directoarele /usr/bin i /usr/sbin, astfel
nct el (/sbin) poate fi refcut dac este necesar.
116

home
etc
usr
bin
sbin
lib
include
share
ucb
ccs
src
sbin
bin
de
v
lib
stand
mnt
spool
tmp
var
export
preserve
adm
tmp
opt
cron
mail
news
uucp
saf
spool


Directorul /lib conine diverse biblioteci i baze de date necesare apelurilor sistem. Doar
versiunile mai vechi de Unix plaseaz acest director n /, cele actuale l plaseaz n
/usr/lib.

Directorul /dev este folosit pentru memorarea fiierelor speciale (fiierele devices). Practic,
fiecare tip de terminal i fiecare tip de unitate de disc trebuie s aib asociat un astfel de fiier
117
special. Incepnd cu SVR4 se permite ca n dev s existe i subdirectoare care s grupeze
astfel de device-uri.

Directorul /stand conine informaiile necesare ncrcrii sistemului.

Directorul /mnt este folosit pentru a monta un sistem de fiiere temporar. De exemplu, un
sistem de fiiere de pe un disc flexibil poate fi montat n /mnt pentru a verifica fiierele de
pe aceast dischet.

Directorul /spool este plasat n / doar n versiunile mai vechi de Unix. In el sunt memorate
fiierele tampon temporare destinate prelucrrilor asincrone: listri asincrone de fiiere
(/spool/lpd) i execuia la termen a unor comenzi (/spool/at).

Directorul /export este folosit ca punct implicit de montare pentru un arbore de sistem de
fiiere exportat, pentru fiierele n reea gestionate prin pachetul NFS (Network File System).

Directorul /var este folosit pentru memorarea fiierelor care cresc dinamic. In particular,
multe dintre versiunile de Unix in n acest director fiierele INBOX cu csuele potale ale
utilizatorilor. Structura de subdirectoare a lui /var o vom descrie ceva mai ncolo.

Directorul /tmp este folosit pentru a memora fiiere temporare pentru aplicaii. In mod
normal, aceste fiiere nu sunt salvate i sunt terse dup o perioad de timp.

In continuare vom descrie pe scurt coninutul directorului /usr. Dup cum se poate vedea,
unele dintre subdirectoare sunt plasate (i au fost descrise) la nivel de rdcin /. Versiunile
mai noi de Unix, ncepnd cu SVR4, le-au cobort din rdcin ca subdirectoare ale lui /usr.
Este cazul directoarelor bin, sbin, lib.

Directorul /usr/include conine fiierele header (*.h) standard ale limbajului C de sub
Unix.

Directorul /usr/share conine o serie de directoare partajabile n reea. In multe dintre
sistemele noi, n el se afl directoarele: man cu manualele Unix, src cu sursele C ale
nucleului Unix i lib mai sus prezentat.

Directorul /usr/ucb conine programele executabile compatibile Unix BSD.

Directorul /usr/src conine textele surs C ale nucleului Unix de pe maina respectiv.

Directorul /usr/ccs conine instrumentele de dezvoltare a programelor C oferite de Unix:
cc, gcc, dbx, cb, indent, etc.

In continuare vom descrie coninutul directorului /var. Ca i mai sus, unele subdirectoare de
la nivelele superioare au fost mutate aici de ctre versiunile mai noi de Unix. Este vorba de
directoarele spool i tmp.

Directorul /var/saf conine fiiere jurnal i de contabilizare a serviciilor oferite.

118
Directorul /var/uucp conine programele necesare efecturii de copieri de fiiere ntre
sisteme Unix (Unix to Unix CoPy). Acest gen de servicii este primul pachet de comunicaii
instalat pe sisteme Unix, este operaional nc din 1978 i este utilizat i astzi atunci cnd nu
exist alt mijloc mai modern de comunicaii. Un astfel de sistem permite, de exemplu, apelul
telefonic ntre dou sisteme Unix, iar dup luarea contactului cele dou sisteme i schimb
ntre ele o serie de fiiere, ca de exemplu mesajele de pot electronic ce le sunt destinate.

Directorul /var/news conine fiierele necesare serviciului de (tiri) nouti (news) care
poate fi instalat pe mainile Unix.

Directorul /var/mail conine csuele potale implicite ale utilizatorilor (INBOX). Pe
unele sisteme, ca de exemplu pe Linux, acestea se afl n /var/spool/mail.

Directorul /var/cron conine fiierele jurnal necesare serviciilor executate la termen.

Directorul /var/opt constituie un punct de montare pentru diferite pachete de aplicaii.

Directorul /var/preserve conine, la unele implementri Unix (SVR4) fiiere jurnal
destinate refacerii strii editoarelor de texte picate ca urmare a unor incidente.

Directorul /var/adm conine fiiere jurnal (log-uri) de contabilizare i administrare a
sistemului. La versiunile mai noi acestea sunt n /var/log.

Dup cum se poate vedea uor, structura de directori Unix ncepnd de la rdcin este relativ
dependent de tipul i versiunea de Unix. De fapt, este vorba de Unix vechi i Unix noi.
De asemenea, multe dintre directoare au fost nlocuite sau li s-a schimbat poziia n structura
de directori. Tabelul de mai jos prezint cteva corespondene ntre vechile i noile plasri de
fiiere.

Nume vechi Nume nou
/bin /usr/bin
/lib /usr/lib
/usr/adm /var/adm
/usr/spool /vsr/spool
/usr/tmp /var/tmp
/etc/termcap /usr/share/lib/termcap
/usr/lib/terminfo /usr/share/lib/terminfo
/usr/lib/cron /etc/cron.d
/usr/man /usr/share/man
/etc/<programe> /usr/bin/<programe>
/etc/<programe> /sbin/<programe>

119

5.3. Procese Unix

5.3.1. Principalele apeluri system de gestiune a proceselor

In seciunile din acest subcapitol vom prezenta cele mai importante apeluri sistem pentru
lucrul cu procese: fork, exit, wait i exec*. Incepem cu fork(), apelul sistem
pentru crearea unui proces.

5.3.1.1. Crearea proceselor Unix. Apelul fork

In sistemul de operare Unix un proces se creeaz prin apelul funciei sistem fork(). La o
funcionare normal, efectul acesteia este urmtorul: se copiaz imaginea procesului ntr-o
zon de memorie liber, aceast copie fiind noul proces creat, n prima faz identic cu
procesul iniial. Cele dou procese i continu execuia n paralel cu instruciunea care
urmeaz apelului fork.

Procesul nou creat poart numele de proces fiu, iar procesul care a apelat funcia fork() se
numete proces printe. Exceptnd faptul c au spaii de adrese diferite, procesul fiu difer de
procesul printe doar prin identificatorul su de proces PID, prin identificatorul procesului
printe PPID i prin valoarea returnat de apelul fork(). La derulare normal, un apel
fork() ntoarce n procesul printe (procesul care a lansat apelul fork()) pid-ul noului
proces fiu, iar n procesul fiu, ntoarce valoarea 0.

fork() fork()
fork()
>0 (pid fiu)
0
Proces parinte
Proces fiu
Context Context
Context
Proces parinte
Inainte de fork: Dupa fork:

Figura 5.3 Mecanismul fork
120

In figura de mai sus am ilustrat acest mecanism, unde sgeile indic instruciunea care se
execut n mod curent n proces.

In caz de eec, fork ntoarce valoarea 1 i desigur, seteaz corespunztor variabila errno.
Eecul apelului fork poate s apar dac:
- nu exist memorie suficient pentru efectuarea copiei imaginii procesului printe;
- numrul total de procese depeste o limit maxim admis.

Acest comportament al lui fork permite descrierea uoar a dou secvene de instruciuni
care s se deruleze n paralel, sub forma:

if ( fork() == 0 )
{ - - - instruciuni ale procesului fiu - - - }
else
{ - - - instruciuni ale procesului tat - - - }

Programul urmtor ilustreaz utilizarea lui fork:

main(){
int pid,i;
printf("\nInceputul programului:\n");
if ((pid=fork())<0) err_sys("Nu pot face fork()\n");
else if (pid==0){//Suntem in fiu
for (i=1;i<=10;i++){
sleep(2); //dormim 2 secunde
printf("\tFIUL(%d) al PARINTELUI(%d):3*%d=%d\n",
getpid(),getppid(),i,3*i);
}
printf("Sfarsit FIU\n");
}
else if (pid>0){//Suntem in parinte
printf("Am creat FIUL(%d)\n",pid);
for (i=1;i<=10;i++){
sleep(1); //dormim 1 secunda
printf("PARINTELE(%d):2*%d=%d\n",getpid(),i,2*i);
}
printf("Sfarsit PARINTE\n");
}
}

In mod intenionat, am fcut astfel nct procesul fiu s atepte mai mult dect printele (n
cazul calculelor complexe apar adesea situaii n care operaiile unuia dintre procese dureaz
mai mult n timp). Ca urmare, printele va termina mai repede execuia. Rezultatele obinute
sunt:
Inceputul programului:
Am creat FIUL(20429)
PARINTELE(20428): 2*1=2
FIUL(20429) al PARINTELUI(20428): 3*1=3
PARINTELE(20428): 2*2=4
PARINTELE(20428): 2*3=6
FIUL(20429) al PARINTELUI(20428): 3*2=6
PARINTELE(20428): 2*4=8
PARINTELE(20428): 2*5=10
FIUL(20429) al PARINTELUI(20428): 3*3=9
121
PARINTELE(20428): 2*6=12
PARINTELE(20428): 2*7=14
FIUL(20429) al PARINTELUI(20428): 3*4=12
PARINTELE(20428): 2*8=16
PARINTELE(20428): 2*9=18
FIUL(20429) al PARINTELUI(20428): 3*5=15
PARINTELE(20428): 2*10=20
Sfarsit PARINTE
FIUL(20429) al PARINTELUI(1): 3*6=18
FIUL(20429) al PARINTELUI(1): 3*7=21
FIUL(20429) al PARINTELUI(1): 3*8=24
FIUL(20429) al PARINTELUI(1): 3*9=27
FIUL(20429) al PARINTELUI(1): 3*10=30
Sfarsit FIU

5.3.1.2. Execuia unui program extern; apelurile exec

Aproape toate sistemele de operare i toate mediile de programare ofer, ntr-un fel sau altul,
mecanisme de lansare a unui program din interiorul altuia. Unix ofer acest mecanism prin
intermediul familiei de apeluri sistem exec*. Dup cum se va vedea, utilizarea combinat de
fork exec ofer o mare elasticitate manevrrii proceselor.

Apelurile sistem din familia exec lanseaz un nou program n cadrul aceluiai proces.
Apelului exec i se furnizeaz numele unui fiier executabil, iar coninutul acestuia se
suprapune peste programul procesului existent, aa cum se vede n fig. 5.10.

exec()
p
r
o
g
ra
m

n
o
u
Context
vechi
Context
vechi
Inainte de exec: Dupa exec:
Context
nou

Figura 5.4 Mecanismul exec

In urma lui exec instruciunile aflate n programul curent nu se mai execut, n locul lor se
lanseaz instruciunile noului program.

Unix ofer, n funcie de trei criterii, sase astfel de apeluri, ilustrate n fig. 5.11. Criteriile
sunt:
- Specificarea cii spre programul executabil ce va fi lansat: absolut sau relativ la
directoarele indicate prin variabila de mediu PATH.
- Mediul este motenit sau se creeaz un nou mediu.
- Specificarea argumentelor din linia de comand se face printr-o list explicit sau printr-
un vector de pointeri spre aceste argumente.

122
Din cele opt posibile, s-au eliminat cele dou cu cale relativ i mediu nou. Prototipurile celor
ase apeluri exec*() sunt:

int execv (char *fisier, char *argv[]);
int execl (char *fisier, char *arg0, , char *argn,
NULL);
int execve(char *fisier, char *argv[], char *envp[]);
int execle(char *fisier, char *arg0, , char *argn, NULL,
char *envp[]);
int execvp(char *fisier, char *argv[]);
int execlp(char* fisier, char *arg0, , char *argn,
NULL);

Semnificaia parametrilor exec este urmtoarea:
- fisier - numele fiierului executabil care va nlocui programul curent. El trebuie s
coincid cu argumentul argv[0] sau arg0.
- argv este tabloul de pointeri, terminat cu un pointer NULL, care conine argumentele
liniei de comand pentru noul program lansat n execuie.
- arg0, arg1, ... , argn, NULL conine argumentele liniei de comand
scrise explicit ca i stringuri; aceast secven trebuie terminat cu NULL.
- envp este tabloul de pointeri, terminat cu un pointer NULL, care conine stringurile
corespunztoare noilor variabile de mediu sub forma nume=valoare.

5.3.1.3. Apelurile exit i wait

Apelul sistem:
exit(int n)

provoac terminarea procesului curent i revenirea la procesul printe (cel care l-a creat prin
fork). Intregul n precizeaz codul de retur cu care se termin procesul. In cazul n care
procesul printe nu mai exist, procesul este trecul n starea zombie i este subordonat
automat procesului special init (care are PID-ul 1).

Ateptarea terminrii unui proces se realizeaz folosind unul dintre apelurile sistem wait()
sau waitpid(). Prototipurile acestora sunt:

pid_t wait(int *stare)
pid_t waitpid(pid_t pid, int *stare, int optiuni);

Apelul wait() suspend execuia programului pn la terminarea unui proces fiu. Dac fiul
s-a terminat nainte de apelul wait(), apelul se termin imediat. La terminare, toate
resursele ocupate de procesul fiu sunt eliberate.

123
5.3.2. Comunicarea ntre procese prin pipe
5.3.2.1. Conceptul de pipe

Conceptul a aprut prima dat sub Unix, pentru a permite unui proces fiu s comunice cu
printele su. De obicei procesul printe redirecteaz ieirea sa standard, stdout, ctre un
pipe, iar procesul fiu i redirecteaz intrarea standard, stdin, din acelai pipe. In
majoritatea sistemelor de operare se folosete operatorul | pentru specificarea acestui gen
de conexiuni ntre comenzi ale sistemului de operare.

Un pipe Unix este un flux unidirecional de date, gestionat de ctre nucleul sistemului. De
fapt, n nucleu se rezerv un buffer de minimum 4096 octei n care octeii sunt gestionai aa
cum am descris mai sus. Crearea unui pipe se face prin apelul sistem:

int pipe(int fd[2]);

Intregul fd[0] se comport ca un ntreg care identific descriptorul pentru citirea din
"fiierul" pipe, iar fd[1] ca un ntreg care indic descriptorul pentru scriere n pipe. In urma
crerii, legtura user nucleu prin acest pipe apare ca n figura de mai jos.

Evident, un pipe ntr-un singur proces nu are sens. Este ns esenial funcionarea lui pipe
combinat cu fork. Astfel, dac dup crearea lui pipe se execut un fork, atunci legtura
celor dou procese cu pipe din nucleu apare ca n figura urmtoare.

read fd[0]
write fd[1]
pipe
sensul datelor
proces user:
nucleu:

124

Figura 5.5 Un pipe leag dou procese nrudite

Asigurarea unidirecionalitii unui pipe cade exclusiv n sarcina programatorului. Astfel,
pentru a se asigura sensul datelor n exemplul de mai sus, se impune ca nainte de a transmite
prin pipe:
- In procesul printe s se apeleze close(fd[0]);
- In procesul fiu s se apeleze close(fd[1]);

Natural, dac se dorete ordinea invers, atunci se vor executa operaiile close(fd[1]) n
procesul printe i close(fd[0]) n procesul fiu.

5.3.2.2. Exemplu: implementarea who | sort prin pipe i exec

S considerm acum comanda shell compus:

$ who | sort

Noi vom prezenta realizarea conexiunii ntre cele dou comenzi: who | sort prin pipe.
Procesul printe (care nlocuiete procesul shell) genereaz doi fii, iar acetia i redirecteaz
corespunztor intrrile / ieirile. Primul dintre ele execut who, cellalt sort, iar printele
ateapt terminarea lor. Sursa este prezentat n programul de mai jos.

//whoSort.c
//Lanseaza in pipe comenzile shell: $ who | sort
#include <unistd.h>

main (){

int p[2];
pipe (p);
if (fork () == 0) { // Primul fiu
dup2 (p[1], 1); //redirectarea iesirii standard
close (p[0]);
Procesul parinte Procesul fiu
Nucleu
pipe
Sensul datelor
fd[0]
fd[1]
fd[0]
fd[1]
read
write
write
read
125
execlp ("who", "who", 0);
}
else if (fork () == 0) { // Al doilea fiu
dup2 (p[0], 0); // redirectarea intrarii standard
close (p[1]);
execlp ("sort", "sort", 0);//executie sort
}
else { // Parinte
close (p[0]);
close (p[1]);
wait (0);
wait (0);
}
}

Observatie: pentru a se nelege mai bine exemplul de mai sus, invitm cititorul s citeasc
din manualele Unix prezentarea apelului sistem dup2. Aici apelul dup2 are ca paramentru
un descriptor pipe.

5.3.3. Comunicarea ntre procese prin FIFO

5.3.3.1. Conceptul de FIFO

Cel mai mare dezavantaj al lui pipe sub Unix este faptul c poate fi utilizat numai n
procese nrudite: procesele care comunic prin pipe trebuie s fie descendeni din procesul
creator al lui pipe. Aceasta deoarece ntregii descriptori de citire/scriere din/n pipe sunt unici
i sunt transmii proceselor fiu ca urmare a apelului fork().

In jurul anului 1985 (Unix System V), a aprut conceptul FIFO ( pipe cu nume). Acesta este
un flux de date unidirecional, accesat prin intermediul unui fiier rezident n sistemul de
fiiere. Incepnd cu Unix System V, exist fiiere de tip FIFO. Spre deosebire de pipe,
fiierele FIFO au nume i ocup un loc n sistemul de fiiere. Din aceast cauz, un FIFO
poate fi accesat de orice dou procese, nu neaprat cu printe comun. Atenie ns: chiar dac
un FIFO exist ca fiier n sistemul de fiiere, pe disc nu se stocheaz nici o dat care trece
prin canalul FIFO, acestea fiind stocate i gestionate n buffer-ele nucleului sistemului de
operare!

Conceptual, canalele pipe i FIFO sunt similare. Deosebirile eseniale dintre ele sunt
urmtoarele dou:
- suportul pentru pipe este o poriune din memoria RAM gestionat de nucleu, n timp
ce FIFO are ca suport discul magnetic;
- toate procesele care comunic prin-un pipe trebuie s fie descendente ale procesului
creator al canalului pipe, n timp ce pentru FIFO nu se cere nici o relaie ntre
procesele protagoniste.

Crearea unui fifo se poate face folosind unul dintre apelurile:

int mknod (char *numeFIFO, int mod, 0);
126
int mkfifo (char *numeFIFO, int mod);

sau folosind una dintre comenzile shell:

$ mknod numeFIFO p
$ mkfifo numeFIFO

- Prin stringul numeFIFO este specificat numele "fiierului" de tip FIFO.
- Argumentul mod, n cazul apelurilor sistem, reprezint drepturile de acces la acest fiier.
In cazul apelului mknod, mod trebuie s specifice flagul S_IFIFO, pe lng drepturile de
acces la fiierul FIFO (se leag prin operatorul |). Acest flag este definit n
<sys/stat.h>.
- Pentru crearea unui FIFO cu apelul sistem mknod, cel de-al treilea parametru este
ignorat (trebuie ns specificat, de aceea am pus 0).
- De remarcat c trebuie specificat "p" (de la pipe cu nume), ultimul parametru al comenzii
shell mknod.

Menionm c cele dou apeluri de mai sus, dei sunt specificate de POSIX, nu sunt
amndou apeluri sistem pe toate implementrile de Unix. Astfel, pe FreeBSD sunt prezente
ambele apeluri sistem mknod() i mkfifo(), dar pe Linux i Solaris exist numai apelul
sistem mknod(), funcia de bibliotec mkfifo() fiind implementat cu ajutorul apelului
sistem mknod(). Cele dou comenzi shell sunt ns disponibile pe majoritatea
implementrilor de Unix. Sub sistemele Unix mai vechi, comenzile mknod i mkfifo sunt
permise numai super-user-ului. Incepnd cu Unix System V 4.3 ele sunt disponibile i
utilizatorului obinuit.

tergerea (distrugerea) unui FIFO se poate face fie cu comanda shell rm numeFIFO, fie cu
un apel sistem C unlink() care cere un descriptor pentru fiierul FIFO.

Odat ce FIFO este creat, el trebuie s fie deschis pentru citire sau scriere folosind apelul
sistem open. Precizarea sau nu a flagului O_NDELAY la apelul sistem open are efectele
indicate n tabelul urmtor.

Condiii normal setat O_NDELAY
deschide FIFO
read-only, dar nu
exist proces de
scriere n FIFO
ateapt pn cnd apare un proces care
deschide FIFO pentru scriere
revine imediat fr a
semnala eroare
deschide FIFO
write-only, dar nu
exist proces de
citire din FIFO
ateapt pn apare un proces pentru citire revine imediat cu
semnalarea de eroare:
variabila errno va
deveni ENXIO
citire din FIFO sau
din pipe, dar nu
exist date de citit
ateapt pn cnd apar date n pipe sau
FIFO, sau pn cnd nu mai exist proces
deschis pentru scriere. Intoarce numrul de
date citite dac apar noi date, sau 0 dac nu
mai exist proces de scriere
revine imediat, cu
ntoarcerea valorii 0
scrie n FIFO sau ateapt pn cnd se face spaiu disponibil, revine imediat, cu
127
pipe, dar acesta
este plin
apoi scrie attea date, ct i permite spaiul
disponibil
ntoarcerea valorii 0

Aceste reguli trebuie completate cu regulile de citire/scriere de la nceputul capitolului despre
comunicaii prin fluxuri de octei. De asemenea, nainte de a fi folosit, un canal FIFO trebuie
s fie n prealabil deschis pentru citire de un proces i deschis pentru scriere de alt proces.

5.3.3.2. Exemplu: aplicare FIFO la comunicare client / server

Modelul de aplicaie client / server este clasic n programare. In cele ce urmeaz vom ilustra
o schem de aplicaii client / server bazate pe comunicaii prin FIFO. Pentru a se asigura
comunicarea bidirecional se folosesc dou FIFO-uri. Pentru partea specific aplicaiei, se
folosesc metodele client(int in, int out) i server(int in, int out).
Fiecare dintre ele primete ca i parametri descriptorii de fiiere, presupuse deschise, prin
care comunic cu partenerul.

In cele dou programe care urmeaz este schiat schema serverului i a clientului. Cele dou
programe presupun c cele dou canale FIFO sunt create, respectiv terse, prin comenzi Unix.

Programul server:

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <stdio.h>
#include <unistd.h>

#include "server.c"

#define FIFO1 "/tmp/fifo.1"
#define FIFO2 "/tmp/fifo.2"

main() {
int readfd, writefd;

- - - - - - - - - - - - - -

readfd = open (FIFO1, 0));

writefd = open (FIFO2, 1));

for ( ; ; ) { // bucla de asteptare a cererilor
server(readfd, writefd);
}

- - - - - - - - - - - - - -

close (readfd);
close (writefd);
}

Programul client:

128
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/errno.h>
#include <stdio.h>
#include <unistd.h>

#include "client.c"

extern int errno;

#define FIFO1 "/tmp/fifo.1"
#define FIFO2 "/tmp/fifo.2"

main() {
int readfd, writefd;

- - - - - - - - - - - - - -

writefd = open (FIFO1, 1));

if ((readfd = open (FIFO2, 0));

client(readfd, writefd);

- - - - - - - - - - - - -

close (readfd);
close (writefd);
}

129

5.4. Interpretoare ale fiierelor de comenzi

5.4.1. Funcionarea unui interpretor de comenzi shell

Un interpretor de comenzi (shell) este un program special care furnizeaz o interfa ntre
nucleul sistemului de operare Unix (kernel-ul) i utilizator. Din aceast perspectiv, a
asigurrii legturii ntre utilizator i sistem, un shell poate fi privit diferit:

1. limbaj de comand care asigur interfaa dintre calculator i utilizator. In momentul n
care un utilizator i deschide o sesiune de lucru, n mod implicit, un shell se
instaleaz ca interpretor de comenzi. Shell-ul afieaz la ieirea standard (asociat de
obicei unui terminal) un prompter, invitnd astfel utilizatorul s introduc comenzi
sau s lanseze n execuie fiiere de comenzi, eventual parametrizate.

2. limbaj de programare, ce are ca element de baz (element primitiv) comanda Unix
(similar semantic cu instruciunea de atribuire din limbajele de programare). Ca i
element primitiv de dirijare a succesiunii elementelor de baz este valoarea codului
de retur al ultimei comenzi executate: valoarea 0 nseamn true, valoare nenul
nseamn false (corespondentul din limbajele de programare clasice este condiia).
Shell-urile dispun de conceptele de variabil, constant, expresie, structuri de control
i subprogram. Spre deosebire de alte limbaje de programare, expresiile cu care
lucreaz shell-urile sunt preponderent iruri de caractere. In ceea ce privete cerinele
sintactice, acestea au fost reduse la minim prin eliminarea parantezelor de delimitare a
parametrilor, a diferitelor caractere de separare i terminare, a declaraiilor de
variabile, etc.

un shell lansat n execuie la deschiderea unei sesiuni de lucru va rmne activ pn la
nchiderea respectivei sesiuni. Odat instalat, acesta lucreaz conform algoritmului urmtor:

CtTimp (nu s-a nchis sesiunea)
Afieaz prompter;
Citete linia de comand;
Dac ( linia se termin cu '&' ) atunci
Creaz un proces i-i d spre execuie comanda
Nu ateapt ca execuia s se termine
Altfel
Creaz un proces i-i d spre execuie comanda
Ateapt s se termine execuia comenzii
SfDac
SfCtTimp

Este important s remarcm, din algoritmul de mai sus, cele dou moduri n care o comand
poate fi executat:
- modul foreground - execuie la vedere. In acest gen de execuie sh lanseaz execuia
comenzii, ateapt terminarea ei dup care afieaz din nou prompterul pentru o nou
comand. Acesta este modul implicit de execuie al oricrei comenzi Unix.
130
- modul background - execuie n fundal, ascuns. In acest gen de execuie sh lanseaz
procesul care va executa comanda, dar nu mai ateapt terminarea ei ci afieaz
imediat prompterul, oferind utilizatorului posibilitatea de a lansa imediat o nou
comand. Comada care se dorete a fi lansat n background trebuie s se ncheie cu
caracterul special '&'.

Intr-o fereastr (sesiune) de lucru Unix se pot rula oricte comenzi n background i numai
una n foreground. Iat, spre exemplu, trei astfel de comenzi, dou lansate n background - o
copiere de fiier (comanda cp) i o compilare (comanda gcc) i una n foreground - editare
de fiier (comanda vi):
cp A B &
gcc x.c &
vi H

5.4.2. Programarea n shell

5.4.2.1. Scurt prezentare a limbajului sh

In cele ce urmeaz vom prezenta gramatica limbajului sh cel mai simplu shell de sub Unix.
Vom pune n eviden principalele categorii sintactice, semantica / funcionalitatea fiecrei
astfel de categorii se deduce uor din context.

Vom considera urmtoarele convenii, pe care le folosim doar n scrierea regulilor gramaticii:
- O categorie gramatical se poate defini prin una sau mai multe alternative de definire.
Alternativele se scriu cte una pe linie, ncepnd cu linia de dup numele categoriei
gramaticale, astfel:
categorieGramatical:
alternativa_1 de definire
- - - -
alternativa_n de definire
- [ ]? Semnific faptul c, construcia dintre paranteze va aprea cel mult odat.
- [ ]+ Semnific faptul c, construcia dintre paranteze va aprea cel puin odat.
- [ ]* Semnific faptul c, construcia dintre paranteze poate s apar de 0 sau mai multe
ori.

Folosind aceste convenii, sintaxa limbajului sh (n partea ei superioar, fr detalii) este
descris n fig. 2.2.

Semnificaia unora dintre elementele sintactice din fig. 2.2 este:
- cuvnt: secven de caractere diferite de caracterele albe (spaiu, tab)
- nume: secven ce ncepe cu liter i continu cu litere, cifre, _ (underscore)
- cifra: cele 10 cifre zecimale

O comanda sh poate avea oricare dintre cele 9 forme prezentate. Una dintre modalitile de
definire este cea de comandElementar, unde o astfel de comand elementar este un ir de
131
elemente, un element putnd fi definit n 10 moduri distincte. O legarePipe este fie o singur
comand, fie un ir de comenzi separate prin caracterul special '|'. In sfrit, listaCom este o
succesiune de legarePipe separate i eventual terminate cu simboluri speciale.

Se poate observa c, n conformitate cu gramatica de mai sus, sh accept i construcii fr
semantic! De exemplu, comand poate fi o comandElementar, care s conin un singur
element, format din >&-;. O astfel de linie este acceptat de sh, fiind corect din punct de
vedere sintactic, dei nu are sens din punct de vedere semantic.

Shell-ul sh are un numr de 13 cuvinte rezervate. Lista acestora este urmtoarea:
if then else elif fi
case in esac
for while until do done

Structurile alternative if i case sunt nchise de construciile fi, respectiv esac, obinute prin
oglindirea cuvintelor de start. In cazul ciclurilor repetitive, sfritul acestora este indicat prin
folosirea cuvntului rezervat done. Nu s-a folosit construcia similar corespunztoare lui do,
deoarece od este numele unui comenzi clasice Unix.

Incheiem acest subcapitol cu prezentarea sintaxei unor construcii rezervate, precum i a
unor caractere cu semnificaie special n shell-ul sh.
a) Construcii sintactice:
| legare pipe
&& legare andTrue
|| legare orFalse
; separator / terminator comand
;; delimitator case
(), {} grupri de comenzi
< << redirectri intrare
> >> redirectri ieire
&cifra, &- specific intrare sau ieire standard
b) Machete i specificri generice:
* nlocuiete orice ir de caractere
? nlocuiete orice caracter
[...] nlocuiete cu orice caracter din ...
Observaie: aceste machete i specificri generice nu trebuie confundate cu convenia
propus la nceputul subcapitolului pentru scrierea gramaticii limbajului sh


comand:
comandElementar
( listaCom )
{ listaCom }
if listaCom then listaCom [ elif listaCom then listaCom ]* [ else listaCom ]? fi
case cuvant in [ cuvant [ | cuvant ]* ) listaCom ;; ]+ esac
for nume do listaCom done
for nume in [ cuvant ]+ do listaCom done
while listaCom do listaCom done
until listaCom do listaCom done
132

comandElementar:
[ element ]+

listaCom:
legarePipe [ separator legarePipe ]* [ terminator ]?

legarePipe:
comanda [ | comanda ]*

element:
cuvnt
nume=cuvnt
>cuvnt
<cuvnt
>>cuvnt
<<cuvnt
>&cifra
<&cifra
<&-
>&-

separator:
&&
||
terminator

terminator:
;
&

5.4.2.2. Variabile sh i mecanisme de substituie

Shell-urile permit dou tipuri de substituii: substituia cu ieire standard i substituia cu
valoarea unei variabile shell.

O construcie avnd urmtoarea form:

`sir`

adic un ir de caractere cuprins ntre dou caractere accent grav sau apostrof invers (`)
reprezint un mecanism de substituie care acioneaz astfel: interpretorul de comenzi shell
implicit va interpreta irul dintre cele dou apostroafe inverse ca pe o comand Unix pe care
o va executa. Intreaga construcie, inclusiv apostroafele inverse, va fi nlocuit cu rezultatul
execuiei acestei comenzi.

De exemplu, dac directorul curent este /home/user1, urmtoarea comand lansat n
linia de comand:
133
$ echo Va aflati in directorul `pwd`!

va afia la ieirea standard:
$ Va aflati in directorul /home/user1!

Dac n schimb se lanseaz:
$ echo Va aflati in directorul pwd!

rezultatul execuiei va fi:
$ Va aflati in directorul pwd!

Variabilele shell sunt nume predefinite de shell-ul curent sau definite de ctre utilizator, ale
cror valori sunt iruri de caractere. Chiar dac ntr-un anumit context o variabil este
interpretat ca un numr, reprezentarea acesteia se face printr-un ir de cifre zecimale scrise
n cod ASCII.

Definirea unei variabile coincide cu atribuirea unei valori iniiale pentru ea i se face printr-o
construcie de urmtoarea form:

$ nume=cuvant

In urma evalurii, shell-ul creeaz o variabil denumit nume, avnd ca valoare irul de
caractere indicat prin cuvant. Trebuie precizat c nainte i dup semnul = nu trebuie s
apar spaiu! Dac se dorete ca n irul cuvant s apar i unul sau mai multe spaii, atunci
acestea trebuie scrise folosind mecanismul de evitare.

O variabil shell este local procesului n care a fost definit. Cu toate acestea exist
posibilitatea ca ea s fie motenit de ctre procesele fiu ale procesului curent, dac n
procesul care definete variabila apare o declaraie de forma:

$ export nume

unde nume indic variabila care se dorete a fi motenit de ctre procesele fiu.

Substituirea valorii unei variabile shell se poate specifica n mai multe moduri:
$nume
${nume}
${nume-cuvant}
${nume=cuvant}
${nume+cuvant}
${nume?cuvant}

Varianta aleas depinde de specificul situaiei. Ne vom opri numai la primele dou modaliti
prezentate, care dau ca rezultat valoarea variabilei sau irul vid dac variabila nu este definit.
A doua form de specificare se folosete n cazul n care prima modalitate nu permit
identificarea unic a numelui de variabil (de exemplu cnd acesta apare ntr-un ir de
caractere).
Prezentm n continuare cteva exemple simple de utilizare a acestor construcii. Considerm
c de la tastatur se introduc succesiv urmtoarele trei linii:
$ Fruct=Mar
134
$ aperitiv=tuica\ batrana
$ echo Dupa $aperitiv mananca $Fruct

In momentul execuiei comenzii echo, care cere afiarea unei linii, va avea loc i substituirea
variabilelor Fruct i aperitiv, cu valorile lor, rezultatul fiind:
Dupa tuica batrana mananca Mar

Dac n schimb se lanseaz comanda:
$ echo Salba de $Fructgaritare

rezultatul afiat va fi:
Salba de

deoarece shell-ul va caut s substituie valoarea variabilei Fructgaritar, care nu este
definit i drept urmare are ca valoare irul vid. Pentru a evita astfel de situaii se folosete a
doua form de specificare a unei substituii:
$ echo Salba de ${Fruct}garitare

Rezultatul execuiei comenzii este:
Salba de Margaritare

Orice proces creat de ctre shell motenete o serie de variabile standard, cu nume
predefinite. Totalitatea acestor variabile formeaz aa-numitul mediu Unix al procesului
(environment). In continuare vom prezenta cteva dintre aceste variabile:

HOME indic directorul gazd al utilizatorului, cel n care intr automat la deschiderea sesiunii
de lucru.

PATH indic cile de cutare ale fiierelor executabile. In momentul lansrii unei comenzi,
shell-ul caut n fiecare dintre cile specificate n PATH un fiier cu numele acesteia.
Separarea cilor n irul PATH se face prin simbolul : (dou puncte), iar cutarea se face de la
stnga spre dreapta. In momentul n care se gsete prima potrivire cutarea se oprete.
Trebuie precizat c operaia de cutare se face numai n cile definite n PATH, nu i n
directorul curent, exceptnd cazul n care acesta este adugat n PATH.

Utilizatorul poate s modifice dup dorin valoarea acestei variabilei. De exemplu, pentru a
aduga la cile deja existente directorul curent, directorul gazd i subdirectorul bin al
acestuia, se va lansa:
$ PATH=${PATH}:.:${HOME}:${HOME}/bin

LOGNAME conine numele sub care utilizatorul a deschis sesiunea de lucru (prin login, telnet,
ssh).

SHELL are ca valoare tipul de interpretor shell folosit.

TERM conine tipul de terminal folosit.

135
MAIL indic fiierul care conine pota electronic a utilizatorului. Dac variabila de mediu
MAILCHECK nu este setat, shell-ul curent va informa utilizatorul n momentul n care un
nou mesaj este depus n fiierul specificat.

MAILCHECK fixeaz intervalul de timp la care se va face controlul existenei mesajelor
primite prin pota electronic.

MAILPATH permite precizarea unei liste de nume de fiiere separate prin caracterul : (dou
puncte) pe care shell-ul curent le va monitoriza pentru a sesiza primirea unui nou mesaj.
Fiecare nume de fiier poate fi urmat de semnul % i de un mesaj ce va fi afiat n momentul
n care s-a primit un mesaj nou (mesajul implicit este You have mail).

IFS conine separatorii shell pentru cuvinte. In mod implicit acetia sunt: spaiul, caracterul
<TAB> i retur de car.

PS1 conine prompterul principal Unix. Acesta difer n funcie de distribuie (de exemplu,
pentru shell-ul Bourne, prompterul implicit pentru utilizatorii obinuii este "$", respectiv "#"
pentru superuser).

Aa cum am vzut, o comand Unix are forma:

$ comanda arg1 arg2 ... argn

Dac presupunem c numim prin comanda numele unui fiier de comenzi (script) care va fi
interpretat de ctre shell-ul implicit, atunci att numele comenzii, ct i primele 9 (nou)
argumente, pot fi utilizate n mod direct n interiorul scriptului n maniera parametrilor
formali, aa cum se vede mai jos:

$ comanda arg1 arg2 ... arg9 arg10 ... argn
^ ^ ^ ... ^
| | | ... |
$0 $1 $2 ... $9

Astfel, $0 desemneaz comanda, n timp ce $i desemneaz argi (al i-lea argument din
linia de comand) unde i poate lua valori ntre 1 i 9 inclusiv. In cazul n care sunt mai
puin de 9 argumente, cele absente au ca valoare irul vid. Dac n schimb, comanda este
lansat cu mai mult de 9 argumente, se vor reine toate, dar la un moment dat vor putea fi
referite doar primele 9 prin intermediul construciilor de forma $1 pn la $9, plus numele
comenzii reinut n $0. De asemenea, tot n contextul unui script, urmtoarele construcii au
semnificaie special:
- $# ntoarce numrul argumentelor comenzii (numrul n de mai sus);
- $* indic toate argumentele liniei de comand, privite ca un singur string:
"$1 $2 . . . $n";
- $@ indic toate argumentele liniei de comand, ca succesiune de stringuri:
"$1" "$2" . . . "$n";
- $- indic argumentul ce conine opiunile liniei de comand;
- $? ntoarce codul de terminare (retur) al comenzii precedente (0 nseamn succes);
- $! indic numrul (PID al) ultimului proces lansat n background;
136
- $$ indic numrul (PID al) procesului printe.

5.4.2.3. Structura de control if din sh

Sintaxa structurii este urmtoarea:

if listaCom then listaCom [ elif listaCom then listaCom
]*
[ else listaCom ]? fi

Se poate vedea din specificarea sintaxei c n cadrul unei instruciuni if pot s apar ori de
cte ori perechi elif ... then .... De asemenea, nainte de sfritul instruciunii,
poate aprea, cel mult o dat, construcia else ....

Inainte de a explica modul de execuie, dorim s atragem atenia asupra unor aspecte lexicale.
Unele shell-uri pretind ca fiecare (sau numai unele) dintre cuvintele rezervate if, then,
elif, else, fi s fie primele cuvinte din linie. De aceea recomandm ca n programe
liniile if s apar astfel:
if listaCom
then listaCom
elif listaCom
then listaCom
- - - - - - - - - - - -
elif listaCom
then listaCom
else listaCom
fi

Lista de comenzi care urmeaz dup if, ca i listele de comenzi care urmeaz dup elif au
un dublu rol: de execuie a comenzilor din list i de fixare a valorii de adevr a execuiei. O
execuie are valoarea TRUE dac codul de retur al ultimei execuii din lista de comenzi are
valoarea zero. Execuia are valoarea FALSE dac codul de retur are valoare nenul.

Listele de comenzi de dup then, ca i lista de comenzi de dup else au doar valori de
execuie.

Succesiunea de evenimente care au loc la ntlnirea unei comenzi if este urmtoarea:
- Se execut lista de comenzi ce urmeaz dup if. Dac execuia fixeaz valoarea
TRUE, (condiia if este adevrat), atunci se execut lista de comenzi de dup then
i execuia lui if se termin (se trece la instruciunea care urmeaz dup fi). In caz
contrar (lista de comenzi de dup if fixeaz FALSE) se trece la pasul urmtor:
- Dac exist (una sau mai multe) construcii elif, atunci se execut, pe rnd, listele
de comenzi care urmeaz dup elif, pn cnd una dintre ele fixeaz valoarea
TRUE. Apoi se execut lista de comenzi de dup then - ul corespunztor i
execuia lui if se termin. In caz contrar (fie nu exist elif, fie toate listele de
comenzi de dup elif - uri au fixat FALSE) se execut pasul urmtor:
137
- Dac exist else atunci se execut lista de comenzi de dup else i execuia lui if
se termin. In caz contrar (nu exist else):
- Execuia lui if se termin i se trece la execuia comenzii ce urmeaz dup fi.

In continuare vom prezenta, n dou variante, un fiier de comenzi care afieaz liniile -
ordonate alfabetic - ale unui fiier text. Numele fiierului va fi dat ca prim argument al liniei
de comand. O prim variant este::

if [ $# -eq 0 ]
then echo "Trebuie dat un nume de fisier"
else sort <$1 | more
fi

Varianta prezentat controleaz doar dac s-a dat un argument la linia de comand. O
verificare mai amnunit este realizat n a doua variant:


if [ $# -eq 0 ]
then echo "Trebuie dat un nume de fisier"
elif [ ! \( -r $1 \) ]
then echo "Fisierul $1 nu exista"
else sort <$1 | more
fi

5.4.2.4. Structuri de control repetitive sh

Shell conine patru structuri repetitive: for n dou variante, while i until:

for nume
do
listaCom
done
for nume in [ cuvant ]+
do
listaCom
done
while listaCom
do
listaCom
done
until listaCom
do
listaCom
done

Construcia for
Aceast construcie este cel mai des folosit pentru structurile repetitive shell. Ea are dou
forme, ambele folosind o variabil shell de control indicat prin nume.

In prima form, variabila nume ia toate valorile parametrilor din linia de comand: $1, $2,
..., $#, (de fapt valorile sunt luate din variabila $@). Pentru fiecare dintre acestea, execut
comenzile din corpul ciclului: listaCom.

In forma a doua, cuvntul sau lista de cuvinte care urmeaz dup in desemneaz cuvinte
simple separate prin spaii, sau specificri generice care se expandeaz la numele tuturor
138
fiierelor din directorul curent care se potrivesc, rezultnd n final o list de elemente.
Variabila nume ia pe rnd ca valori aceste elemente i pentru fiecare dintre ele execut
corpul ciclului: listaCom.

S dm cteva exemple. Mai nti sortri i afiri pentru mai multe fiiere:
for fiier
do
sort <$fiier | more
done

S presupunem c numele fiierului de mai sus este SORT. Atunci, comanda:
$ SORT A b C

va genera i executa comenzile:
sort <A | more
sort <b | more
sort <C | more

Acelai efect va fi obinut dac fiierul SORT va conine n interiorul lui numele fiierelor:

for fiier in A b C
do
sort <$fiier | more
done

iar lansarea se va face:
$ SORT

In sfrit, vor fi sortate, lansnd aceeai comand, toate fiierele din directorul curent al cror
nume se termin cu escu, dac fiierul de comenzi este:

for fiier in *escu
do
sort <$fiier | more
done

Exemplul de mai jos transmite un mail la toi utilizatorii conectai:

for x in `who | cut -f1 -d ' ' `
do
mail -s "Salutari celor conectati" ${x}@scs.ubbcluj.ro
<<MESAJ
Ne cerem scuze ca va deranjam. Am trimis acest mail doar
ca si un test pentru structura de control for din shell.
MESAJ
done

Construciile while i until
Aceste construcii sunt oarecum similare, ambele executnd mai nti listaCom de dup
cuvntul while sau until. In funcie de codul de retur obinut se execut listaCom din
corpul ciclului (dintre do i done) i apoi se reia secvena listaCom (de dup while sau
until), sau execuia ciclului se ncheie. Execuia ciclului while se termin cnd n urma
139
procesrii listei de comenzi, listaCom se primete codul de retur 0. Spre deosebire de
while, pentru ncheierea execuiei ciclului repetitiv until este necesar s se ntoarc un
numr nenul.

Iat spre exemplu n figura urmtoare programul de afiare sortat a unor fiiere cu numele
date prin argumentele din linia de comand, descris nti folosind while i apoi folosind
until:

while [ $# -gt 0 ]
do
if [ -s $1 ]
then sort <$1 | more
else echo "$1 nu exista"
fi
shift
done
until [ $# -eq 0 ]
do
if [ -s $1 ]
then sort <$1 | more
else echo "$1 nu exista"
fi
shift
done

Construciile true, false, break, continue
Aceste instruciuni sunt simple ns execuia lor are sens doar n contextul structurilor de
control ciclice.

Intruciunile break i continue se refer la prsirea, respectiv reiterarea ciclurilor
declarate prin construciile for, while sau until. Construciile sunt preluate din limbajul
C (unde se refer doar la ciclurile cele mai interioare) i extinse de ctre shell. Sintaxele lor
sunt urmtoarele:

break [ n ]
continue [ n ]

Comanda break cere prsirea corpului unui ciclu i continuarea execuiei cu comanda
care urmeaz ciclului (urmtoarea instruciune dup done). Dac parametrul n lipsete,
atunci este prsit ciclul cel mai interior care conine comanda break. Dac este prezent n i
break este coninut n cel puin n cicluri incluse unul n altul, atunci execuia continu cu
comanda aflat dup cel de-al n-lea ciclu (dup cel de-al n-lea cuvnt done).

Comanda continue reia execuia corpului unui ciclu. In absena lui n reitereaz ciclul cel
mai interior, altfel este reiterat cel de-al n-lea ciclu n care este inclus continue (naintea
celui de-al n-lea cuvnt do). Reiterarea nseamn pentru for c variabila shell de ciclare
primete urmtoarea valoare, iar pentru while i until reexecuia listaCom care
urmeaz dup while sau until.

5.4.2.5. Exemplul 1: o aplicaie de supraveghere

De multe ori n practic se pune problema supravegherii integritii unui anumit director de
pe un sistem Unix. Presupunem c operaia de supraveghere se va face dup cum urmeaz: la
un interval de timp t specificat n secunde (primul argument din linia de comand),
programul va face rezumatul detaliat al directorului supravegheat (al doilea argument din
linia de comand). Dac acest rezumat coincide cu cel efectuat n urm cu t secunde,
140
programul adoarme la loc pentru nc t secunde, dup care verific iari coincidena
rezumatelor, .a.m.d. La prima neconcordan programul de supraveghere furnizeaz un
mesaj semnalnd situaia i i ncheie execuia. Programul pe care l vom numi
supraveghere i care realizeaz secvena de aciuni descrise anterior, este prezentat n
figura de mai jos.
In legtur cu coninutul programului, facem cteva precizri:
- Variabilele t i DIRECTOR conin intervalul de timp ntre dou verificri, respectiv
numele directorului de supravegheat. Atribuirea unei valori iniiale pentru t se face
prin parametrul $1 dat n linia de comand (primul parametru). In absena acestui
parametru, t va primi implicit valoarea 60. Similar, DIRECTOR poate fi precizat prin
$2 (al doilea parametru din linia de comand), iar n absen va indica directorul
gazd.
- Variabila x reine penultimul rezumat al directorului, iar y reine ultimul rezumat.

#!/bin/sh
DIRECTOR=${2-${HOME}} # in absenta, directorul gazda
t=${1-60} # in absenta, valoarea 60
x=`ls -l $DIRECTOR` # vechiul rezumat
while true
do
sleep $t # asteptare t sec.
y=`ls -l $DIRECTOR` # noul rezumat
if [ "$x" != "$y" ] # sunt egale ?
then
echo "Directorul $DIRECTOR a fost modificat"
exit
else
echo "Nici o schimbare. Mai asteptam $t secunde"
fi
x=$y # se retine ultimul rezumat
Done

Un astfel de program poate fi folosit n diverse situaii. Un scenariu posibil este urmtorul: un
utilizator oarecare i-a deschis dou sesiuni de lucru la dou terminale, iar de la unul dintre
ele, avnd ca director curent directorul gazd $HOME, lanseaz comanda:
$ supraveghere 10

Dac de la cellalt terminal se face o modificare n acest director, de exemplu prin comanda
cat >A atunci, n maximum 10 secunde pe cellalt terminal apare mesajul care anun
modificarea.

Programul poate fi adaptat pentru situaii similare. Dac spre exemplu n locul comenzii
echo se folosete o comand trap adecvat, sau este apelat un alt program indicat de
utilizator, atunci supravegherea poate fi activat de la acelai terminal:
$ supraveghere >ieire &

In cazul n care n directorul curent apar modificri, va intra n lucru comanda trap sau
programul indicat de ctre utilizator.

141
5.4.2.6. Exemplul 2: utilizri break i continue

Pentru a ilustra modalitatea de folosire a comenzilor break i continue considerm
urmtoarea problem: s se gseasc n directorul curent un fiier text care s aib primul
cuvnt de pe o linie mai lung de 5 caractere. Programul care rezolv problema este
urmtorul:

for x in *
do
if [ `file $x | grep -c text` -ne 1 ]
then
echo $x nu e fisier text. Trecem la urmatorul fisier din
director
continue
fi
#in variabila cuv1 se retine primul cuvant de pe o linie
#(consideram ca delimitator este caracterul spatiu)
cat $x | cut -d" " -f1 | while read cuv1
do
#verificam daca linia nu e vida, respectiv lungimea
primului cuvant
if [ ! -z $cuv1 ] && [ `expr length $cuv1` -ge 5 ]
then
echo In $x s-a gasit cuv $cuv1 cu lungimea `expr
length $cuv1`
#se iese din ciclul while
break
fi
done
#se iese din ciclul for
break
done

Selectarea fiierului de tip text se face folosind combinaia a dou comenzi: file i grep.
La ntlnirea primului cuvnt care ndeplinete condiia cerut, se prsesc cele dou cicluri
(while inclus n for), folosind comanda break. Dac n schimb se comenteaz aceste
linii, se vor afia toate liniile care ncep cu un cuvnt de cel puin 5 caractere, din fiierele
text ale directorului din care a fost lansat programul.

5.4.2.7. Exemplul 3: reunirea fiierelor tipribile ntr-unul singur

Se cere un script sh care s fie apelat n modul urmtor:

$ pall director

142
i care s creeze n directorul /tmp un fiier text care s reuneasc toate fiierele tipribile
care sunt depistate n substructura de directoare care ncepe cu director. In fiierul text
rezultat fiecare dintre fiierele componente va fi precedat de un antet de identificare.

Cnd este util o astfel de aplicaie? De exemplu n momentul n care un utilizator care are n
structura de directoare proprii numeroase fiiere de tip text, scripturi shell, surse de programe,
etc. Pentru a evita tiprirea pe rnd a lor, utilizatorul poate opta pentru folosirea unui program
avnd funcionalitatea prezentat anterior.

Programul pall depisteaz, folosind filtrul egrep, toate fiierele ce pot fi tiprite, pe care
le reunete apoi n form tipribil. Sursa programului pall este:

#!/bin/sh
if [ $# -ne 1 ]
then echo "folosire: pall director" >&2
exit 1
fi
if [ ! \( -d $1 \) ]
then echo "$1 nu exista sau nu este director" >&2
exit 2
fi
rm /tmp/${LOGNAME}Afisari /tmp/${LOGNAME}DeListat >/dev/null
2>&1

TotalLinii=0
find $1 -type f -print | sort | while read FISIER
do
if file $FISIER |
egrep "exec|data|empty|reloc|cannot open" >/dev/null
2>&1
then
continue
else
NrLinii=`wc -l <"$FISIER"`
Linie=${TotalLinii}" Pana la "`file $FISIER`
echo $Linie >/dev/tty
echo $Linie >> /tmp/${LOGNAME}DeListat
echo $Linie >> /tmp/${LOGNAME}Afisari
pr -f $FISIER >> /tmp/${LOGNAME}Afisari
TotalLinii=`expr $TotalLinii + $NrLinii`
echo $TotalLinii >/tmp/${LOGNAME}TotalLinii
fi
done
if [ -f /tmp/${LOGNAME}TotalLinii ]
then
read TotalLinii </tmp/${LOGNAME}TotalLinii
rm /tmp/${LOGNAME}TotalLinii
fi
echo "Total general: $TotalLinii linii"
>>/tmp/${LOGNAME}DeListat
143
echo "Total general: $TotalLinii linii"
>>/tmp/${LOGNAME}Afisari
cat /tmp/${LOGNAME}Afisari >>/tmp/${LOGNAME}DeListat
rm /tmp/${LOGNAME}Afisari

Programul creeaz fiierul /tmp/${LOGNAME}DeListat n care apare mai nti un
cuprins ce conine numele fiierelor i lungimile acestora n numr de linii. Astfel, variabila
NrLinii conine, n fiecare moment numrul de linii al fiierului curent. In variabila
TotalLinii acest numr este cumulat de la nceputul procesului de concatenare a
fiierelor.

Pentru informaii suplimentare referitoare la fiierele considerate a fi tipribile, recomandm
consultarea fiierului /usr/share/magic (sub Linux), respectiv /etc/magic (Solaris),
acestea fiind fiierele folosite de ctre comanda file pentru stabilirea tipului.

144

6. Bibliografie general


1. ***: Linux man magyarul, http://people.inf.elte.hu/csa/MAN/HTML/index.htm
2. A.S. Tanenbaum, A.S. Woodhull, Opercis rendszerek, 2007, Panem
Kiad.
3. Alexandrescu, Programarea modern in C++. Programare generic si modele de
proiectare aplicate, Editura Teora, 2002.
4. Angster Erzsbet: Objektumorientlt tervezs s programozs Java, 4KR Bt, 2003.
5. Bartk Nagy Jnos, Laufer Judit, UNIX felhasznli ismeretek, Openinfo
6. Bjarne Stroustrup: A C++ programozsi nyelv, Kiskapu kiad, Budapest, 2001.
7. Bjarne Stroustrup: The C++ Programming Language Special Edition, AT&T, 2000.
8. Boian F.M. Frentiu M., Lazr I. Tambulea L. Informatica de baz. Presa Universitar
Clujeana, Cluj, 2005
9. Boian F.M., Ferdean C.M., Boian R.F., Drago R.C., Programare concurent pe
platforme Unix, Windows, Java, Ed. Albastr, Cluj-Napoca, 2002
10. Boian F.M., Vancea A., Bufnea D., Boian R.,F., Cobrzan C., Sterca A., Cojocar D.,
Sisteme de operare, RISOPRINT, 2006
11. Bradley L. Jones: C# mesteri szinten 21 nap alatt, Kiskapu kiad, Budapest, 2004.
12. Bradley L. Jones: SAMS Teach Yourself the C# Language in 21 Days, Pearson
Education,2004.
13. Cormen, T., Leiserson, C., Rivest, R., Introducere n algoritmi, Editura Computer
Libris Agora, Cluj, 2000
14. Date C.J., Au Introduction to database Systems, Addison-Wesley, 1995
15. Eckel B., Thinking in C++, vol I-II, http://www.mindview.net
16. Ellis M.A., Stroustrup B., The annotated C++ Reference Manual, Addison-Wesley,
1995
17. Frentiu M., Lazr I. Bazele programrii. Partea I-a: Proiectarea algoritmilor
18. Herbert Schildt: Java. The Complete Reference, Eighth Edition, McGraw-Hill, 2011.
19. Horowitz, E., Fundamentals of Data Structures in C++, Computer Science Press,
1995
20. J. D. Ullman, J. Widom: Adatbzisrendszerek - Alapvets, Panem kiado, 2008.
21. Kiad Kft, 1998, http://www.szabilinux.hu/ufi/main.htm
22. Niculescu,V., Czibula, G., Structuri fundamentale de date i algoritmi. O perspectiv
orientat obiect., Ed. Casa Crii de Stiin, Cluj-Napoca, 2011
23. Raffai Mria: UML 2 modellez nyelvi szabvny, Palatia nyomda s kiad, 2005.
24. Ramakrishnan R., Database Management Systems, WCB McGraw-Hill, 1998
25. Robert A. Maksimchuk, Eric J. Naiburg: UML fldi halandknak, Kiskapu kiad,
2006.
26. Robert A. Maksimchuk, Eric J. Naiburg: UML for Mere Mortals, Pearson Education,
2005.
27. Robert Sedgewick: Algorithms, Addison-Wesley, 1984
28. Simon Kroly: Kenyernk Java. A Java programozs alapjai, Presa Universitar
Clujean, 2010.
29. Tmbulea L., Baze de date, Facultatea de matematic i Informatic, Centrul de
Formare Continu i Invmnt la Distan, Cluj-Napoca, 2003
30. V. Varga: Adatbzisrendszerek (A relcis modelltl az XML adatokig), Editura
Presa Universitar Clujean, 2005, p. 260. ISBN 973-610-372-2
145

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