Sunteți pe pagina 1din 93

1

1. Concepte fundamentale de programare cu exemple VisualBasic .NET


n dezvoltarea oricrei aplicaii informatice, de obicei, se parcurge o succesiune bine definit
de pai care pornete de la identificarea i analiza cerinelor problemei i se termin cu lansarea
n exploatare i ntreinerea sistemului (figura1-1). Este un fel de a spune se termin, pentru c
munca echipei de dezvoltare nu se termin dect odat cu ieirea din exploatare a aplicaiei. De
obicei, primele trei activiti i ultimele trei sunt realizate de analiti i proiectani de sistem,
programatorilor fiindu-le rezervat sarcina de a implementa(transpune) ntr-un limbaj de
programare, ntr-o manier ct mai optimizat cu putin, specificaiile tehnice obinute de la
echipa de proiectare a modulelor.

Definirea
problemei
Analiza
cerinelor
Arhitectura
global
Proiectare
detaliat (module)

Algoritmi + structuri
de date

Scrierea codului
modulelor
Testarea
modulelor

Testarea
sistemului
Elaborare
documentaie
Implementare i
ntreinere
Figura 1-1 Secvena de activiti ce o presupune dezvoltarea unei aplicaii informatice

A programa nseamn a scrie secvene de cod ce implementeaz un anumit algoritm, ntr-un


limbaj de programare. Exist accepiunea general c :

Algoritm +limbaj+ structuri de date = program


1.1.

Definitii ( algoritm, date, program, structuri de date).

Dicionarul de Informatic definete algoritmul ca un concept folosit n mod intuitiv pentru a


desemna o multime finit de operaii (instruciuni, comenzi) cunoscute, care exexcutate ntr-o
ordine bine stabilit pornind de la un set de valori (intrri), produc n timp finit un alt set de
valori (ieiri). Noiunea de elgoritm este foarte bine descris chiar de caracteristicile eseniale
ale acestuia:
1. Finitudine. Un algoritm trebuie ntotdeauna s se ncheie dup un numr finit de pai.
2. Claritate. Fiecare pas al unui algoritm trebuie s fie bine definit; aciunile ce trebuie
executate vor fi riguros specificate ntr-o manier care s elimine orice ambiguitate.
Pentru ca un algoritm s poat fi neles de oricine, reprezentarea operaiilor trebuie
cumva formalizat. n acest sens se poate apela la :
a. un limbaj astfel formalizat nct s fie universal valabil : scheme logice i
pseudocod;
b. un limbaj de programare (Java, VB, C++, etc) n care fiecare instruciune are
un neles bine delimitat;
3. Intrri. Un algoritm poate avea zero sau mai multe date de intrare, valori ce i sunt
furnizate fie la momentul iniial (nainte ca algoritmul s nceap s se execute), fie n
mod dinamic, pe msur ce algoritmul se execut.
4. Ieiri. Un algoritm poate avea una sau mai multe valori de ieire, ca rezultat al
operaiilor execute pe parcursul execuiei asupra datelor de intrare (dac acestea
exist)
5. Eficacitate. algoritmul prelucreaza datele initiale si furnizeaza rezultatul scontat;
6. Determinism. Orice algoritm trebuie s fie astfel specificat nct ntotdeauna un
procesor (fie calculatorul fie o persoan cu un creion i o foaie n mn) s poat obine
n mod repetat exact aceleai date de ieire dac aplic operaiile precizate asupra
acelorai date de intrare.
Iat un exemplu de algoritm pentru determinarea rdcinii ecuaie de gradul 1:
Analiza problemei: forma generala a unei ecuatii de gradul I este ax+b=0. Datele de intrare
vor fi coeficientii ecuatiei: a si b. Datele de iesire (rezultatul prelucrarii):
- radacina x a ecuatiei sau
- un mesaj ("x real" sau "nu exista solutie")
Procesul prelucrarii datelor de intrare (algoritmul) poate fi descris astfel:
PAS 1. Se introduc (=se citesc) valorile coeficientilor a, b;
PAS 2. Daca a=0 si b=0 atunci se afiseaza "ecuatia are o infinitate de solutii !";
PAS 3. Daca a=0 si b<>0 atunci se afiseaza "ecuatia nu are solutii !";
PAS 4. Daca a<>0 atunci solutia este x= -b/a;
PAS 5. Afiseaza valoarea lui x;
Datele sunt elemente eseniale ale unui algoritm. Asupra lor se aplic operaiile. Datele sunt
n sine valori cu o anumit semnificaie pentru procesor (cel care mnuiete algoritmul). n
memoria calculatorului orice dat apare ca o succesiune de bii. Modul n care pentru o astfel de
succesiune se asociaz o valoare depinde de interpretarea ce i se d. Datele pot fi:

elementare : data apare ca o entitate indivizibil din punct de vedere al valorii - aici
includem: simboluri (litere sau caractere speciale ) i numere

structurate: colecie de date elementare sau date structurate organizate ntr-o


anumit manier pentru a reprezenta ntr-o form abstractizat anumite noiuni din

lumea real; iat cteva tipuri de date structurate (sau structuri de date): tablouri
unidimensionale sau multidimensionale, liste, arbori, fiiere etc.
Datele structurate vor fi abordate pe larg ntr-o seciune separat

1.1.1.

Reprezentarea datelor elementare n memoria RAM

Dei prin utilizarea unui limbaj de nivel nalt (VB, FoxPro, Java, C, Delphi, etc) datele
elementare sunt manipulate ntr-o manier mult simplificat din perspectiva utilizatorului
limbajului respectiv, orice programator tie c la nivelul sistemului de calcul toate instruciunile
i datele ce alctuiesc un program sunt convertite n iruri de bii (iruri de valori 0 i 1). n cele
ce urmeaz vom prezenta tehnicile de baz prin care datele elementare (simboluri i numere)
sunt reprezentate n memoria intern a calculatorului.
Reprezentarea simbolurilor (litere i caractere speciale)
O metod de a reprezenta datele la nivelul sistemului de clacul const n proiectarea unui
sistem de coduri n care fiecrui simbol i se asociaz o combinaie unic de bii. n vremurile de
nceput ale tehnologiei informaiei au existat mai multe astfel de sisteme de codificare,
multitudinea lor promovnd ambiguitate i dificulti n ncercrile de comunicare ntre mai
multe sisteme de calcul. Pentru a elimina aceast situaie se impunea adoptarea unui sistem
standard care s fie implementat de toi productorii de sisteme hardware i software.
n anii 70 American National Standards Institute (ANSI) a dezvoltat sistemul de codificare
ASCII American Standard Code for Information Interchange care a devenit n scurt timp
extrem de popular i care este utilizat pe scar larg i astzi. Iniial acest sistem de codificare
utiliza un model de 7 bii (o niruire de 0 i 1) pentru a reprezenta literele mari i mici ale
alfabetului englez, caracterele de punctuaie, cifre de la 0 la 9 i anumite informaii de control.
Astzi ASCII reprezint simbolurile printr-o combinaie unic de 8 bii care nu numai c se poate
stoca foarte uor n memorie (celul de memorie= 1 byte (octet) =8 bii) dar ofer posibilitatea
reprezentrii unui numr de 256 (28)de simboluri diferite, suficiente pentru a reprezenta spre
exemplu toate caracterele ce pot fi introduse prin intermediul tastaturii. Spre exemplu, dac
utilizm harta de coduri ASCII (www.ansi.org ), irul de caractere Hello va fi reprezentat astfel:
01001000 01100101 01101100 01101100 01101111 00101110

Pe lng ASCII, care este cel mai utilizat sistem de codificare la momentul actual, exist i
alte sisteme care ofer posibilitatea reprezentrii caracterelor ntr-o manier mult mai extensiv.
Spre exemplu, sistemul de codificare UNICODE (dezvoltat ca urmare a cooperrii ntre liderii de
pia n industria hardware i software) utilizeaz 16 bii pentru a reprezenta n mod unic un
caracter oferind astfel 65536 (216) de combinaii unice, suficiente pentru a acoperi necesitile
alfabetelor chinezesc i japonez.
Reprezentarea valorilor numerice
Metoda de stocare intern a informaiei sub form de combinaii unice ntr-un sistem de
coduri este totui ineficient atunci cnd datele reprezint valori numerice. Astfel, dac ar fi s
apelm la ASCII pentru a reprezenta numrul 37, ar fi necesari 16 bii (2 octei) , cte un octet
pentru fiecare cifr. Prin aceast tehnic un numr mai mare de 99 nu va putea fi stocat ntr-un
interval de 16 bii. O abordare mult mai eficient ar fi reprezentarea numrului nu n baza zece
( cifre de la 0 la 9 ) ci n baza doi (0 i 1).

Sistemele de numerotaie utilizeaz n general o asociere poziie-cantitate, cu alte cuvinte


poziia unei cifre ntr-un numr determin semnificaia acelei cifre. Spre exemplu semnificaia
numrului 375 n baza zece se obine nmulind fiecare cifr cu 10 la puterea i, unde i este
indicele de poziie numrnd de la dreapta la stnga ncepnd cu 0, astfel: 3x100+7x10+5x1
Notaia binar este utilizat pentru a stoca numere prin intermediul a doar dou cifre: 0 i 1.
n mod similar sistemului zecimal, pentru a obine semnificaia numrului, vom efectua suma
cifrelor ponderate cu factorul de poziie. Fiecrei cifre (0 sau 1) i se asociaz un factor
reprezentnd o putere a lui doi, astfel: cifra cea mai din dreapta se nmulete cu 2 0 , urmtoarea
cifr spre stnga se nmulete cu 2 1 , urmtoarea cu 22 .a.m.d. Astfel, numrul 37 poate fi scris
n baza doi: 100101 = 1x25+0x24+0x23+1x22+0x21+1x20 = 32+0+0+4+0+1=37. Cu alte
cuvinte, numrul de bii utilizai pentru a reprezenta numrul se reduce de la 16 (n ASCII) la 6.
Urmtorul exemplu constituie nruirea numerelor de la 0 la 8 n baza 2:
0
1
10
11
100
101
110
111
1000
Pentru a obine reprezentarea unui numr n baza doi (din baza zece) apelm la urmtorul
algoritm:
Pas1 - mparte numrul la 2 i pstreaz restul;
Pas2. - ct timp rezultatul mpririi nu este 0 continu sa impari noul rezultat la 2 i
memoreaz restul;
Pas3. - o dat ce s-a obinut un rezultat =0 al ultimei mpriri, reprezentarea binar a
numrului se obine prin aezarea resurilor obinute anterior n ordine de la dreapta la stnga
ncepnd cu primul rest obinut (acesta va fi cel mai din dreapta).
Iat un exemplu de aplicare a algoritmului pentru numrul 13 (n sistem binar reprezentat ca
1101):

(1) 13/2=6 rest= 1


(2) 6/2 = 3 rest= 0
(3) 3/2=1 rest= 1
(4) 1/2=0 rest=1
(ultimul ct = 0 stop)
1 1 0 1
Ca urmare a adoptrii acestui sistem, un byte (8 bii) poate stoca numere de la 0 la 255
(00000000 la 11111111) iar prin intermediul a doi octei putem stoca numere de la 0 la 65535.
Obinem astfel o mbuntire drastic fa de utilizarea sistemului ASCII unde pe doi octei
puteau fi reprezentate doar numere n intervalul 0-99.
n practic, datorit complexitii generate de reprezentarea numerelor mari, a semnelor
pentru pozitiv/negativ i a numerelor zecimale, sistemul binar prezentat anterior constituie doar
baza unor sisteme de reprezentare ceva mai complicate. Astfel, exist notaia celor dou

coplemente (pentru numere pozitive/negative) i notaia n virgul mobil (pentru numere


zecimale). Analiza detaliat a acestor sisteme depete ns scopul acestui curs.

1.1.2.

Variabile,pointeri, literali, constante. Operaii fundamentale n algoritmi

Datele unei probleme apar n algoritmi sub form de variabile. n informatic varibila
reprezint un nume atribuit unei adrese (celule) de memorie care stocheaz o valoare. Spunem
astfel, c varibila identific valoarea respectiv. Noiunea de variabil este folosit i n
matematic. De pild, spunem c f(x, y)=2x+3y+5 este funcie de dou variabile independente
x i y. n programare, noiunea de variabil are un neles puin diferit. Mai exact, o variabil
poate lua valori dintr-o mulime bine precizat, care, ca i n matematic, se numete domeniul
de definiie al variabilei, dar la un moment dat variabila are o valoare bine precizat.

O varibil este caracterizat de:

Nume

Tipul datei (domeniul de valori acele valori care pot constitui la un moment dat
valoare curent)

Valoare curent

Domeniu de vizibilitate

Fiecrei variabile i se asociaz un nume. Variabila se identific n algoritm cu acest nume. De


aceea, numele, se mai numete i identificatorul variabilei. Numele de variabile din algoritmi
apar i n programe. Dup ce un program se lanseaz n execuie, fiecrei variabile i se rezerv
n memoria intern a calculatorului o zon n care se nregistreaz valoarea sa iniial. Aceast
valoare se modific pe parcursul execuiei programului. Valoarea care se afl la un moment dat
n zona rezervat unei variabile se numete valoare curent.
Datele prelucrate de un algoritm trebuie s fie de un anumit tip. Tipul de dat este puternic
influenat de limbajul de programare n care va fi scris programul. Ca urmare i varibilele (prin
care se manipuleaz acele date) vor avea un anumit tip. Majoritatea limbajelor de programare
dispun de cteva tipuri standard de date. Dintre acestea menionm tipurile numerice ntregi,
tipurile numerice reale, tipul logic i tipul caracter. Tipurile numerice sunt compatibile ntre
ele. Cu alte cuvinte, se pot determina valorile unor expresii n care apar tipuri numerice diferite.
Nu se pot evalua, ns, expresii n care apar date numerice i date logice, date numerice i
caracter sau date logice i caracter. Pentru a efectua operaii cu tipuri diferite de date,
respectivele valori trebuie mai nti convertite la un tip comun (vom vedea ceva mai trziu cum
se realizeaz acest lucru).
Noiunea de tip de dat este una din noiunile de baz utilizate n limbajele de programare.
Declararea unui tip de date nseamn n esen a preciza o mulime de valori i o mulime de
operaii care se pot efectua cu valorile respective.
Exist ns i varibile care nu conin o valoare ci o adres a unei valori. Aceste tipuri de
varibile se numesc pointeri. Figura 1-2 prezint ntr-o manier simplificat diferena ntre o
variabil i un pointer la nivelul memoriei interne. Astfel, variabila V1 va avea valoarea 1254 iar
varibila V2 va avea ca valoare adresa de memorie a valorii 1254, adic (Adr2).

Variabila

NumeVariabila + (TIP)
+ Valoare

V1+ (INTEGER) +
(Adr2)
1254
(Adr1)

Pointer
V2+ (POINTER) +
(Adr9)
(Adr2)
(Adr8)

Figura 1-2 Varibile si pointeri

Aa cum se poate intui, n acest exemplu ambele variabile, V1 i V2, lucreaz cu aceeai
valoare, cu alte cuvinte ntr-un algoritm, manipularea valorii 1254 se poate efectua prin
intermediul oricreia din cele dou variabile. ntr-un mod formalizat:
V1 1254
V2 ADDR(V1)
SCRIE V1 (se va afisa 1254)
SCRIE V2 (se va afisa (Adr2))
SCRIE DEREF(V2) (se va afisa 1254)
DEREF(V2) 256
SCRIE V1 (se va afisa 256)

n algoritmul de mai sus prin DEREF specificm faptul c se manipuleaz valoarea la care se
refer (spre care puncteaz) variabila V2 i nu valoarea n sine a acesteia care reprezint o
adres de memorie (Adr2).
Pe parcursul dezvoltrii programelor, pot apare anumite date a cror valoare nu se schimb
pe parcursul execuiei. Dac respectivele date sunt utilizate n mod direct, folosim noiunea de
literal: x+2 2 este un literal. Dac ns unui literal i se atribuie chiar de la nceputul execuiei
programului un identificator (un nume), iar pe parcursul programului utilizm acel nume (n mod
similar variabilelor) n locul valorii explicite, spunem c am definit o constant. Constantele
dein toate caracteristicile variabilelor (nume, domeniu, adresa) dar sunt mrimi care nu i
modific valorile n timpul efecturii calculelor. De pild, ntr-un program pentru controlul
traficului aerian la un aeroport, o mrime intens utilizat n calcule este altitudiunea aeroportului
fa de nivelul mrii: s zicem 30m. Dac utilizm direct valoarea 30 n calcule, tranferul
programului la un alt aeroport (plasat s zicem la 40m altit.) va implica modificarea tuturor
liniilor de program ce utilizeaz valoarea respectiv. Dac ns declarm o constant
AltitAeroport 30 i utilizm aceast constant n toate operaiile de calcul, la tranferul
programului nu va trebui dect s modificm valoarea constantei AltitAeroport i s rulm
aplicaia.
Aadar, n orice algoritm manipulm datele prin intermediul variabilelor i a constantelor.
Operaiile fundamentale ce se pot realiza ntr-un algoritm sunt:

Operaii de atribuire determin asocierea unui nume (a unei variabile) cu o valoare. De


multe ori valoarea poate s nu fie o cantitate n sine ci rezultatul evalurii unei expresii. O
expresie presupune mai multe date crora li se aplic operatori, spre exemplu operatori
matematici (+, -, / , *, ^ (ridicare la putere)). Operaia de atribuire este implementat cu notaii
diferite de la un limbaj la altul, dar ntr-o form general ea se noteaz cu pentru a o
diferenia de operatorul logic =.
A 10
B 20
C A+B
Operaii de decizie

- prin care se determin valoare logic a unei propoziii. Presupun

utilizarea operatorilor relaionali (=, <,>, <>, #, <=, >=) i, eventual, a operatorilor logici (AND,
OR, NOT). Valoarea logic obinut se utilizeaz de obicei n cadrul unor structuri de control
alternative.
A 10

Operaia

B 20
IF A<>0 THEN

de

decizie

R -B/A
END IF
Operaii de Intrare/Ieire se refer la furnizarea unor valori iniiale ale variabilelor (citire)
prin intermediul unei componente externe algoritmului sau extragerea valorilor unor variabile i
furnizarea lor pentru afiare/stocare pe un suport extern (scriere).

1.1.3.
Elemente de sintax VB .NET (tipuri de date, variabile, operaii, structuri
de control)
Anatomia unui program VB .NET
1. Un program VB .NET poate fi alctuit din unul sau mai multe module
2. fiecare modul poate fi de un anumit tip
3. modulele uzuale sunt :
a. module ce conin secvene de cod executabile (proceduri i funcii)
b. module ce conin elemente de interfa grafic-utilizator (formulare i
rapoarte)
4. un modul poate conine mai multe secvene de cod executabile separat, denumite
subrutine:
a. proceduri se declar i delimiteaz prin expresiile rezervate SUB / END SUB
b. funcii se declar prin FUNCTION / END FUNCTION
5. pentru fiecare rutin trebuie s se precizeze numele i, eventual parametri (vom
reveni mai trziu asupra acestoir aspecte)
6. fiecare rutin va conine, de regul, trei zone de cod, logic separate i n ordinea
urmtoare:
a. declaraii de variabile utilizate
b. iniializarea variabilelor utilizate

c. expresii i instruciuni de prelucrare a valorilor de intrare pentru a produce


valorile de ieire
7. printre secvenele de cod pot apare i comentarii (text ce nu va fi interpretat de
compilator , prefixat cu apostrof () )

Tipuri de date utilizate de Visual Basic .NET


ncadrarea unei date ntr-o anume categorie este absolut necesar pentru a putea efectua
calcule sau alte prelucrri. Pe lng tipurile fundamentale (numaric i caracter) majoritatea
limbajelor de programare ofer, n plus, cel puin nc un tip: ir de caractere. Un ir de caractere
(String) este o secven caractere care sunt tratate ca o singur entitate. Visual Basic lucreaz
cu iruri de caractere de lungime fix sau variabil. Tabelul 1-1 prezint tipurile de date VB .NET.
Tabelul Nr. 1-1 Tipuri de date VB

Tipul

Descriere

Boolean Denumit i logic, poate lua doar valorile True sau False. True i False sunt
cuvinte rezervate n Visual Basic.
Byte
Date

Memorie
Alocat
Depinde
de
platforma
1 Byte
8 bytes

Valori numerice pozitive, fr zecimale, n intervalul 0 255.


Date calendaristice i timp. Data se ncadreaz n intervalul 1 ianuarie 100 31
decembrie 9999.
Double Valori numerice reale (pot conine zecimale) n intervalul
8 bytes
-1.79769313486232E+308 1.79769313486232E+308. Este denumit i dubl
precizie.
Decimal Valori numerice reale (pot conine zecimale)
16 bytes
Valori in intervalul -32,768 / 32,767
Short
2 bytes
Integer Valori numerice ntregi fr zecimale, n intervalul - -2,147,483,648 / + 2,147,483,647. 4 bytes
Long
Similar cu Integer, dar cu valori n -9,223,372,036,854,775,808 /
8 Bytes
9,223,372,036,854,775,807 Acest tip consum mai mult. Este denumit i long
integer (ntreg lung).
Object Tip special de date, care face referire la obiecte (precum obiectele grafice).
String ir de caractere alfanumerice (pana la 2 mld de caractere UNICODE). Pe lng
cifre i litere se pot include caractere speciale precum ^, %, and @.
Notaia tiinific: 78.932E+6 nseamn 106 * 78.932 adic 78,932,000,000.

Variabile n VisualBasic .NET


ntr-un program se poate lucra cu oricte variabile este necesar, dar nainte de a putea lucra
cu o variabil, aceasta

trebuie declarat,

specificnd numele i tipul acesteia. Unele

limbaje de programare restricioneaz declararea n mod explicit a variabilelor nainte de a le


utiliza pentru a determina de la bun nceput tipul de date ce va fi manipulat prin intermediul
acelei variabile. Alte limbaje ofer o mai mare libertate n lucrul cu variabile astfel nct acestea
pot fi declarate n momentul utilizrii lor ( prin atribuirea direct a unei valori), moment la care
se determin i tipul variabilei respective. Limbajele ce fac parte din platforma .NET ofer
ambele variante de declarare (explicit i implicit), dar prima variant este definit ca implicit
ntr-un proiect .NET.:

Pentru declararea explicit a variabilelor se utilizeaz instruciunea Dim. Aceasta este


plasat la nceputul programului, indicnd c undeva pe parcurs vor fi necesare variabilele
declarate. Formatul instruciunii de declarare este:

Dim <NumeVariabil> As <TipDat>


<NumeVariabil> este definit de ctre utilizator, iar <TipDat> este specificat explicit,
tipurile fiind cele prezentate n tabelul 1-1 sau un tip compozit (dup cum vom vedea mai trziu).
O b s e r v a i e . Numele de variabile pot conine litere, cifre i caracterul de subliniere
(underscore). Nu pot s nceap cu cifre, nu pot conine spaii ori alte caractere speciale. Este
interzis folosirea unor nume care sunt cuvinte-cheie n Visual Basic (nu putem avea o variabil
numit Form, dar putem folosi numele Form15). Aceleai precizri sunt valabile i pentru
constante.
Atunci cnd se execut instruciunea Dim, se rezerv n memorie un spaiu cu dimensiunea
compatibil cu <tipDat> i acestui spaiu i se atribuie numele <NumeVariabil>.
Instruciunea Dim se poate plasa oriunde ntr-o procedur, dar se recomand scrierea sa la
nceputul acesteia.
Nu se pot defini dou variabile cu acelai nume n aceeai procedur.
Operatori n VisualBasic
Spuneam mai devreme c unei variabile i se poate atribui o valoare sub forma unei expresii.
n general o expresie nseamn o niruire de valori (operanzi) i simboluri specializate
(operatori) care poate fi evaluat la momentul execuiei i obinut o valoare drept rezultat.
Fiecare limbaj implementeaz operatori aritmetici, pentru iruri de caractere i logici. n marea
majoritate a cazurilor operatorii aritmetici sunt implementai n mod similar de la un limbaj la
altul (prin simbolurile universal valabile) iar celelalte dou tipuri pot avea implementri diferite.
Tabelul Nr. 1-2. Operatori n Visual Basic

Operator
+
*
/
\
Mod
^
&

AND
OR
NOT

Exemplu

Descriere
Opeartori aritmetici
Sal + Imp
Adun valorile celor dou variablile.
Pret 10000
Scade o valoare din alta.
Total * ProcTVA
nmulete dou valori.
Total / 12
mparte o valoare la alta.
102\4
Calculeaz ctul unei mpriri cu rest.
Calculeaz restul unei mpriri.
6 Mod 4
6 MOD 4=2
X^3
Ridic valoarea X la puterea 3.
Operatori pentru iruri de carcatere
Concateneaz dou iruri (se poate
Nume1 & Nume2
folosi i semnul + care, n cazul irurilor
nseamn concatenare i nu adunare).
Operatori logici
X=True
Y=False
X AND Y = False
X=True
Y=False
X OR Y = True
X=True
NOT X = False

10

XOR

X
True
False
True
False

Y
True
True
False
False

X Xor Y
False
True
True
False

ntr-o exprimare mai direct : Poate fi X sau Y dar niciodat


ambele
Ordinea de efectuare a operaiilor este cea cunoscut: nti ridicarea la putere, apoi
nmulirile i mpririle i la urm adunrile i scderile. Pentru a schimba aceast ordine
(denumit i precedena operatorilor), se utilizeaz parantezele.
Exemplu:

3 + 2 * 4 + 1 = 12
(3 + 2) * (4 + 1) = 25
102/4=25.5
102\4=25
102 Mod 4=2
La folosirea operatorilor aritmetici pentru efectuarea de calcule, tipul de dat al rezultatului,
dac nu este declarat n prealabil, este dat de tipul de dat cel mai precis.
Exemplu:

Dim a as Long, b as Integer


a=25.565689
b=12
c=a+b
Rezultatul, memorat n variabila c, va fi 37.565689. Tipul de dat al variabilei c va fi Long
(tipul variabilei a), deoarece acesta are un grad de precizie mai mare dect tipul Integer (tipul
variabilei a). Dac variabila c ar fi fost declarat n prealabil ca Integer, Visual Basic ar fi rotunjit
automat rezultatul la valoarea 38, deoarece tipul Integer nu are poziii zecimale.
Prin concatenare se obine un ir nou format din cele dou iruri de caractere puse cap la
cap (cel de-al doilea este adugat la sfritul primului). Dac am avea 2 casete de text (txtNume
i txtPrenume) n care utilizatorul a introdus numele, respectiv prenumele, prin concatenarea
celor dou valori am obine numele ntreg, astfel:
strNumePrenume = txtNume & txtPrenume
Exist o mic problem cu instruciunea de mai sus, referitoare la absena spaiului dintre
nume i prenume. Operatorul & nu insereaz automat un spaiu pentru c nu ntotdeauna este
necesar aa ceva. Spaiul trebuie specificat explicit astfel:
strNumePrenume = txtNume & " " & txtPrenume
O b s e r v a i e : Visual Basic folosete pentru concatenare i operatorul +, dar nu-l recomandm deoarece poate produce confuzia (n
mintea programatorului nceptor) cu operatorul pentru adunare. Oricum, nu este greit dac scriem:

strNumePrenume = txtNume + " " + txtPrenume

De asemenea, operatorul & este recomandat atunci cnd se dorete obinerea unui
text prin concatenarea unoir valori de tipuri diferite. n acest caz, operatorul & va ncerca
o conversie automat a tipurilor non-String, spre deosebire de operatorul + care are
genera o eroare. Spre exemplu
Dim a as Integer
Dim b as String
Dim rezultat as String
A=2
B=test
Rezultat=b & a valoarea variabilei Rezultat va fi

test2

11

1.2. Reprezentarea formalizat a algoritmilor


Exist dou modaliti general adoptate pentru reprezentarea unui algoritm:

Schemele logice ansamblu de simboluri grafice ce permit reprezentarea sub form


grafic a unui algoritm. Simbolurile sunt standardizate din 1970 printr-un standard ANSI
X35

Pseudocod

- se materializeaz prin extragerea unui grup de cuvinte din limbajul

natural prin care se traduc structurile de control fundamentale, fr a implementa o


semantic strict. Nu exist un standard precum n cazul schemelor logice.
Tabelul 1-1 prezint n paralel elementele grafice ale schemelor logice i cuvintele pseudocod
eseniale n reprezentarea algoritmilor. Menionm c nu sunt evideniate simbolurile pentru
operaii speciale definite de standrdul X35. De asemenea precizm c pentru pseudocod au fost
alese cuvinte n englez (dei puteau fi i n romn) datorit modului familiar de implementare
n diverse limbaje de programare.
Simbol schem logic
STOP

START
FALSE

Cond

TRUE

AB+C
WRITE a,b,c

READ a,b,c

Pseudocod
BEGIN
END
IF Cond THEN
ELSE
END IF
A=B+C (sau)
AB+C
READ a,b,c
WRITE a,b,c
CALL Proc1

Proc1

Semnificaie
nceput /sfrit algoritm
Bloc
de
decizie
(se
evalueaz condiia Cond).
n
pseudocod
trebuie
evideniat sfritul blocului
Operaie de atribuire i
evaluare expresii de calcul
Citete / Scrie valorile
variabilelor a,b,c
Apel
de
(subprogram)

procedur

Reprezentarea unui algoritm fie prin intermediul schemelor logice (Aranjarea simbolurilor
grafice ntr-o anumit ordine) fie prin pseudocod (enumerarea cuvintelor rezervate ntr-o
anumit ordine) are la baz cteva structuri fundamentale de control ce sunt utilizate n
diverse combinaii pentru a rezolva orice problem algoritmic:

structura secvenial operaiile se execut n ordinea apariiei de sus n jos,

structura alternativ n funcie de rezultatul evalurii unei condiii se execut un


anumit set de operaiuni sau altul. Exist dou subcategorii ale acestei structuri:
o

structura alternativ cu o ramur vid n funcie de evaluarea unei condiii se


execut sau nu un anumit set de operaii

structura alternativ generalizat (multipl- cunoscut i sub numele CASE) un


operand va fi comparat cu un set de valori predefinit

structura iterativ(repetitiv) -

anumite operaii se execut n mod repetat ntr-un

numr finit de pai. Exist urmtoarele subcategorii:


o

structura iterativ cu un numr cunoscut de pai ( FOR) numrul de iteraii


depinde de un contor (o variabil numeric ce crete/descrete pn la un
anumit prag) ce se incrementeaz/decrementeaz cu un anumit factor

structura iterativ cu un numr necunoscut de pai ( WHILE) numrul de


iteraii variaz n funcie de anumite condiii

12

condiionat anterior (WHILE DO) mai nti se evalueaz condiia i apoi se


execut setul de operaii (obs: este posibil ca setul de operaii s nu se execute
vreodat)

condiionat posterior(DO-WHILE) mai nti se execut setul de operaiuni i


apoi se evalueaz condiia pentru a relua pasul anterior sau a trece mai departe
(obs: setul de operaii se va executa macar o dat)

Corpul (subsetul de operaii) unei structuri alternative sau iterative poate fi la rndul su
reprezentat prin oricare din cele trei structuri : secvena, decizia, iteraia.

1.2.1.
Reprezentarea structurilor de control. Scheme logice, Pseudocod, Limbaje
Diverse

13

Schema Logica
START
A1

Pseudocod
BEGIN
A1
B2
CA+B

B2

WRITE C
END

VisualBasic
FoxPro
Structura secvenial
Private Sub Secventa()
DIM a,b,c as Integer
a=1
b=2
c=a+b

a=1
b=2
c=a+b
?c

Console.WriteLine(c)

End Sub
CA+B

Java
public static void
main(String[] args)
{
int a=1;
int b=2;
int c=a+b;
System.out.print(c);
}

Oracle PL/SQL
DECLARE
a Integer;
b Integer;
c Integer;
BEGIN
a:=1;
b:=2;
c:=a+b;
DBMS_OUTPUT.PUT_LINE(c);

WRITE C

END;

STOP

Structura Alternativa

14

BEGIN
B2

START
B2

FALSE

B>0

WRITE
Negativ

TRUE
WRITE
Pozitiv

IF B>0 THEN
WRITE Pozitiv
ELSE
WRITE Negativ
END IF
END

Private Sub Secventa()


DIM b as Decimal
b=2
If (b > 0) Then
Console.WriteLine ("Pozitiv")

Else

B=2
If b>0
? pozitiv
Else
? negativ
Endif

Console.WriteLine ("Negtiv")

End If

public static void


main(String[] args)
{
int b=2;
if (b>0)
System.out.print
("pozitiv");
else
System.out.print
("negativ");

End Sub
}
STOP

Structura alternativ cu o ramur vid

declare
b Integer;
begin
b:=2;
if b>0 then
DBMS_OUTPUT.PUT_LINE(
'Pozitiv');
else
DBMS_OUTPUT.PUT_LINE(
'Negativ');
end if;
end;

15

BEGIN
B2

START
B2

B>0

TRUE
WRITE
Pozitiv

IF B>0 THEN
WRITE Pozitiv
END IF
END

Private Sub Secventa()


DIM b as Integer
b=2
If (b > 0) Then
Console.WriteLine ("Pozitiv")

End If

End Sub

B=2
If b>0
? pozitiv
Endif

public static void


main(String[] args)
{
int b=2;
if (b>0)
System.out.print
("pozitiv");
}

STOP

Structura repetitiv condiionat anterior (FOR, WHILE-DO) Exemplu: N factorial

declare
b Integer;
begin
b:=2;
if b>0 then
DBMS_OUTPUT.PUT_LINE(
'Pozitiv');
end if;
end;

16

BEGIN
i1

START

N1

i1

While i<=8 Do
NN*I

N1

ii+1
i<=8

TRUE
NN*i

END While
WRITE N
END

Private Sub Secventa()


DIM i, n as Integer
N=1
For i = 1 To 8
N=N*i
Next
Console.WriteLine (N)

N=1
For i=1 to 8
N=N*i
EndFor
?N

End Sub
Varianta While-DO:

ii+1
FALSE
WRITE N
Pozitiv
STOP

Varianta While-DO:
Private Sub Secventa()
DIM i, n as Integer
N=1
i=1
Do While i <= 8
N=N*i
i=i+1
Loop
Console.WriteLine (N)

N=1
i=1
Do While i<=8
N=N*i
i=i+1
EndDo
?N

End Sub

Structura repetitiv condiionat posterior (DO-WHILE)

public
static
void
main(String[] args) {
int n=1;
for (int i=1;i<=8;i++)
n=n*i ;
System.out.print(n)
;
}

Varianta While-DO:
public
static
void
main(String[] args) {
int n=1;
int i=1;
while (i<=8)
{ n=n*i;
i++;
}
System.out.print(n);
}

declare
N Integer;
begin
N:=1;
For i in 1..8 Loop
N:=N*i;
End Loop;
DBMS_OUTPUT.PUT_LINE(N);
end;
Varianta While-DO:

declare
N Integer;
i Integer;
begin
N:=1;
i:=1;
While i<=8 Loop
N:=N*i;
i:=i+1;
End Loop;
DBMS_OUTPUT.PUT_LINE(N);
end;

17

BEGIN
i1

START
i1

N1

N1

DO
NN*I
ii+1
While i<=8
WRITE N
END

NN*i
ii+1

Private Sub Secventa()


Dim n, i as Integer
N=1
i=1
Do
N=N*i
i=i+1
Loop While i <= 8
Console.WriteLine (N)
End Sub

i<=8
FALSE
WRITE N
Pozitiv
STOP

TRUE

Nu implementeaza

public
static
void
main(String[] args) {
int n=1;
int i=1;
do
{ n=n*i;
i++;}
while (i<=8);
System.out.print(n);
}

declare
N Integer;
i Integer;
begin
N:=1;
i:=1;
Loop
N:=N*i;
i:=i+1;
EXIT WHEN i >8;
End Loop;
DBMS_OUTPUT.PUT_LINE(N);
end;

18

Un

caz

special

de

structur

alternativ

este

aa

numita

structur

alternativ generalizat, care presupune compararea unei variabile cu un set


de valori predefinit. In VB .NET structura alternativ generalizat poate fi
implementat n dou moduri:
1- prin structura IF-ELSEIF caz n care putem utiliza orice operator
relaional pentru a scrie expresia de testare
Dim nr As Integer
nr = InputBox("introdu un nr intre 0-10")
If (nr = 0) Then
Console.WriteLine("zero")
ElseIf nr = 1 Then
Console.WriteLine("unu")
ElseIf nr = 2 Then
Console.WriteLine("doi")
ElseIf

Else
Console.WriteLine("numar in afara domeniului precizat ")
End If

2- Prin structura SELECT CASE -

caz n care operatorul relaional este

implicit i se refer la egalitate (=)


Select Case nr
Case 0
Console.WriteLine("unu")
Case 1
Console.WriteLine("unu")
Case 2
Console.WriteLine("doi")
...........
Case Else
Console.WriteLine("numar in afara domeniului precizat")
End Select

Un alt caz special se refer la necesitatea ieirii forate dintr-o bucl repetitiv
FOR, la prima validare a unei condiii. Spre exemplificare vom recurge la un
algoritm pentru testarea apartenenei unui numr la mulimea numerelor prime.
Astfel, dac analizm secvena de cod de mai jos, observm c, pe msur ce se
testeaz rezultatul mpririi numrului la toate numerele mai mici dect el, n
cazul n care se descoper un rest=0, nu mai are sens testarea celorlate. Ca
urmare, instruciunea EXIT FOR este utilizat pentru a ntrerupe forat execuia
buclei FOR.

19

Sub testIesireFortataFor()
Dim nr, i As Integer
Dim este As Boolean
este = True
nr = InputBox("intro un nr intreg")
For i = 2 To nr - 1
'Console.WriteLine(i) ' uncomment pentru testarea iesirii fortate
If (nr Mod i) = 0 Then
este = False

Exit For

End If
Next
If (este) Then
Console.WriteLine("numarul " & nr & " este nr prim")
Else
Console.WriteLine("numarul " & nr & "nu este nr prim")
End If
End Sub

Testarea unui algoritm poate fi efectuat doar cu un creion i o hrtie, dac


utilizm un tabel n care liniile sunt reprezentate de pai iar coloanele de valorile
curente ale variabilelor i instruciunile ce se execut. Spre exemplu, pentru
calculul N factorial prezentat n schemele de mai sus (varianta WHILE-DO cu
N=4):
Pas
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

Instruciune
i1
N1
i<=4?
NN*i
ii+1
i<=4?
NN*i
ii+1
i<=4?
NN*i
ii+1
i<=4?
NN*i
ii+1
i<=4?
WRITE N

EvalCond

TRUE

TRUE

TRUE

TRUE

FALSE

i
1
1
1
1
2
2
1
3
3
3
4
4
4
5
5
5

N
1
1
1
1
1
2
2
2
6
6
6
24
24
24
24

Iat n continuare i algoritmul de rezolvare a ecuaiei de gradul doi


2

ax +bx+c=0 , algoritm reprezentat prin intermediul unei scheme logice.

20

START
READ a,b,c
Pozitiv
FALSE

TRUE

a<>0

b^2 4*a*c

x-c/b
WRITE x
Pozitiv

FALSE

>0

TRUE
X1=(-b - SQRT()) / (2*a)

FALSE

TRUE

=0

X2=(-b + SQRT()) / (2*a)


WRITE Fara radacina
Pozitiv

WRITE b/(2*a)
Pozitiv

WRITE X1, X2
Pozitiv

STOP

1.3.

Modularizarea programelor..

nc de la nceputurile erei calculatoarelor programatorii s-au confruntat cu


problema complexitii aplicaiilor. Majoritatea problemelor din lumea real sunt
complexe i nu pot fi formalizate prin intermediul unui singur algoritm. Mai mult,
exist numeroase pri ale unei probleme ce pot fi regsite n formularea altora,
i, ca urmare, algoritmii ce descriu prile pot fi reutilizai. Reutilizarea codului
este una din paradigmele fundamentale n programare iar dezvoltatorii de
aplicaii vd n acest procedeu un scop n sine al procesului de programare. n
esen, reutilizarea codului se refer la gruparea unora din paii unui algoritm
pentru a forma poriuni de cod scurte (numite generic module, subprograme sau
subrutine), ct mai simple i specializate, astfel nct:
-

prin asamblarea acestor pri s se obin rezultatul dorit;

unele module s poat fi reutilizate pentru asamblarea algoritmic a


rezolvrii unei alte probleme; acest aspect presupune simplitate i
specializare (modulul trebuie s rezolve o sarcin definit ct mai abstract
posibil, sarcin care se poate apoi regsi n definirea altei probleme)

Subrutinele nu sunt altceva dect programe (algoritmi) n miniatur, cu


propriile lor variabile i opearii fundamentale asupra datelor.

21

Asamblarea ulterioar a modulelor presupune construirea unui program


(algoritm) mai general care include instruciuni de apel (sau invocare) a
subprogramelor.

A invoca o subrutin nseamn

a transfera

controlul

execuiei din modulul general ctre subrutin. n majoritatea cazurilor modulul


principal i suspend execuia ct timp se execut subrutina (mai puin n
cazurile de programare pe mai multe fire de execuie) . O dat ce controul
execuiei este primit, subprogramul se execut la rndul su apoi, dup
finalizare, napoiaz controlul modulului apelant (principal) care i reia
execuia de la pasul urmtor apelului subrutinei.

1.3.1.

Proceduri, funcii, parametri.

n programare, subrutinele pot fi de dou tipuri:

Proceduri module ce execut o anumit sarcin, iar dup finalizarea


execuie redau controlul programului apelant;

Funcii

- module ce execut o anumit sarcin dar pasul final al

execuiei presupune transmiterea unor valori ctre programul


apelant, ca rezultat al prelucrrilor. Se spune c o funcie este un modul
care ntotdeauna returneaz un rezultat. Multe limbaje de programare
implementeaz un cuvnt rezervat, RETURN, pentru a trimite rezultatul
prelucrrilor programului apelant
PROCEDURA

Controlul execuiei
Transfer date-rezultat

FUNCIE

Figura 1-3 Dou tipuri fundamentale de subrutine

Orice subprogram (procedur sau funcie) are un nume, nume ce va fi utilizat


n instruciunea de invocare.
n multe cazuri, la momentul transferului execuiei programul apelant poate
trimite o list de valori subrutinei, valori ce se vor materializa sub forma unor
variabile de intrare numite parametri (sau argumente). Cu alte cuvinte, exist

22

module care necesit date de intrare pentru a realiza prelucrri asupra lor, iar
aceste date sunt preluate odat cu controlul execuiei de la programul apelant.

atext
b2
c3
CALL P(a,b)

X=F(c)

text,2

PROCEDURA P
(params: p1,p2)

Controlul execuiei

p1text
p22

Transfer date-rezultat
Transfer date
parametri

FUNCIA F
(params: p1)

p13

1,5

RETURN p1/2
Figura 1-4 Transferul de parametri

Urmtoarele aspecte sunt eseniale i general valabile:

Parametrii sunt de dou tipuri:

o Parametri formali varibilele declarate la nivelul subrutinei


pentru a prelua valori de la programul apelant (n fig. 1-8
parametrii formali ai procedurii P sunt p1 i p2 iar pentru funcia
F p1 );

o Parametri actuali valorile ce vor fi transmise subrutinelor la


momentul execuiei (n fig 1-8 este vorba de valorile variabilelor
a i b , adic text i 2, n cazul procedurii P i valoarea 3 n
cazul funciei F) ; parametrii actuali pot fi varibile, literali,
constante (cu alte cuvinte obineam acela rezultat dac
apelam procedura

cu doi literali n loc de dou variabile :

P(text, 2)

Numrul i ordinea parametrilor este extrem de important


parametrii actuali sunt preluai de cei formali n ordine, strict de la
stnga la dreapta (n fig 1-8, instruciunea CALL P(a,b) determin ca
primul parametru formal al procedurii P (adic p1) s ia valoarea text
iar cel de-al doilea (p2) s ia valoarea 2). Numrul parametrilor actuali
trebuie ntotdeauna s fie identic cu numrul parametrilor formali.

Pentru c o funcie ntotdeuna returneaz un rezultat, respectivul


rezultat trebuie preluat ntr-o variabil la nivelul rutinei principale
(apelant) tocmai de aceea, ntotdeauna invocarea unei funcii se
realizeaz dup urmtroarea schem:

23

V=NumeFuncie(lista_parametri_actuali)
n timp ce pentru a invoca o procedur este nevoie de o instruciune
special implementat la nivelul limbajului (spre exemplu CALL n VB):
CALL NumeProcedura (lista_parametri_actuali)
Iat un exemplu de problem n care definim cteva module specializate
(proceduri i funcii): s se calculeze media semestrial a studenilor unei
specializri tiind c au fost doar dou examene, fiecare cu o pondere diferit
(0.4 x nota1+0.6 x nota2) n media final. n acelai timp, pentru fiecare student
s se afieze dac beneficiaz de cazare i/sau de burs. Repartizarea n cmine
a studenilor se face pe baza mediei acestora : 7<=medie<8 camin1,
8<=medie<9 camin2, 9<=medie<10 camin3. Exist dou tipuri de burse
repartizte astfel: 9<=med<9.5 burs_studiu, 9.5<=med<10 burs_merit .
Datele de intrare se prezint sub forma unei matrici (prima coloan =numele
studenilor iar urmtoarele dou notele) astfel (vezi mai intai seciunea 2.1
dedicat tablourilor):
Student

10

10

1
Student

2
Student

3
Student

24

PRINCIPAL

CalculM

READ Matrice(4,3)

READ N1, N2, C1, C2

I1

Media4
TRUE

I<=4

N1>=5
And
N2>=5
MEDCalculM(Matrice(I,2),Matrice(I,3) 0.4, 0.6)

FALSE

FALSE
WRITE
Restante

MED>=5

FALSE

TRUE

RepartCamin(Matrice(I,1), MED)
Return Media
RepartBurse (Matrice(I,1), MED)

II+1
STOP

TRUE

MediaN1*C1+ N2*C2

25

RepartCamin

READ NumeStud, MedS

FALSE

TRUE

MedS>=7

WRITE NumeStud, Fara Camin


FALSE

MedS>=8

TRUE

WRITE NumeStud, Camin1


FALSE

MedS>=9

WRITE NumeStud, Camin2

TRUE

WRITE NumeStud, Camin3

STOP

RepartBurse

READ NumeStud, MedS

FALSE

MedS>=9

TRUE

WRITE NumeStud, Fara Bursa


FALSE

MedS>=9.5

WRITE NumeStud, Bursa Studiu

STOP

TRUE

WRITE NumeStud, Bursa Merit

26

Iat i implementarea algoritmului n VB (fa de schema de mai sus,


procedura principal() a fost mbogit cu declararea i popularea explicit
a tabloului Matrice i un apel la procedura de afiare ( Debug.Print()) pentru
media fiecrui student) :
Listing 1-1 Proceduri, Funcii i parametri n VB
Module curs_3_4_proceduri_functii
Sub principal()
Dim i As Integer
Dim med As Decimal
Dim Matrice(3, 2)
Matrice(0, 0) = "Student1"
Matrice(1, 0) = "Student2"
Matrice(2, 0) = "Student3"
Matrice(3, 0) = "Student4"
Matrice(0, 1) = 10
Matrice(1, 1) = 7
Matrice(2, 1) = 9
Matrice(3, 1) = 5
Matrice(0, 2) = 10
Matrice(1, 2) = 8
Matrice(2, 2) = 6
Matrice(3, 2) = 4
For i = 0 To 3
Med = CalculM(Matrice(i, 1), Matrice(i, 2), 0.4, 0.6)
Console.writeLine("media " & Matrice(i, 0) & " este: " & Med)
If Med >= 5 Then
Call RepartCamin(Matrice(i, 0), Med)
Call RepartBurse(Matrice(i, 0), Med)
Else
Console.writeLine("Restante")
End If
Next
End Sub
Function CalculM(ByVal N1, ByVal N2, ByVal C1, ByVal C2)
Dim media As Decimal
media = 4
If N1 >= 5 And N2 >= 5 Then
Media = N1 * C1 + N2 * C2
End If
Return media
End Function

27

Sub RepartCamin(ByVal NumeStud, ByVal MedS)


If MedS >= 7 Then
If MedS >= 8 Then
If MedS >= 9 Then
Console.writeLine(NumeStud + "Camin3")
Else
Console.WriteLine(NumeStud + " Camin2")
End If
Else
Console.WriteLine(NumeStud + " Camin1")
End If
Else
Console.WriteLine(NumeStud + " Fara Camin")
End If
End Sub
Sub RepartBurse(ByVal NumeStud, ByVal MedS)
If MedS >= 9 Then
If MedS >= 9.5 Then
Console.WriteLine(NumeStud + " Bursa Merit")
Else
Console.WriteLine(NumeStud + " Bursa Studiu")
End If
Else
Console.WriteLine(NumeStud + " Fara Bursa")
End If
End Sub
End Module

28

Fereastra Immediate utilizat i pentru apelul


procedurii (CTRL+G)

Fereastra Output utilizat pentru vizualizarea


rezultatelor afisate la executia programelor

n majoritatea limbajelor, o funcie se ncheie prin instruciunea Return


<valoare>.

Instruciunea Return poate fi utilizat i pentru ieirea dintr-o

FUNCIE sau PROCEDUR, nainte de a a fi executate toate instruciunile:


Sub testReturn ()
Dim nr As Integer
nr = InputBox("introdu un nr intre 0-10")
If (nr = 0) Then
Console.WriteLine("zero")
Return

29

ElseIf nr = 1 Then
Console.WriteLine("unu")
Return
ElseIf nr = 2 Then
Console.WriteLine("doi")
Return
ElseIf

Else
Console.WriteLine("numar in afara domeniului precizat ")
End If
End SUB

Sau, pentru funcii


Function testReturnText (nr as Integer) as String
Dim nr As Integer
nr = InputBox("introdu un nr intre 0-10")
If (nr = 0) Then
Return "zero"
ElseIf nr = 1 Then
Return "unu"
ElseIf nr = 2 Then
Return "doi"
ElseIf

Else
Return ""
End If
End Function

Dup instruciunea RETURN, orice secven de cod, scris n cadrul aceleiai


subrutine, nu va fi executat vreodat. Multe compilatoare atenioneaz
dezvoltatorul despre acest lucru. Din pcate, VB.NET nu face acest lucru i, ca
urmare, programatorul trebuie s aloce atenie sporit la utilizarea instruciunii
Return
Function CalculM(N1, N2, C1, C2)
Dim Media = 4
If N1 >= 5 And N2 >= 5 Then
Media = N1 * C1 + N2 * C2
End If
Debug.print(After Process)
Return Media
End Function

expresia After Process va fi afiat .


Dar dac modificarea se realizeaz n felul urmtor:
Function CalculM(N1, N2, C1, C2)

30
Dim Media = 4
If N1 >= 5 And N2 >= 5 Then
Media = N1 * C1 + N2 * C2
End If
Return media
Debug.print(After Process)
End Function

expresia After Process nu va fi afiat (cu alte cuvinte nu se va executa


procedura de scriere: Debug.print())
n VB, procedurile i funciile sunt organizate n module cunoscute n general
sub numele de biblioteci de funcii. Dac scriem toate subrutinele din listingul 1-1
ntr-un modul cu numele Modul1 , atunci apelul procedurii Principal() dintr-un
alt modul va fi de forma :
Call Modul1.Principal
(punctul ce desparte numele modulului de numele procedurii este esenial
(vom aborda aceast tehnic ceva mai trziu))

1.3.2.

Dou modalitai de transmitere a parametrilor.

Exist dou variante de transmitere a argumentelor (mai bine zis a valorilor


acestora) de la programul apelant ctre subrutin:

prin adres (sau prin referin) - modul implicit n Visual Basicparametrii formali din procedura apelat vor prelua ca valoare adresa
valorilor parametrilor actuali (vezi noiunea de pointer). Ca urmare, att
variabilele din rutina apelant ct i cele ce constituie parametrii
formali n subrutin vor manipula aceeai valoare: modificarea
valorilor varibilelor ce constituie parametrii formali n cadrul subrutinei
va nsemna, de fapt, modificarea valorilor parametrilor actuali din rutina
principal(vezi figurile 1-9 i 1-10).

prin valoare - parametrii formali din procedura invocat vor prelua o


copie a valorilor parametrilor actuali. Ca urmare, modificarea valorilor
parametrilor formali n subrutin nu va afecta valorile parametrilor
actuali din programul apelant (figurile 1-9 i 1-11)

Transmiterea

prin

valoare

protejeaz

variabilele

din

rutina

principal

(parametrii actuali), valoarea acestora rmnnd ntotdeauna neschimbat dup


execuia subprogramului apelat, chiar dac la nivelul acestuia din urm valorile
parametrilor formali se modific.
Avnd n vedere frecvena foarte ridicat a invocrii diverselor funcii i
proceduri ntr-o aplicaie real, la implementarea uneia sau alteia dintre cele
dou metode trebuie s se aib n vedere urmtoarele aspecte:
transferul prin referin asigur o bun gestionare a memoriei interne
(copierea valorilor la nivelul parametrilor formali necesit operaii i

31

spaiu de memorie suplimentare) dar ofer o bre de securitate ce


poate fi exploatat, n mod deliberat sau nu, de modulul apelat;
transferul prin valoare garanteaz imposibilitatea modificrii parametrilor
actuali (variabile locale ale modului apelant) dar implic operaii pentru
alocarea memoriei suplimentare i copierea valorilor
MEMORIE (RAM)
Program

Subrutina

Pas 1: a=1

Transfer prin referin


(b preia adresa valorii lui a)

Pas2: Call Proc(a)

Proc(b)

a
Pas3 b=25

25

Transfer prin valoare


(b preia o copie a valorii lui a)

25

Pas4: WRITE a
Figura 1-5 Dou modaliti de transmiterea valorilor parametrilor (prin referin i prin valoare)

Rezultat execuie
testTransferParametri()

Figura 1-6 Transmiterea valorilor parametrilor prin referin n VB (procedura principal:


TestTransferParametri())

32

Rezultat execuie
testTransferParametri()

Figura 1-7 Transmiterea valorilor parametrilor prin valoare n VB (procedura principal:


TestTransferParametri())

1.3.3.

Declararea tipului parametrilor

Exist i posibilitatea restricionrii parametrilor la un anumit tip de


dat. n exemplele de mai sus, parametrii formali nu sunt declarai ca fiind
de un anumit tip, astfel c ei vor fi considerai n mod implicit de tip
Variant. Tipul de date Variant permite VB s identifice tipul la momentul
execuiei n funcie de valoarea variabilei respective. De cele mai multe ori
este ns indicat s specificm explicit tipul fiecrui parametru formal,
astfel nct funcia (sau procedura) s nu accepte alte tipuri de date care
ar putea bloca prelucrrile.
Function F( p1 As Integer, p2 As Double, p3 As String)
O asemenea declaraie oblig aplicaia-client (modulul apelant) s
furnizeze parametri actuali de tipul specificat, n caz contrar obinnd un
mesaj de eroare. Asta nseamn c variabilele ce vor constitui parametrii
actuali trebuie neaprat declarate de tipul respectiv. Cu alte cuvinte, o
procedur de apel pentru funcia F ar putea fi construit astfel:
Sub P()
Dim pa1 as Integer
Dim pa2 as Double
Dim pa3 as String
Pa1=1
Pa2=3.5
Pa3=text
Rez=F(pa1,pa2,pa3)
End sub

33

1.3.4.

Din nou despre Domeniul de Vizibilitate a variabilelor

ntr-un program, orice variabil are o anumit durat de existen, cu alte


cuvinte o anumit durat n care valoarea asociat poate fi manipulat. Unele
variabile pot fi utilizate pe parcursul ntregii aplicaii pe cnd altele se
iniializeaz i se volatilizeaz n cadrul unei structuri de control (IF, FOR, WHILE).
Diverse limbaje de programare implementeaz n mod diferit acest concept de
programare. O regul general adoptat este aceea o variabil declarat la
nceputul unei proceduri ( a unui algoritm) va fi disponibil pe parcursul
prelucrrilor generate de acel algoritm pn la terminarea lui. Astfel, exist
limbaje de programare:

care impun declararea tuturor variabilelor la nceputul unitii de


program: ADA, Oracle PL/SQL, Pascal

care ofer libertatea declarrii variabilei chiar la momentul utilizrii ei,


dar restricioneaz

durata de via la nivelul structurii de control n

care a fost declarat (dac aceasta este o decizie IF - sau o iteraie FOR, WHILE, variabila declarat n cadrul structurii nu va fi vizibil n
afara ei , chiar dac este vorba de aceeai subrutin ) : Java,
VisualBasic .NET, C#.NET
Am vzut mai devreme c o variabil poate fi declarat explicit prin utilizarea
instruciunii DIM. Locul n care este plasat instruciunea DIM este important
pentru c determin domeniul de vizibilitate al respectivei variabile. Spre
exemplu, secvena:
Sub testWhile(ByVal a)
Do While a < 5
Dim x = 0
Debug.Print("A")
Loop
Debug.Print("a " & x)
End Sub

Va genera o eroare de compilare deoarece variabila x este declarat n


cadrul structurii WHILE i este apoi apelat n afara acesteia.
Reguli:
1 - Dac Dim este plasat la nceputul unei proceduri (dup declaraia Sub
<nume-procedur>) atunci variabila declarat va fi recunoscut i va putea fi
utilizat doar n procedura respectiv, fiind o variabil local.
2 Dac variabila este declarat n interiorul unei structuri de control, ea va
putea fi utilizat doar n cadrul acelei structuri
3 - Pentru ca variabilele s poat fi utilizate n toate procedurile dintr-un
modul, trebuie s plasm instruciunea DIM n seciunea general a modulului
(vezi figura 1-8), adic n afara unei proceduri (de regul n antetul modulului).
Dac n locul instruciunii Dim se utilizeaz Public (avnd acelai format cu
Dim), toate modulele-standard i toate form-urile aplicaiei vor putea lucra cu
variabilele declarate astfel. Acestea se numesc variabile globale. Instruciunea

34

Public este utilizat pentru declararea variabilelor n seciunea General a


modulelor standard. Nu se poate folosi declaraia Public ntr-o procedur
delimitat prin SubEnd Sub.
Declaraia Private permite declararea de variabile la nivel de modul (pot fi
apelate numai din procedurile din modulul respectiv, nu i din alte module ori
form-uri). Se folosete de asemenea n seciunea General a modulului. Nici
declaraia Private nu se poate utiliza n cadrul procedurilor delimitate prin Sub
End Sub.
n figura urmtoare, variabilele PI i unghi pot fi accesate din toate procedurile modulului
respectiv

Figura 1-8 Variabile locale i globale

Iat un alt exemplu pentru utilizarea constantelor i a variabilelor


globale: Presupunem c o aplicaie necesit autentificarea utilizatorilor
(userName i parol). Unii utilizatori au dreptul s execute o anumite
funcii, alii nu. S zicem c avem dou grupuri de utilizatori: Studeni i
Profesori.

Userii

din

grupul

Studeni

nu

au

dreptul

execute

proceduraRestricionat() vezi listingul 1-3. Ca urmare, aplicaia va


trebui s furnizeze o funcie de login i s atribuie unei variabile globale
(vezi variabila userProfile in listingul 1-2) o valoare care s indice grupul
din care face parte utilizatorul. proceduraRestricionat() va testa

35

aceast variabil pentru a afla dac utilizatorul face parte din grupul celor
care au drepturi de execuie. Pentru valorile de test ale variabilei
userProfile este indicat s definim cte o constant pentru fiecare grup
distinct de utilizatori.
Listing 1-2 Modulul VisualBasic Login
Public Const USER_GROUP_STUDS = 1
Public Const USER_GROUP_PROFI = 2
Public userProfile As Double
Function login(userName As String, pass As String) As Boolean
Dim ok As Boolean
If userName = "Popescu" And pass = "popescu" Then
userProfile = USER_GROUP_STUDS
ok = True
End If
If userName = "prof1" And pass = "prof1" Then
userProfile = USER_GROUP_PROFI
ok = True
End If
login = ok
End Function

Listing 1-3 - Modulul Aplicatie


Sub proceduraRestrictionata()
If Login.userProfile <> Login.USER_GROUP_PROFI Then
MsgBox ("nu aveti suficiente drepturi pt aceasta functie")
Else
Debug.Print ("prelucrari....")
End If
End Sub

Listing 1-4 Modul de test:


Sub testLogin()
Dim userName As String, pass As String
Dim x As Boolean
userName = InputBox("UserName")
pass = InputBox("parola")
x = Login.Login(userName, pass)
If x = False Then
MsgBox ("user/pass incorect")
Else
Call Aplicatie.proceduraRestrictionata
End If
End Sub

Figura 1-9. Domeniul variabilelor

1.4.

Funcii de conversie

De regul, conversiile ntre tipuri de date sunt necesare doar atunci


cnd conversia automat implementat de mediul VB.NET nu este

36

suficient sau nu se poate efectua. Iat un exemplu de conversie


automat:
Dim x As Double
x = "2.33" se va realiza conversia automat la tipul Double
Debug.Print(x + 1)

n afara conversiei automate, exist o suit de funcii de conversie ce


pot fi utilizate n funcie de necesiti
C B o o l ( expression) , C B y t e ( expression) , C C h a r ( expression) , C D a t e ( expression) ,
C D b l ( expression) , C D e c ( expression) , C I n t ( expression) , C L n g ( expression) , C O b j ( expression) ,
C S h o r t ( expression) , C S n g ( expression) , C S t r ( expression)

Unde: <expression> reprezint argumentul obligatoriu sub forma oricrei expresii ce poate fi evaluat
la un tip numeric, String sau Date (depinde de scopul funciei)

Cea mai utilizat dintre acestea este CDate() i CStr()

Tipul returnat de fiecare funcie este prezentat n tabelul urmtor:


Funcie

Tip Returnat

Cbool

Input:
numar

Boolean

Exemplu
Dim A, B, C As Integer
Dim Check As Boolean

orice

A = 5

sau

B = 5

expresie evaluata

Check = C B o o l ( A = B)

la true/false

' Check ia valoarea True.

' ...
C = 0
Check = C B o o l ( C)

CChar

Char

CDate

Date

CDbl

Double

CDec

Decimal

CInt

Integer

CLng

Long

CShort

Short

' Check ia valoarea False.

37

CStr

String

Not! n multe situaii, funciile de conversie nu sunt necesare,


deoarece

sistemul

va

ncerca

efectueze

singur

conversiile

corespunztoare.

1.5. Funcii matematice


Majoritatea funciile necesare n diverse operaii cu numere se regsesc
n modulul-sistem Math. Denumirea lor este sufucient de sugestiv pentru
a nu mai fi necesare explicaii detaliate. Totui mai sunt i cteva funcii n
afara pachetului Math, precum Int, Rnd. Iata cateva exemple pe care le
putei testa rapid n fereastra Immediate (CTRL+G)

Sub testFunctiiMatematice()
Console.WriteLine("abs - valoare absoluta:" & Math.Abs(-2) & " / " & Math.Abs(2))
Console.WriteLine("round - rotunjire :" & Math.Round(2.54) & " / "
Math.Round(2.2))
Console.WriteLine("Ceiling - primul intreg mai mare: " & Math.Ceiling(2.54) & " /
& Math.Ceiling(2.2))
Console.WriteLine("Floor - primul intreg mai mic: " & Math.Floor(2.54) & " / "
Math.Floor(2.2))
Console.WriteLine("Sqrt - radacina patrata: " & Math.Sqrt(4) & " / "
Math.Sqrt(9) & " / " & Math.Sqrt(-9))
'functii in afara modului math
Console.WriteLine("Int - partea intreaga: " & Int(2.54) & " / " & Int(2.2))
Console.WriteLine("Rnd - numar aleator intre 0-1: " & Rnd())
Console.WriteLine("Rnd * 100 - numar aleator intre 0-100: " & Rnd() * 100)
End Sub

2. Organizarea datelor n Structuri de date.


La nivelul sistemului de calcul, memoria intern este organizat n celule (n
majoritatea cazurilor cu dimensiune de 1 octet=8bii) cu adrese consecutive. n
mod normal ns, este mai convenabil s organizm datele sub forma unor
structuri abstracte, familiare. Spre exemplu vnzrile sptmnale ale unei firme

&
"
&
&

38

vor fi organizate ntr-o form tabelar, cu produsele vndute sub form de


coloane i zilele sptmnii sub form de linii.
Obiectivul seciunii ce urmeaz este de a nelege mecanismele prin care
programatorul gestioneaz datele conform viziunii sale abstracte asupra acestora
i nu dup organizarea actual la nivelul memoriei interne.

2.1.

Tablouri

Una din cele mai utilizate structuri de date este tabloul (array), structur care
prezint datele ntr-o form rectangular, fiecare valoare fiind stocat ntr-o
celul astfel nct programatorul poate la un moment dat manipula valoarea
respectiv prin intermediul poziiei sale. Identificarea valorii prin intermediul
poziiei sale n cadrul tabloului (cu alte cuvinte identificarea celulei de memorie
intern ce conine respectiva valoare) cade n sarcina translatorului limbajului de
programare cu care se lucreaz. Exist dou tipuri de tablouri: unidimensionale i
multidimensionale.
Tablouri Unidimensionale (figura 2-1) tablouri cu o singur linie i n
coloane numite i vectori reprezint datele sub forma unei liste ordonate de
celule de memorie (cu adrese consecutive) creia i se atribuie un nume pentru
identificare. Fiecare celul va stoca o valoare. Accesul la o anumit valoare se
realizeaz prin numele listei i poziia (numit i index) elementului n list. Spre
exemplu, notele unui student la patru discipline dintr-un semestru pot fi
reprezentate prin intermediul unui vector cu numele Note, ce va conine, patru
valori localizate fizic n patru celule de memorie cu adrese consecutive. Pentru a
manipula nota la cea de-a doua discplin, vom utiliza o sintax de genul Note(2)
(sau Note[2] n funcie de limbajul utilizat) astfel: pentru preluarea notei putem
spune:
Note(2)=8.7
Iar pentru a calcula ulterior media:
Medie=(Note(1)+Note(2)+)/4
Numele tabloului (Note) este n esen un pointer (o variabil ce conine o
adres) spre valoarea din prima celul a tabloului. Astfel,

pentru a extrage o

valoare de la o anumit poziie, translatorul va trebui s identifice adresa celulei


respective. tiind c adresele sunt consecutive, i deinnd prima adres (101
vezi figura 2-1), adresa notei la a treia disciplin se obine prin : 101+(3-1)=103.
Iat de ce Note(3) va returna ntotdeauna valoarea de la adresa de memorie 103
(n exemplul nostru fiind vorba de nota 6)

39
Adrese de memorie
101
9
Celule de memorie

102 103
8.7
6

104
6
Note(1)
Note(2)
Note(3)
Note(4)

Figura 2-10

Tablouri Multidimensionale reprezint n fapt structuri de tablouri


unidimensionale ale cror elemente (noduri sau celule) sunt alte tablouri
unidimensionale. Cel mai utilizat tablou multidimensional este matricea (tablou
cu linii i coloane 2 dimensiuni). Spre exemplu dac ar trebui s reprezentm
notele tuturor studenilor unei secii pe primul semestru, presupunnd c sunt 4
examene, am putea construi un tabel n care pe fiecare line s reprezentm
notele unui alt student.

10
4
10

7
9
10

5.5
9
10

Disciplina 1

6
10
9

Student 1
Student 2
Student 3

Disciplina 4

Disciplina 2
Disciplina 3

Structura de date astfel obinut este uor de abordat de programator, fiind


un mod familiar de reprezentare a datelor. Manipularea datelor se realizeaz prin
intermediul unei sintaxe similare celei prezentate la tablourile unidimensionale,
doar c identificarea poziiei unui element se realizeaz prin numrul liniei i al
coloanei. Astfel, dac numele tabloului ar fi Note, nota studentului 2 la disciplina
1 se obine prin: Note(2,1) adic Note(linie, coloan). Pentru a modifica
nota studentului 1 la disciplina 3 vom scrie:
Note(1,3)=5.5
Iar pentru a obine media notelor studentului 2 la cele patru discipline:
MedieS2=(Note(2,1)+Note(2,2)+Note(2,3)+Note(2,4))/4
adic 4+9+9+10/4
Dup cum tim, memoria intern a mainii de calcul este organizat n celule
cu adrese consecutive. Ca urmare, translatorul limbajului de programare va
trebui s simuleze modalitatea tabelar de organizare a datelor. n esen, liniile
(n exempl;ul nostru 4 celule de date) vor fi stocate n ordinea natural, ntr-o
structur liniar de celule de memorie cu adrese consecutive (primele patru

40

celule de memorie vor constitui prima linie, urmtoarele patru vor constitui cea
de-a doua linie, .a.m.d vezi figura 2-2). Numele tabloului (Note) este de fapt o
variabil-pointer spre prima valoare din irul astfel obinut. Avnd n vedere c
tim prima adres a irului de celule de memorie ce stocheaz valorile noastre, i
c adresele respectivelor celule sunt ntotdeauna consecutive, adresa fizic a
unui element al tabloului (valoare

manipulat la nivelul limbajului prin

Note(i,j)) poate fi calculat. Translatorul va efectua acest calcul pentru a


returna valoarea de la linia i, coloana j. Dac C reprezint numrul de coloane,
adresa fizic a elementului Note(i,j) se obine prin adugarea la adresa primului
element a numrului obinut prin:
(Cx(i-1)) + (j-1)
Spre exemplu (vezi i figura 2-2) pentru a calcula adresa la care se afl
valoarea Note(3,2) (adic nota la discipl. 2, studentul 3, care este 10), tiind c
adresa primei celule (spre care ine o referina variabila(pointerul) Note) este
100 :
adresa element (3,2)=100+ 4x(3-1)+(2-1)=100+8+1=109
Tabloul Note la nivel conceptual

Linia 1
Linia 2
Linia 3

Reprezentarea tabloului n
memorie

Linia 1
100 101

102

Linia 2
103 104 105

106

Linia 3
107 108

Adrese consecutive ale celulelor de


memorie

109

110

111

Valoarea Note(3,2)

Figura 2-11 Reprezentarea matricilor n memorie

Observaie. Datorit modalitii specifice de adresare a memoriei (celule cu


adrese consecutive) tablourile se mai numesc i structuri statice de date,
adic structuri a cror dimensiune (numr de elemente) este cunoscut la
momentul compilrii i nu poate fi modificat pe parcursul execuiei programului.
n toate limbajele de programare tablourile se declar n mod explicit la
momentul scrierii codului, la momentul declarrii programatorul fiind obligat s
specifice numrul maxim de elemente. La execuie, se aloc memorie (celule cu
adrese consecutive) pentru numrul maxim de elemente (nr. linii x nr. coloane).

41

De asemenea, trebuie precizat c indexul primului element poate fi 0 (zero)


sau 1 n funcie de limbajul de programare (cu alte cuvinte elementele se numr
ncepnd cu 0 sau cu 1) . n cazul VB, n mod implicit indexul primului element
este 0 (zero). Spre exemplu, n VisualBasic dimensionm un array (tablou) cu
instruciunea DIM, astfel:
DIM Note(4) -

tablou unidimesional cu 5 elemente (de la 0 la 4)

DIM Note(3,4) - tablou bidimensional cu 4 linii i 5 coloane (primul element


fiind Note(0,0))
Astfel, pentru a dimensiona tablourile exemplificate n figurile 2-1 i 2-2, n VB,
ar trebui s scriem:
DIM Note(3)
DIM Note(2,3)
Listingul urmtor (vezi i opeartorul de concatenare a dou iruri n seciunile
anterioare) prezint un exemplu VB de declarare i populare automat cu date, a
unui vector i a unei matrici. Datele reprezint notele studenilor la patru
discipline (vezi exemplele anterioare i figura 2-1 i 2-2). Notele vor fi obinute
sub form de numere aleatoare de la 0 la 10, generate de funcia Rnd. Funcia
Rnd returneaz un numr ntre 0 i 1 care, nmulit cu un alt numr (n), va
determina obinerea de valori aleatoare ntre 0 i n. Funcia Round(n,nrZec)
returneaz numrul zecimal n rotunjit la nrZec zecimale .
Listing 2-1 Procedura de populare i manipulare elemente tablouri
Module curs2_tablouri
Sub Tablouri()
Dim i, j As Integer
Dim MediaStud1 As Decimal
Dim VectorNote(3)
Dim MatriceNote(2, 3)
For i = 0 To 3
VectorNote(i) = Math.Round(Rnd() * 10, 2)
Debug.Print("VectorNote(" & i & ")=" & VectorNote(i))
Next
Debug.Print("------------------------------------")
For i = 0 To 2
For j = 0 To 3
MatriceNote(i, j) = Math.Round(Rnd() * 10, 2)
Debug.Print("MatriceNote(" & i & "," & j & ")=" &
MatriceNote(i, j))
Next
Next
Debug.Print("------------------------------------")
MediaStud1 = (MatriceNote(0, 0) + MatriceNote(0, 1) _
+ MatriceNote(0, 2) + MatriceNote(0, 3)) / 4
Debug.Print("Media studentului 1=" & MediaStud1)

42

End Sub
End Module

Nota! n procedura de mai sus, semnul _ (underscore) permite scrierea unei


comenzi sau a unei operaii pe mai multe rnduri.
Call Tablouri()

Rezultatul execuiei procedurii Tablouri() va fi cel din figura 2-3

Figura 2-12 Fereastra Immediate afieaz mesajele trimise din procedura Tablouri()

Dup cum s-a vzut anterior (listing 2-1), pentru a parcurge un vector element
cu element utilizm o bucl FOR a crei variabil-contor va fi utilizat pe post de
index pentru a manipula valorile de la respectiva poziie n vector. Pentru a
parcurge o matrice, element cu element,

avem nevoie de dou structuri

repetitive FOR imbricate (una pentru linii iar urmtoarea pentru fiecare coloan).
n acest fel parcurgerea va nsemna mai nti prelucrarea elementelor primei linii
(n ordine de la stnga la dreapta) apoi a elementelor celei de-a doua linii
.a.m.d.
Se observ c n procedura Tablouri() pentru a parcurge tablourile, limita
inferioar i superioar a contorului buclelor FOR (i i j) se specific prin literali
(0,2,3). Exist i posibilitatea de obine valoarea acestor literali (adic a limitei
superioare i inferioare a indexului unui tablou), prin utilizarea urmtoarelor
funcii predefinite n VisualBasic:
LBound(<tablou> [,dimensiune]) pentru limita inferioar;
UBound(<tablou> [,dimensiune]) pentru limita superioar.

43

Parametrul dimensiune este opional i specific n mod implicit dimensiunea


1. Pentru matrice dimensiunea 1 nseamn liniile iar dimensiunea 2 nseamn
coloane. Cu alte cuvinte:
LBound(MatriceNote)=LBound(MatriceNote,1)=0
UBound(MatriceNote)=UBound(MatriceNote,1)=2
LBound(MatriceNote, 2)=0
UBound(MatriceNote, 2)=3
Ca urmare, procedura Tablouri() din listingul 2-1 poate fi scris i astfel:

Listing 2-2 Utilizarea functiilor UBound() i LBound()


Sub Tablouri2()
Dim MediaStud1 As Decimal, i, j As Integer
Dim VectorNote(3)
Dim MatriceNote(2, 3)
For i = LBound(VectorNote) To UBound(VectorNote)
VectorNote(i) = Math.Round(Rnd() * 10, 2)
Debug.Print("VectorNote(" & i & ")=" & VectorNote(i))
Next
Debug.Print("------------------------------------")
For i = LBound(MatriceNote, 1) To UBound(MatriceNote, 1)
For j = LBound(MatriceNote, 2) To UBound(MatriceNote, 2)
MatriceNote(i, j) = Math.Round(Rnd() * 10, 2)
Debug.Print("MatriceNote(" & i & "," & j & ")=" &
MatriceNote(i, j))
Next
Next
Debug.Print("------------------------------------")
MediaStud1 = (MatriceNote(0, 0) + MatriceNote(0, 1) _
+ MatriceNote(0, 2) + MatriceNote(0, 3)) / 4
Debug.Print("Media studentului 1=" & MediaStud1)
End Sub

Nota! n tablourile declarate mai sus, elementele sunt, n mod implicit,


de tip nedeterminat. ntr-un astfel de tablou, tipul este determinat la
run-time i va fi tipul valorilor introduse ca elemente
Exist ns i posibilitatea specificrii tipului elementelor astfel:
Dim Tablou(5) As Integer va accepta doar numere ntregi
Dim Tablou(3,4) As String toate elementele vor fi de tip String
(iruri de char)
Dac, ns, o matrice trebuie s pstreze date de diverse tipuri, va
trebui declarat conform modelului implicit.

44

!!!! De reinut(pentru cazul VisualBasic) :

Nu putem utiliza un tablou dac nu este n prealabil declarat (pentru a se


aloca memorie) cu instruciunea DIM

Prin decrarea tabloului, DIM tablou(N), indexul elementelor n tablou pornete


ntotdeauna de la 0 i se oprete la N. Cu alte cuvinte, se aloc memorie
pentru N+1 elemente. Ca urmare, pentru a declara un tablou de 10 elemente
: DIM Tablou(9), sau o martice de 10x10: DIM Matrice(9,9)

La utilizarea tabloului (citire/scriere elemente din/n tablou) indexul (numrul


coloanei i/sau numrul liniei) trebuie s se ncadreze, obligatoriu, ntre limita
minim (0 zero) i limita maxim declarat. Cu alte cuvinte, ncercarea de a
atribui o valoare sau de a citi un element care nu are alocat spaiu de
memorie se va solda cu o eroare. Spre exemplu (pornind de la listing 2-2):
MatriceNote(6,4)=6.5
va genera o eroare de execuie cu mesajul Subscript Out Of Range

n VB exist i posibilitatea declarrii unor vectori (tablouri unidimensionale)


dinamici atunci cnd nu se tie de la nceput care va fi numrul elementelor,
astfel:

Dim Vector() nu se specific indexul maxim


n acest caz, la momentul declarrii nu se aloc spaiu de memorie urmnd
ca programatorul s includ instruciunea

Redim

Preserve

Vector(Ubound(vector)+1)

- atunci cnd are

nevoie de spaiu pentru nc un element. Clauza Preserve este


obligatorie dac se dorete

pstrarea valorilor elementelor anterioare

deoarece, n esen, instruciunea Redim

determin crearea unui alt

vector cu numarul de elemente specificat clauza Preserve determin i


copierea vechilor valori n noile locaii.
Iat un exemplu:
Sub tablouri_3()

End Sub

Dim V() As String


ReDim V(0) 'primul element trebuie intotdeauna alocat explicit
V(0) = "text0"
ReDim Preserve V(UBound(V) + 1)
V(1) = "text1"
Debug.Print(V(0) & V(1))

Va afia text0text1

2.2. Structuri de date compozite (definite de utilizator).


Am vzut n seciunile anterioare c orice algoritm necesit date de
prelucrare, date care sunt n general de dou tipuri: elementare sau

45

primitive (simboluri i numere) i date structurate (spre ex. tablouri). De


multe ori ns un algoritm poate fi mult mai comod exprimat prin utilizarea
unor structuri de date compuse care s reprezinte cu mai mult acuratee
datele din lumea real. Spre exemplu, o aplicaie de gestiune a traiectoriei
colare a studenilor unei faculti ar putea fi mai uor modelat dac am
ptutea defini date de tipuri precum: Student, Disciplina. Aceste noi
tipuri de date ar trebui s descrie o entitate din lumea real (spre exemplu
entitatea Student ar putea fi descris prin: matricol, nume, grupa,
note),

cu alte cuvinte ar trebui s constituie un ablon pe baza cruia

algoritmul s manipuleze datele despre un anumit student sau o anumit


disciplin ntr-o manier unitar.
DEFINIREA TIPURILOR
Majoritatea limbajelor de programare ofer posibilitatea definirii unor
structuri de date proprii, compuse, fie pe baza celor primitive (scalare,
predefinite), fie pe baza altor tipuri compuse. n VisualBasic o structur
proprie poate fi definit astfel:
[<Public/Private>] STRUCTURE denumireTip
DIM <atribut_1> AS <tipAtribut_1>
DIM <atribut_2> AS <tipAtribut_2>

DIM <atribut_N>

AS

<tipAtribut_1>

END STRUCTURE

Aadar, elementele eseniale ale unui tip nou de date sunt:


-

denumirea noului tip

numele atributelor ce descriu acel tip

tipul de dat al fiecrui atribut poate fi un tip primitiv


(Integer, Double, String, etc.), un tip structurat (tablou), sau
un alt tip compozit definit anterior

<nota>
1 noile tipuri pot fi vizibile (pot fi utilizate la declararea variabilelor)
doar n modulul n care sunt declarate (prin utilizarea specificatorului de
vizibilitate Private, sau n toate modulele proiectului, prin cuvntul
rezervat Public (VEZI i figura 2-4).
2- n locul instruciunii DIM pot fi utilizai specificatori de vizibilitate,
astfel: PUBLIC (atributul va fi accesibil din aplicaiile-client), PRIVATE
(atributul nu va fi accesibil prin intermediul varibilelor din aplicaii)

46

3- dac unul din atribute este de tip tablou (note n figura de mai jos),
lungimea acestuia nu poate fi specificat, urmnd ca, la momentul
declarrii unei variabile de acel tip, s utilizm instruciunea REDIM (vezi
anterior paragrafele dedicate tablourilor) pentru a specifica numrul de
elemente pentru tabloul respectiv.
</nota>
n VB, definirea tipurilor proprii trebuie obligatoriu realizat n seciunea
Declarations a unui modul (adic imediat la nceputul modulului).
Spre exemplu, putem construi un nou tip de dat, cu numele Student,
descris prin atributele: matricol, nume, datanasterii i un vector de note
pentru disciplinele unui anumit semestru (vezi figura 2-4). Desigur,
numrul de atribute descriptive ale noului tip depinde doar de necesitile
problemei sau de imaginaia i experiena programatorului.

Figura 2-13 Declararea unui nou tip de date

MANIPULAREA NOILOR STRUCTURI DE DATE PRIN INTERMEDIUL


VARIABILELOR, TABLOURILOR I PARAMETRILOR
O dat declarat noul tip, se pune problema utilizrii lui. A utiliza un tip
nseamn de fapt a declara o variabil (sau mai multe) ca fiind de acel tip
i a atribui valori efective fiecrui atribut n parte. Spunem atunci c
identificm o instan a tipului respectiv. Cu alte cuvinte, identificm o
entitate din lumea real i o descriem prin intermediul ablonului, lund n
considerare doar atributele definite pentru structura respectiv. Lucrurile
pot fi vzute i din perspectiva similitudinii cu bazele de date. Astfel,
definiia (structura) unei tabele a bazei de date nu este altceva dect o
form descriptiv a unei anumite entiti din domeniul problemei.

47

nregistrrile tabelei sunt instane ale acelei entiti, adic valori reale
setate pentru fiecare din atributele tabelei.
n listingul 2-3 este prezentat un exemplu de manipulare a datelor de
tip Student. Se observ c se declar dou variabile de tip Student,
variabile prin intermediul crora vom manipula datele a doi studeni.
Listing 2-3. Utilizarea tipurilor compozite pentru manipularea datelor entitilor reale.
Sub aplicatieSimpla_test_Types()
Dim stud_1 As Student
Dim stud_2 As Student
Dim i As Integer
'redimensionam tablourile :
ReDim stud_1.note(4)
ReDim stud_2.note(4)
'initializam atributele :
stud_1.nume = "Gigel"
stud_1.matricol = "EL101"
stud_1.dataNasterii = #10/31/1982#
stud_1.note(0) = 10
stud_1.note(1) = 8
stud_1.note(2) = 5
stud_1.note(3) = 7
stud_1.note(4) = 10
stud_2.nume = "Costel"
stud_2.matricol = "EL102"
stud_2.dataNasterii = #2/22/1982#
stud_2.note(0) = 10
stud_2.note(1) = 9
stud_2.note(2) = 10
stud_2.note(3) = 9
stud_2.note(4) = 10
Console.WriteLine("notele studentului " & stud_1.nume)
For i = 0 To 4
Debug.Print(stud_1.note(i))
Next
End Sub

Aspectul esenial ce trebuie reinut n exemplul de mai sus se refer la


notaia cu punct. Astfel, se observ c spre deosebire de variabilele
declarate de tipuri primitive, pentru tipurile compozite atribuim valori
atributelor dup o schem de genul:
numeVariabil.numeAtribut=valoare
unde valoarea trebuie s fie de tipul declarat la costruirea ablonuluitip.
Prin notaia cu punct valoarea atributului este strict asociat variabilei
ce descrie entitatea respectiv. Cu alte cuvinte, studentul 1 este
reprezentat n exemplul nostru de variabila stud_1 i are numele Gigel,

48

data naterii 31-10-1982 etc. Pentru studentul 2 desemnm o alt


variabil,

stud_2,

care

preia

alte

valori

pentru

aceleai

atribute

(nume=Costel, dataNasterii=22-2-1982) aceste valori fiind strict asociate


variabilei stud_2.
n cazul n care atributul este de tip tablou, accesul la elementele
acestuia se realizeaz n mod similar variabilelor simple de tip tablou, doar
c se mai adaug la stnga variabila-entite i punctul corespunztor
pentru a specifica entitatea de care vor aparine valorile elementelor
tabloul respectiv. n exemplul de mai sus, pentru a atribui a doua not
studentului Gigel, procedam astfel:
stud_1.Note(2) = 8

Figura 2-14 rezultatul execuiei procedurii din listingul 2-3

Not!

Vezi

prezentarea

curs_6.ppt

(portal.feaa.uiac.ro)

pentru

mecanismul privind transferul datelor la operaia de atribuire


Variabilele prin care se gestioneaz datele pentru tipurile compozite pot
fi utilizate n mod similar variabilelor clasice pot fi contruite tablouri de
elemente de tipul respectiv (n exemplul nostru Student) i pot constitui
parametri ai unor funcii sau procedurii. n exemplul ce urmeaz ne
propunem s construim o funcie care s primeasc drept argument o
instan Stundent i s returneze media notelor studentului respectiv.
Listing 2-4 Funcie cu parametru de tip compozit (Student)
Function calculMedia(ByVal stud As Student)
Dim sumaNote As Double, restanta As Boolean, i As Integer

49

sumaNote = 0
restanta = False
For i = LBound(stud.Note) To UBound(stud.Note)
If stud.Note(i) < 5 Then
restanta = True
Exit For
Else
sumaNote = sumaNote + stud.Note(i)
End If
Next
If restanta Then
calculMedia = 4
Else
calculMedia = sumaNote / UBound(stud.Note) - LBound(stud.Note) + 1
End If
End Function

Vom utiliza aceast funcie ntr-o aplicaie precum cea din listingul 2-5.
Procedura aplicaie() const n construirea unui vector de studeni
(elementele vectorului vor fi de tip Student), atriburea unor note aleatoare
fiecrui student i invocarea funciei calculMedia() cu fiecare element al
vectorului drept parametru actual.
Se observ c, n mod similar variabilelor, atributele unui element al
vectorului vectStudenti se acceseaz prin utilizarea notaiei cu punct:
vectStudenti(1).Nume = "Gigel"

Cu alte cuvinte, studentul 1 va avea numele Gigel, studentul 2 va


avea numele Costel .a.m.d.
Listing 2-5. Structurarea instanelor tipurilor compozite ca elemente ale unui tablou i
utlizarea lor ca parametri pentru funcii/proceduri
Sub Aplicatie()
Dim vectStudenti(3) As Student
vectStudenti(0).nume = "Gigel"
vectStudenti(0).matricol = "EL101"
vectStudenti(0).dataNasterii = #10/31/1982#
vectStudenti(1).nume = "Costel"
vectStudenti(1).matricol = "EL102"
vectStudenti(1).dataNasterii = #2/22/1982#
vectStudenti(2).nume = "Fanel"
vectStudenti(2).matricol = "EL103"
vectStudenti(2).dataNasterii = #3/1/1981#
vectStudenti(3).nume = "Gerogel"
vectStudenti(3).matricol = "EL104"
vectStudenti(3).dataNasterii = #7/28/1984#
' atribuim 5 note aleatoare pentru fiecare student si le afisam

50

' apoi afisam media


Dim textSirNote As String, i As Integer, k As Integer, randomNota,
media As Double
For i = 0 To 3
textSirNote = ""
ReDim vectStudenti(i).note(4)
For k = 0 To 4
randomNota = Rnd() * 10 + 4
randomNota = IIf(randomNota > 10, 10, randomNota)
vectStudenti(i).note(k) = Math.Round(randomNota, 2)
textSirNote = textSirNote & vectStudenti(i).note(k) & _
IIf(k < 4, " , ", "")
Next
Console.WriteLine(vectStudenti(i).nume & "-->note:" & textSirNote)
media = calculMedia(vectStudenti(i))
Console.WriteLine(vectStudenti(i).nume & "-->are media:" & media)
Next
End Sub

Not. Funcia IIF (IF imediat) o putem utiliza n locul unei structuri IFTHEN-ELSE i are urmtoarea definiie:
IIF(condiie, val_return_if_True, val_return_if_false)
Iat i rezultatul execuiei procedurii din listingul 2-5

51

Figura 2-15 execuia procedurii din listingul 2-5

Important! Nu trebuie s uitm c modalitatea de transmitere a


parametrilor (ByVal sau ByRef vezi, anterior, paragraful corespunzator)
trebuie selectat n funcie de necesitile aplicaiei. Astfel, dac funcia
calculMedia() ar trebui s modifice unul din atributele studentului (s
presupunem c ar exista atributul media), atunci declaraia funciei ar fi:
Function calculMedia (ByRef stud as Student)

COMPUNEREA TIPURILOR
Am vzut, mai devreme, c atributele ce descriu un tip compozit pot fi
att tipuri primitive (String, Double, Date etc.) ct i tipuri structurate
(tabloul Note pentru exemplul tipului Student). Exist ns i posibilitatea
de a declara un atribut al unui tip compozit ca fiind de un alt tip compozit.
Mai mult, un atribut poate stoca o structur (tablou) de entiti din alte
tipuri. Astfel, dac ne propunem s gestionm, ntr-o aplicaie, gupe de
studeni, putem spune c o grup este caracterizat de un numr

52

(indicativ) i un ansamblu de elemente de tip Student ce vor reprezenta


studenii grupei respective. Prin abstactizare, putem defini un nou tip,
Grupa, astfel:
Public Structure Grupa
Public idGrupa As Long
Public studenti() As Student
End Structure
Declararea unui atribut ca fiind de un tip compozit sau tablou de
elemente

compozite este cunoscut sub numele de compunerea

tipurilor. Astfel, spunem c am compus un tip nou, Grupa, prin utilizarea


tipului Student definit anterior.
n definiia noului tip, atributul studenti este declarat ca vector de
elemente Student, fr a i se preciza dimensiunea, urmnd ca, la
momentul instanierii tipului Grupa (constituirea unei grupe reale) s
furnizm acestui atribut un tablou cu instane Student n funcie de
numrul de studeni din grupa respectiv.
Exemplul urmtor construiete o grup de studeni, apoi atribuie note n
mod aleator fiecruia, iar n final afieaz notele i media (prin invocarea
funciei calculMedia() definit n listingul 2-4).
Listingul 2-6. Manipularea datelor tipurilor compuse pe baza altor tipuri.
Sub Aplicatie_2()
' Construim o instanta Grupa si dimensionam tabloul de studenti
Dim grupa_1 As Grupa
grupa_1.idGrupa = 311
ReDim grupa_1.studenti(3)
grupa_1.studenti(0).nume = "Gigel"
grupa_1.studenti(0).matricol = "EL101"
grupa_1.studenti(0).dataNasterii = #10/31/1982#
ReDim grupa_1.studenti(0).note(3)
grupa_1.studenti(1).nume = "Costel"
grupa_1.studenti(1).matricol = "EL102"
grupa_1.studenti(1).dataNasterii = #2/22/1982#
ReDim grupa_1.studenti(1).note(3)
grupa_1.studenti(2).nume = "Fanel"
grupa_1.studenti(2).matricol = "EL103"
grupa_1.studenti(2).dataNasterii = #3/1/1981#
ReDim grupa_1.studenti(2).note(3)
grupa_1.studenti(3).nume = "Gerogel"
grupa_1.studenti(3).matricol = "EL104"
grupa_1.studenti(3).dataNasterii = #7/28/1984#
ReDim grupa_1.studenti(3).note(3)
' atribuim 5 note aleatoare pentru fiecare student al grupei si le afisam
' apoi afisam media
Dim textSirNote As String, i As Integer, k As Integer, randomNota As Double

53

For i = LBound(grupa_1.studenti) To UBound(grupa_1.studenti)


textSirNote = ""
For k = LBound(grupa_1.studenti(i).Note) To
UBound(grupa_1.studenti(i).Note)
randomNota = Rnd * 10 + 4
randomNota = IIf(randomNota > 10, 10, randomNota)
grupa_1.studenti(i).Note(k) = Math.Round(randomNota, 2)
textSirNote = textSirNote & grupa_1.studenti(i).Note(k) & " , "
Next
Console.WriteLine(grupa_1.studenti(i).nume & "-->note:" & textSirNote)
Console.WriteLine(grupa_1.studenti(i).nume & "-->media:" _
& calculMedia(grupa_1.studenti(i)))
Next
End Sub

Figura 2-16 rezultatul execuiei procedurii din listingul 2-6

i n acest caz, esenial de remarcat este utilizarea notaiei cu


punct pentru a accesa valorile atributelor de tipuri compozite.
Schema general este:
variabilaTipComp.atributTipComp.atributPrimitiv = valoare
Astfel, pornind de la exemplul din listingul 2-6, pentru a modifica
numele primului student al grupei 311

(Gigel), scriem urmtoarea

operaie de atribuire
Grupa_1.studenti(1).nume=Apetrei Marius

n mod similar, pentru a modifica a doua not a studentului 3 din grupa


1, scriem urmtoarea operaie:
Grupa_1.studenti(3).Note(2)=8

54

Spunem, astfel, c am modificat elementul 2 al tabloului note (de tip


primitiv Double) asociat elementului-entitate 3 al tabloului studenti (de
tip Student) asociat variabilei-entitate grupa_1 (de tip Grupa)
Bineneles c nu ne oprete nimeni s construim nc un tip, cu numele
Facultate, descris prin structura:
Public Struncture Facultate
Public denumire As String
Public adresa As String
Public grupe() As Grupa
END STRUCTURE
n acest caz, atribuirea unei note va fi realizat pe baza unui ablon de
notaie cu punct, dup cum urmeaz:
Dim f as Facultate
initializare atribute
f.grupe(i).studenti(k).note(j)=

2.3. Clase i obiecte. Scurt introducere n programarea


orientat-obiect
n decursul istoriei programrii, mult vreme s-a considerat c orice
problem poate fi rezolvat printr-un algoritm sau un ansamblu de
algoritmi. Cu alte cuvinte, o problem era adaptat pentru a fi modelat
pe nelesul mainii de calcul. O aplicaie consta n asamblarea unor
module ce descriu algoritmic o anumit manier de manipulare a datelor.
Odat cu sporirea complexitii aplicaiilor, a fost inventat o nou
modalitate de organizare a datelor: crearea unor tipuri derivate (definite
de programator) ce reprezentau concepte din spaiul problemei. Astfel,
pentru a reprezenta entiti din lumea real, abloanele anterior construite
pot fi utilizate prin asocierea unor valori explicite atributelor descriptive
ale acelui tip de entitate. Ca urmare, ntr-un algoritm, datele puteau fi
reprezentate

manipulate

ntr-o

manier

abstractizat,

mult

mai

apropiat de modelul de gndire natural uman.


La un moment dat ns, n procesul de abstractizare s-a mai fcut un
pas: tipurilor compozite li se pot asocia operaii, transformndu-se,
astfel, din structuri de date pasive, manipulate de algoritmi supervizori, n

55

uniti active, ce definesc un anume comportament ca rspuns la stimuli


externi. Aceste noi tipuri au fost numite clase , operaiile au fost numite
metode, iar instanele lor (elemente din lumea real aparinnd acelui tip)
au fost numite obiecte. Metodele nu sunt altceva dect proceduri i/sau
funcii

care

se

asociaz

mod

indivizibil

claselor

prin

care

programatorul specific ansamblul de operaii ce pot fi realizate de


obiectele ce provin din acea clas. Asta nseamn c acele obiecte pot s
manipuleze singure datele pe care le conin (valorile atributelor), sau pot
s efectueze operaii cu acele date i s returneze un rezultat, ca urmare a
unui apel provenit de la un alt obiect. Aceste apeluri sunt numite generic
mesaje. Astfel, problemele pot fi modelate ntr-un mod foarte natural, ca
un ansamblu de obiecte ce comunic ntre ele.
Obiectele pot fi caracterizate prin stare i comportament. Definim
starea obiectului ca fiind setul de valori al atributelor unui obiect la un
moment dat. Comportamentul este dat de ansamblul operaiilor pe care
le poate efectua un obiect. nterminologia OO, operaiile sunt denumite
metode.
Limbajele care ofer suport pentru definirea claselor i manipularea
obiectelor prin mesaje se numesc limbaje orientate-obiect.
n aceast nou viziune, procesul de dezvoltare a unei aplicaii se
axeaz pe identificarea entitilor (conceptelor cheie) din spaiul problemei
i a operaiilor pe care le realizeaz aceste entiti. O dat identificate
atributele descriptive ale fiecrei entiti i implementate operaiile sub
form de metode, aplicaia n sine va presupune implementarea unei
tehnici de manipulare a obiectelor i transmiterea de mesaje ntre acestea.
Fiecare obiect va asigura o poriune distinct din logica aplicaiei.
Dei elementele descrise mai sus pot fi implementate, Visual Basic nu
este un limbaj care poate fi numit orientat-obiect, pentru c nu ofer
suport pentru alte cteva concepte eseniale ale programrii orientateobiect (motenire, suprascriere, suprancrcre, polimorfism), concepte ce
nu au fost descrise aici pentru c depesc obiectivul acestui curs.
Pentru exemplificare acestui stil de programare vom porni de la tipurile
Student i Grupa definite n seciunea anterioar. La momentul respectiv
constriserm o funcie, calculMedia(stud as Student) (listing 2-4), cu
rolul de a calcula media unui student pe baza notelor reprezentate prin
atributul de tip tablou, Note. Aadar, un algoritm primea ca argument o
instan a tipului Student i prelucra datele coninute de aceasta. Notele

56

pentru fiecare student erau preluate n mod aleator, tot ntr-un algoritm
distinct, cu numele aplicatie (listing 2-5)
n cele ce urmeaz, vom schimba maniera de abordare a problemei:
vom construi o clas care va descrie entitatea Student prin intermediul
acelorai atribute (matricol,nume, datanasterii i vectorul Note) iar
pentru calculul mediei i preluarea notelor vom defini dou metode
(operaii) la nivelul acestei clase. Ca urmare, la nivelul aplicaiei, dup
instanierea claselor i obinerea obiectelor de tip Student, vom trimite
cte un mesaj fiecrui obiect pentru a genera notele i a obine mediile.
Astfel, logica prelucrilor se transfer de la nivelul aplicaiei la nivelul
definirii operaiilor pentru fiecare tip din spaiul problemei.
Algoritmi (module aplicaie)

Stud1

Stud3
Aplicatie

Stud2

Stud1

Stud2

Stud3

Grupa

obiecte

Grupa

Date
Programare Procedural
Aplicaie=Algoritmi+date

Programare orientat-obiect
Aplicaie= Ansamblu de obiecte ce comunic prin
mesaje

Figura 2-17 Diferene ntre abordarea procedural i cea obiectual


Clasa Student

Matricol
Nume
Datanasterii
Note[ ]

Atribute

CalculMedia()
IncarcaNoteExamene()
SetNota(ByVal nota, index)
GetNota(index)
Metode

Figura 2-18 Clasa Student

57

n VB.NET, pentru a construi o clas apelm la opiunea Add Class


Module din meniul context al SolutionExplorer-ului sau din meniul Project.
Numele clasei va fi introdus prin proprietatea name a modulului.

Figura 2-19 Crearea unei noi clase.

Observm c blocul pentru declararea unei clase este : Public Class


<nume_clasa> .... End Class. n interiorul acestor delimitatori vor fi
declarate atributele i metodele (operaiile) clasei

58

Listingul 2-7 prezint codul surs VB pentru definirea clasei Student. Se


observ c atributele clasei se declar ca variabile globale la nivelul
modulului (n seciunea General a modulului Student), iar metodele sunt
definite conform modalitii standard VB de construire a funciilor sau
procedurilor.

Bineneles

ntr-o

aplicaie

real,

metoda

incarcaNoteExamene() ar prelua notele dintr-o resurs extern (fiier,


baz de date) sau ar invoca o metoda specifica a unui alt obiect (care ar
putea fi de tip Examen spre exemplu) . Pentru simplificarea exemplului, n
acest caz notele se genereaza aleator.
Listing 2-7 Definiia clasei Student
Public Class Student
' Declararea atributelor
Public Matricol As String
Public Nume As String
Public DataNasterii As Date
' in cazul claselor, tablourile pot fi declarate cu o anumita dimensiune :
Public Note(4) As Double
'Urmeaza declararea si implementarea metodelor
Public Sub loadNoteExamene()
Dim k As Integer, randomNota As Double
For k = LBound(Note) To UBound(Note)
randomNota = Rnd() * 10 + 4.5
randomNota = IIf(randomNota > 10, 10, randomNota)
Note(k) = Math.Round(randomNota, 2)
Next
End Sub
Function calculMedia()
Dim sumaNote As Double, restanta As Boolean, i As Integer
sumaNote = 0
restanta = False
For i = LBound(Note) To UBound(Note)
If Note(i) < 5 Then
restanta = True
Exit For
Else
sumaNote = sumaNote + Note(i)
End If
Next
If restanta Then
calculMedia = 4
Else
calculMedia = sumaNote / (UBound(Note) - LBound(Note) + 1)
End If
End Function
Public Sub setNota(ByVal nota As Double, ByVal index As Integer)
If index >= LBound(Note) And index <= UBound(Note) And nota >= 1 And nota
<= 10 Then
Note(index) = nota
End If
End Sub

59

Public Function getNota(ByVal index As Integer)


If index >= LBound(Note) And index <= UBound(Note) Then
getNota = Note(index)
Else
getNota = -1
End If
End Function
End Class

n definiia clasei observm urmtoarele:


atributul Note este declarat ca Private. Asta nseamn c

vizibilitatea acestui membru se reduce doar la nivelul metodelor


definite de aceeai clas, n timp ce alte obiecte/aplicaii nu vor
avea acces direct la valorie tabloului printr-un apel de genul:
variabila_stud.Note(1). Exist dou motive pentru care acest
atribut este declarat Private:
restricie impus de limbaj: atributele de tip tablou cu

numr fix de elemente i atributele de tip compozit (tipuri


noi definite de programator) nu pot fi declarate publice.
Chiar dac limbajul ar permite-o, este indicat ca

atributul Note s fie declarat Private pentru ca un alt


obiect/aplicaie s nu poat modifica n mod direct notele
studentului.
i totui cum rezolvm problema accesului (fie citire, fie modificare) la
atributul note? Rspunsul este: prin intermediul unor metode declarate
Public (deci vizibile din exteriorul obiectului). n mod normal trebuie s
implementm dou metode una pentru citirea valorilor i alta pentru
modificarea lor. Att timp ct accesul la valorile atributului se poate realiza
doar

prin

intermediul

unor

metode,

putem

defini

asemenea

implementare a metodei de modificare nct s restricionm, ntr-o


anumit msur, domeniul de valori acceptabile pentru atributul respectiv.
O astfel de restricie ar putea fi ca notele studentului s fie cuprinse n
intervalul 1-10.

Dac am dori s restricionm complet modificarea

valorilor, am defini doar o metod de citire. Iat de ce, definiia clasei


Student cuprinde i dou metode suplimentare:

getNota(byVal index as Integer) metod ce va returna


valoarea Note(index),

bineneles dac

indexu-ul primit ca

parametru se ncadreaz n limita maxim i limita minim

setNota(ByVal nota As Double, byVal index As Integer)


metod ce ofer posibilitatea modificrii notelor. Se observ
(listingul 2-7) c modificarea elementului corespunztor al

60

tabloului Note are loc doar dac valoarea nou (parametrul nota)
se ncadreaz n intervalul 1-10
Instanierea claselor. Manipularea obiectelor prin variabile
n mod similar tipurilor compozite, obiectele se manipuleaz prin
intermediul unor variabile de tip pointer (dein o referin ctre zona de
memorie n care sunt stocate datele obiectului).
Pentru a obine un obiect dintr-o anumit clas utilizm sintaxa : NEW
Clasa. n mod similar datelor scalare, obiectele se manipuleaz prin
intermediul variabilelor, doar c acestea vor fi ntotdeauna de tip pointer
(vor primi o referin spre zona de memorie n care este stocat obiectul).
variabila_pointer = NEW numeClasa
Cuvntul cheie NEW are rolul de a aloca o nou zon de memorie
pentru a stoca valorile atributelor noului obiect.
Ulterior, pentru a adresa atributele obiectului i a citi/scrie valori,
utilizm varibila i notaia cu punct n mod similar tehnicii prezentate
pentru cazul tipurilor compozite (vezi subcapitolul anterior):
Variabila_pointer.atribut=valoare
Aceeai notaie cu punct se utilizeaz i pentru a invoca o metod a
obiectului ( a transmite un mesaj):
Call Variabila_pointer.metoda()

Exemplu de construire i manipulare a unui obiect prin intermediul variabilelor-pointer


Module TesteClase_Obiecte
Sub testObiecteStudent()
Dim x, y As Student
x = New Student
y = New Student
x.Nume = "Student_X"
y.Nume = "Student_y"
x.setNota(7, 2)
Console.WriteLine("a treia nota a studentului " & x.Nume & "este :"
& x.getNota(2))
' incarca tabloul de note cu ajutorul metodei loadNote (note aleatoare)

61

x.loadNoteExamene()
Console.WriteLine("media " & x.Nume & " este: " & x.calculMedia())
y = x
Console.WriteLine("media " & y.Nume & " este: " & y.calculMedia())
End Sub
End Module

n listingul de mai sus este prezentat un exemplu de manipulare a


datelor asociate prin intermediul unor obiecte de tip Student. Iat i o
descriere pe scurt a fiecrei operaii:
1 se instaniaz clasa Student, de dou ori, adresele de memorie ale
noilor obiecte fiind preluate de variabilele x i y.
2 numele studenilor (Student_X i Student_Y) sunt setate prin
intermediul atributului Nume al noului obiect; utilizm notaia cu punct
pentru a accesa atributul obiectului prin intermediul variabilei x sau y
3 se invoc metoda setNota() pentru a atribui nota 7 pe poziia 3 n
tabloul intern de note pentru studentul Student_X (variabila x)
4 se afieaz a treia not a studentului X. Pentru c atributul Note
este specificat Private, nu pot fi accesate elementele printr-un apel de
genul: stud1.Note(2). Ca urmare, se invoc metoda getNota(index)
definit tocmai n scopul de a oferi acces la elementele tabloului.
5

se

modific

notele

studentului

prin

invocarea

metodei

loadNoteExamene(); conform implementrii (listing 2-7) aceast metod


va genera note aleatoare i le va ncrca n tabloul Note .
6 se afieaz media studentului X
7- variabila y preia adresa lui x y i x vor fi pointeri ctre acelai
obiect Student (n spe, Student X)
8 se afieaz aceleai informaii ca la punctul 6 doar c prin
intermediul variabilei y
Not.

Vezi i prezentarea curs_6.ppt (portal.feaa.uiac.ro) pentru

mecanismul de transfer al referinei la operaia de atribuire


Compunerea claselor. Colecii de obiecte.
n mod similar tipurilor compozite, atributele claselor pot fi tipuri de
date scalare (predefinite) sau pot defini referine ctre alte obiecte.
Procesul prin care construim o clas cu unul sau mai multe atribute ce vor
prelua referine ctre obiecte din alte clase se numete compunerea
claselor.

62

Revenind la situaia exemplificat n seciunea dedicat compunerii


tipurilor compozite (subcap. 2.2), presupunem c dorim s construim clasa
Grupa, obiectele din aceast clas urmnd a reprezenta o anumit grup
de studenti. Atributele acestei clase ar fi: idGrupa (indicativul grupei) i
studenti (o colecie de obiecte din clasa Student definit anterior).
Pentru acest din urm atribut exist dou variante de implementare:
1.

sub forma unui tablou fr numr precizat de elemente, n mod


similar exemplului din seciunea 2.2. n acest caz, la momentul
utilizrii unui obiect Grupa, am asocia membrului studenti un
tablou definit explicit cu elemente Student, sau am utiliza
intruciunea Redim Preserve (vezi finalul sectiunii 2.1) pentru a
adauga/sterge un obiect din tabloul respectiv.

2.

sub forma unei colecii dinamice, colecie reprezentat n VB tot


prin intermediul unei clase (predefinite) : Collection.

Clasa Collection este mult mai potrivit pentru a implementa colecii


dinamice(n care pot fi adaugate/sterse elemente) de obiecte deoarece
furnizeaz un comportament natural pentru manipularea elementelor
coleciei. Tocmai de aceea o vom utiliza n exemplul nostru. Aceast clas
definete urmtoarele metode:
- Add (item [ , key] [, before] [, after] ) adauga elementul item
(poate fi un obiect sau o valoare de tip scalar (String, Double, Variant,
etc.)) n colecie. Ultimiii trei parametri sunt opionali, astfel c, prin
ignorarea lor, elementul nou, furnizat prin intermediul primului parametru
(item), va fi adugat la sfaritul coleciei. Prin intermediul parametrilor
(opionali) before /after funrnizm o poziie explicit pentru noul element
(item) n colecie iar prin intermediul parametrului key (trebuie s fie o
valoare de tip String unic n respectiva colecie) specificm un alt
identificator al elementului n locul poziiei (indexului) acestuia.
- Item (index) extrage i returneaz elementul de la poziia
specificat prin parametrul index. Dac s-a utilizat o cheie de identificare
a elementeloir coleciei, parametrul index poate furniza valoarea cheii (de
tip String aa cum am precizat mai sus) ce va fi cutat pentru a
identifica elementul asociat.
- Remove(index) elimin din colecie elementul de la poziia/cheia
precizat

prin

index.

Important

de

reinut

este

faptul

indicii

elementelor rmase se vor actualiza n consecin (dac avem 5 elemente


i este extras primul, elementele rmase vor fi numerotate 1..4)
- Count() returneaz numrul de elemente al coleciei

63

Aadar, o colecie dinamic va fi reprezentat de un obiect din clasa


Collection, obiect pe care l vom manipula prin intermediul unei
variabile. n exemplele furnizate n listingul urmtor se creaz un nou
obiect de tip Collection, i se testeaz att adugarea, extragerea,
tergerea unor elemente de tip Scalar (String n cazul de fa) ct i a unor
obiecte

de

tip

Student

Deasemenea,

se

testeaz

identificarea

elementelor prin poziie, ct i prin cheie (n cazul celei de-a doua


proceduri, elemenetele de tip Student sunt manipulate att prin poziie ct
i printr-o cheie de tip string cu semnificaia de matricol)
Listing Manipularea elementelor unei colecii

Sub testColectii()
Dim c As Collection
c = New Collection
c.Add("abc")
c.Add("def")
Console.WriteLine("elementul
Console.WriteLine("elementul
c.Add("xyz", Before:=2)
Console.WriteLine("elementul
Console.WriteLine("elementul

1: " & c.Item(1))


2: " & c.Item(2))
2 dupa insert: " & c.Item(2))
3 dupa insert: " & c.Item(3))

c.Remove(2)
Console.WriteLine("elementul 1 dupa remove: " & c.Item(1))
Console.WriteLine("elementul 2 dupa remove: " & c.Item(2))

End Sub
Sub testIdentificarePrinCheie_Colectii()
Dim c As Collection
c = New Collection
c.Add(New Student, "EL01")
c.Add(New Student, "EL02")
c.Item(1).nume = "Student 1"
c.Item(2).nume = "Student 2"
c.Item("EL01").dataNasterii = #1/15/1985#
c.Item("EL01").dataNasterii = #10/24/1986#
Console.WriteLine("elementul 1: " & c.Item(1).nume & " nascut la : " &
c.Item(1))
Console.WriteLine("elementul 2: " & c.Item("EL02").nume & " nascut la : " &
c.Item("EL02"))
End Sub

Pentru a parcurge o colecie, element cu element, utilizm o structur


de control specific VB:

64

FOR EACH variabila IN colectie


instructiuni
NEXT
Dup cum spuneam mai devreme, elementele unei colecii dinamice de
tip Collection pot fi att valori scalare ct i alte obiecte. Ca urmare,
putem defini clasa Grupa (ale crei instane vor reprezenta grupe de
studenti) astfel:
Listing 2-8 Definiia clasei Grupa
Public Class Grupa
Public idGrupa As Long
Public studenti As Collection
Public Function calculMediaGrupa()
Dim sumaMediiStud As Double
Dim stud As Student
For Each stud In studenti
sumaMediiStud = sumaMediiStud + stud.calculMedia()
Next
calculMediaGrupa = sumaMediiStud / studenti.Count
End Function
End Class

Funcionalitatea metodei calculMediaGrupa() este, credem, evident:


calculul mediei aritmetice generale a studenilor grupei. Se observ
tehnica de parcurgere, element cu element, a coleciei de obiecte de tip
Student reprezentat de membrul studenti. n cadrul buclei For Each
Next, variabila stud va deine la fiecare pas, o referin ctre urmtorul
obiect din colecie, astfel c, prin intermediul acestei variabile putem
accesa membrii (definii de clasa Student) pentru obiectul respectiv: n
acest caz, metoda calculMedia() .
Listingul urmtor prezint codul unei aplicaii (o procedur definit ntrun modul separat) care lucreaz cu obiecte din cele dou clase definite
(Student i Grupa).
De remarcat c utilizm o singura variabila (stud) pentru a construi
diferite obiecte Student. Fiecrae obiect, o dat complet construit, va fi
pasat coleciei studenti a obiectului Grupa, astfel c variabila stud va
putea fi reutilizat pentru a ine o referin ctre un nou obiect Student.

65

Dei exemplul definete o singur grup, pot fi create oricte obiecte de


tip Grupa sau Student.
Listing 2-9. O procedur pentru testarea gestionrii obiectelor prin variabile i colecii
Sub aplicatie()
Dim stud As Student
Dim grupa_1 As Grupa
' construim un obiect de ti Grupa
grupa_1 = New Grupa
grupa_1.idGrupa = 311
grupa_1.studenti = New Collection
'adaugam obiecte Student in colectia "studenti"
'aceeasi variabila, stud, o vom utiliza pentru a instantia obiectele Student
stud = New Student
stud.Nume = "Gigel"
stud.Matricol = "EL101"
stud.DataNasterii = #10/31/1982#
grupa_1.studenti.Add(stud)
stud = New Student
stud.Nume = "Costel"
stud.Matricol = "EL102"
stud.DataNasterii = #2/22/1982#
grupa_1.studenti.Add(stud)
stud = New Student
stud.Nume = "Fanel"
stud.Matricol = "EL103"
stud.DataNasterii = #3/1/1981#
grupa_1.studenti.Add(stud)
stud = New Student
stud.Nume = "Gerogel"
stud.Matricol = "EL104"
stud.DataNasterii = #7/28/1984#
grupa_1.studenti.Add(stud)
' afisam notele si media fecarui student al grupei
Dim textSirNote As String, i As Integer, k As Integer, randomNota As Double
For Each stud In grupa_1.studenti
textSirNote = ""
stud.loadNoteExamene() genereaza note aleatoare
For k = 0 To 4
textSirNote = textSirNote & stud.getNota(k) & " , "
Next
Debug.Print(stud.Nume & "-->note:" & textSirNote)
Debug.Print(stud.Nume & "-->media:" & stud.calculMedia())
Next
'

afisam media generala a grupei prin apelul metodei calculMedia()

Debug.Print(" Media Grupei:" & grupa_1.calculMediaGrupa())

66

End Sub

2.4. Tratarea erorilor


Managementul

erorilor

ntr-o

aplicaie

este

activitate

foarte

important pentru funcionalitatea corect a respectivei aplicaii. S lum


urmtoarea procedur drept exemplu:
Sub testErori()
Dim a(1) As String, index As Integer
a(0) = "test A"
a(1) = "test A"
index = InputBox("introduceti pozitia pentru a afla elementul
corespunzator din tabloul A :")
MsgBox(a(index))
MsgBox("alte prelucrari")
End Sub

ntrebarea fireasc ar fi : ce se va ntmpla dac utilizatorul introduce


un numr n afara limitei minime sau maxime a poziiilor disponibile n
tablou? Sau : ce se va ntmpla dac nu introduce un numr ci un
caracter?
La ambele ntrebri rspunsul este unul singur: aplicaia va genera o
eroare care, nefiind tratat n mod corespunztor, va determina blocarea
acesteia
Pentru a evita asemenea probleme, procedura de mai sus poate fi
scris i astfel:
Sub testErori()
Dim a(1) As String, index As Integer
a(0) = "test A"
a(1) = "test A"
Try
index = InputBox("introduceti pozitia pentru a afla elementul
corespunzator din tabloul A :")
MsgBox(a(index))
Catch ex As Exception
MsgBox("index invalid")
End Try
MsgBox("alte prelucrari")
End Sub

67

Astfel, utilizm un bloc Try-Catch pentru a prinde eventualele erori i


a genera un mesaj corespunztor. n varianta 2, procedura testErori() va
funciona ntotdeauna (mesajul alte prelucrri va apare indiferent dac
se declaneaz o eroare sau nu), doar c , n cazul n care utilizatorul nu
introduce un index valid, va obine mesajul index invalid
Aadar:
Try

secvene de cod care pot genera erori la run-time


Catch ex as Exception
secventa de cod pentru tratarea erorilor
End Try
. Alte prelucrri .

2.5. Liste
O lista este o structur abstract de date ce reprezint o colecie de
elemente de informaie ( denumite generic noduri) aranjate intr-o anumit
ordine. Lungimea unei liste este numarul de noduri din lista. Structura
corespunzatoare de date trebuie sa ne permita sa determinam eficient
care este primul/ultimul nod in structura si care este
predecesorul/succesorul (daca exist) unui nod dat. Iat cum arat cea
mai simpla lista, lista liniar:

O lista circulara este o lista in care, dupa ultimul nod, urmeaza primul,
deci fiecare nod are succesor si predecesor.
Capul
/coada listei

Operaii curente care se fac in liste sunt: inserarea unui nod, stergerea
(extragerea) unui nod, concatenarea unor liste, numrarea elementelor
unei liste etc. Implementarea (reprezentarea algoritmic) unei liste se
poate face in principal in doua moduri:

Implementarea

secventiala,

in

locaii

succesive

de

memorie,

conform ordinii nodurilor in lista. Avantajele acestei tehnici sunt


accesul rapid la predecesorul/succesorul unui nod si gasirea rapida a
primului/ultimului

nod.

Dezavantajele

sunt

inserarea/stergerea

68

relativ complicat a unui nod i faptul ca, in general, nu se foloseste


intreaga memorie alocata listei.

Implementarea inlnuit. In acest caz, fiecare nod conine doua


pri:
o

informaia propriu-zis si

adresa (pointer ctre) nodului succesor.

Alocarea memoriei fiecarui nod se poate face in mod dinamic, in


timpul rulrii programului. Accesul la un nod necesita parcurgerea
tuturor predecesorilor si, ceea ce poate lua ceva mai mult timp.
Inserarea/tergerea unui nod este in schimb foarte rapida. Se pot
folosi doua adrese in loc de una, astfel incat un nod s conin, pe
langa adresa nodului succesor si adresa nodului predecesor.
Obinem astfel o lista dublu inlantuita, care poate fi traversat in
ambele directii.
Listele nlnuite pot fi reprezentate cel mai simplu prin intermediul
tablourilor.

In

acest

caz,

adresele

(nodului

succesor

i,

eventual,

predecesor) sunt de fapt indici de tablou. O alternativ este s folosim


tablouri paralele: s memorm informaia fiecarui nod (valoarea) intr-o
locatie VAL[i] a tabloului VAL[1 .. n], iar adresa (indicele) nodului sau
succesor intr-o locatie LINK[i] a tabloului LINK[1 .. n]. Indicele de tablou al
locaiei primului nod va fi memorat intr-o variabil, pe care o putem
denumi head. Vom conveni ca, pentru cazul listei vide, sa avem head = 0.
Convenim de asemenea ca LINK[ultimul nod din lista] = 0. Atunci,
VAL[head] va contine informaia primului nod al listei, LINK[head] adresa
celui de-al doilea nod, VAL[LINK[head]] informaia din al doilea nod,
LINK[LINK[head]] adresa celui de-al treilea nod etc.
Acest mod de reprezentare este simplu dar, la o analiza mai atent,
apare o problem esenial: cea a gestionarii locaiilor libere. O soluie
elegant ar fi s reprezentm locaiile libere tot sub forma unei liste
inlnuite. Atunci, stergerea unui nod din lista iniial implic inserarea sa
in lista cu locaii libere, iar inserarea unui nod in lista iniiala implica
stergerea sa din lista cu locaii libere. Aspectul cel mai interesant este c,
pentru implementarea listei de locaii libere, putem folosi aceleai tablouri.
Avem nevoie de o alta variabila, freehead, care va conine indicele primei
locatii libere din VAL si LINK. Folosim aceleasi conventii: daca freehead = 0
inseamn c nu mai avem locaii libere, iar LINK[ultima locatie libera] = 0.

69

Vom descrie in continuare, ceva mai amnunit, dou tipuri de liste


particulare foarte des folosite.

2.5.1.

Stive

O stiv (stack) este o lista liniar cu proprietatea c operaiile de


inserare/extragere a nodurilor se fac in/din coada listei. Daca nodurile A, B,
C, D sunt inserate intr-o stiva in aceasta ordine, atunci primul nod care
poate fi extras este D. n mod echivalent, spunem ca ultimul nod inserat
va fi i primul ters. Din acest motiv, stivele se mai numesc si liste LIFO
(Last In First Out ultimul intrat primul ieit), sau liste pushdown.
Cel mai natural mod de reprezentare pentru o stiva este implementarea
secventiala intr-un tablou S[1 .. n], unde n este numarul maxim de noduri.
Primul nod va fi memorat in S[1], al doilea n S[2], iar ultimul n S[top],
unde top este o variabil care conine adresa (indicele) ultimului nod
inserat. Iniial, cand stiva este vid, avem top = 0. Iat operaiile de
inserare si de tergere/ extragere a unui nod:

function introdu(x, S[1 .. n])


{adauga nodul x in stiva}
if top n then return stiva plina
top top+1
S[top] x
return succes
function extrage(S[1 .. n])
{sterge ultimul nod inserat din stiva si il returneaza}
if top 0 then return stiva vida
x S[top]
top top-1
return x
Cei doi algoritmi necesita timp constant, deci nu depind de marimea
stivei.
Vom da un exemplu elementar de utilizare a unei stive. Daca avem de
calculat expresia aritmetica
5(((9+8)(46))+7)

70

putem folosi o stiva pentru a memora rezultatele intermediare. Intr-o


scriere simplificata, iata cum se poate calcula expresia de mai sus:
push(5); push(9); push(8); push(pop + pop); push(4); push(6);
push(pop pop); push(pop pop); push(7); push(pop + pop);
push(pop pop); write (pop);
Observam ca, pentru a efectua o operatie aritmetica, trebuie ca
operanzii sa fie deja in stiva atunci cand intalnim operatorul. Orice
expresie aritmetica poate fi transformata astfel incat sa indeplineasca
aceasta conditie. Prin aceasta transformare se obtine binecunoscuta
notatie postfixata (sau poloneza inversa), care se bucura de o proprietate
remarcabila: nu sunt necesare paranteze pentru a indica ordinea
operatiilor. Pentru exemplul de mai sus, notatia postfixata este:
5 9 8 + 4 6 7 +
Pentru a implementa conceptul de stiv n VB vom construi o clas care
va defini un atribut intern de tip tablou i operaiile descrise mai sus. Fa
de operaiile generice prezentate mai sus, cele definite de clasa Stiva nu
definesc parametrul de tip tablou, tocmai pentru c acest tablou este
pstrat intern (vezi atributul vStiva) de obiectul obinut prin instanierea
clasei:
Definiia clasei Stiva:
Public Class Stiva
Dim vStiva()
Dim top As Long
Sub initializeaza(ByVal nrMaxElemente As Long)
ReDim vStiva(nrMaxElemente - 1) 'indexul tabloului porneste de la zero
top = -1
End Sub
Sub introdu(ByVal element As Object)
If top + 1 > UBound(vStiva) Then
MsgBox("Stiva plina!")
Exit Sub
End If
top = top + 1
vStiva(top) = element
End Sub
Function extrage() As Object
Dim element As Object
If top < LBound(vStiva) Then
MsgBox("Stiva vida!")
Return Nothing
Else
element = vStiva(top)
top = top - 1
Return element
End If

71

End Function
End Class

Iata si o secventa de test:


Sub testeStiva()
Dim s As Stiva
s = New Stiva()
s.initializeaza(3)
s.introdu("element 1")
s.introdu("element 2")
s.introdu("element 3")
s.introdu("element 4") 'se va afisa mesajul "stiva plina"
Console.WriteLine(s.extrage()) va fi afisat element 3
Console.WriteLine(s.extrage()) va fi afisat element 2
Console.WriteLine(s.extrage()) va fi afisat element 1
Console.WriteLine(s.extrage()) ' se va afisa mesajul "stivaVida"

End Sub

2.5.2.

Cozi

O coada (queue) este o lista liniara in care inserarile se fac doar in


capul listei, iar extragerile doar din coada listei. Cozile se numesc si liste
FIFO (First In First Out).
O reprezentare secventiala interesanta pentru o coada se obtine prin
utilizarea unui tablou C[0 .. n-1], pe care il tratam ca si cum ar fi circular:
dupa locatia C[n-1] urmeaza locatia C[0]. Fie tail variabila care contine
indicele locatiei predecesoare primei locatii ocupate si fie head variabila
care contine indicele locatiei ocupate ultima oara. Variabilele head si tail
au aceeasi valoare atunci si numai atunci cand coada este vida. Initial,
avem head = tail = 0. Inserarea si stergerea (extragerea) unui nod
necesita timp constant.

72

function insert-queue(x, C[0 .. n-1])


{adauga nodul x in capul cozii}
head (head+1) mod n
if head = tail then return coada plina
C[head] x
return succes
function delete-queue(C[0 .. n-1])
{sterge nodul din coada listei si il returneaza}
if head = tail then return coada vida
tail (tail+1) mod n
x C[tail]
return x
Este surprinzator faptul ca testul de coada vida este acelasi cu testul de
coada plina. Daca am folosi toate cele n locatii, atunci nu am putea
distinge intre situatia de coada plina si cea de coada vida, deoarece in
ambele situatii am avea head = tail. In consecinta, se folosesc efectiv
numai n-1 locatii din cele n ale tabloului C, deci se pot implementa astfel
cozi cu cel mult n-1 noduri.
Pentru implementarea cozilor, n VB.NET, vom recurge, deasemenea, la
paradigma orientat pe obiecte. Astfel, definitia clasei Coada o regsim n
listingul urmtor:
Definiia clasei Coada:
Public Class Coada
Dim vCoada()
Dim head As Long
Dim tail As Long
Public coadaPlina As Boolean
Public coadaVida As Boolean
Sub initializeaza(ByVal nrMaxElemente As Long)
ReDim vCoada(nrMaxElemente) 'indexul minim al vectorului =0
head = 0
tail = 0
End Sub
Sub adauga(ByVal element As Object)
Dim v As Long
v = (head + 1) Mod (UBound(vCoada) + 1)
If v = tail Then
MsgBox("Coada plina")
coadaPlina = True
Else
head = v
coadaPlina = False
vCoada(head) = element
End If

73

End Sub
Function extrage() As Object
If head = tail Then
MsgBox("Coada vida")
Return Nothing
Else
tail = (tail + 1) Mod (UBound(vCoada) + 1)
If head = tail Then
coadaVida = True
Else
coadaVida = False
End If
Return vCoada(tail)
End If
End Function
End Class

Iat i o secven de test:


Sub testeCoada()
Dim s As Coada
s = New Coada()
s.initializeaza(3)
s.adauga("element 1")
s.adauga("element 2")
s.adauga("element 3")
s.adauga("element 4") 'se va afisa mesajul "stiva plina"
While Not s.coadaVida
Console.WriteLine(s.extrage())
End While
End Sub

3. Algoritmi
3.1.

Algoritmi clasici de cutare i sortare

74

n munca unui programator, cutarea n diferite structuri de date reprezint o operaie foarte
des efectuat. Exemplele cele mai frecvente se refer la cutarea unei anumite nregistrri dintr-un
fiier de un anumit tip, regsirea unei anumite valori ntr-un tablou care conine mai multe elemente,
parcurgerea unei liste n cutarea unui anumit reper, etc. n funcie de specificul problemei concrete
care trebuie rezolvat, fiecare dintre structurile sau valorile cutate pot avea sau nu diverse proprieti:

toate valorile sunt distincte ntre ele;

valorile sunt ordonate n conformitate cu o anumit relaie de ordine (ex.:


valorile dintr-un vector sunt ordonate cresctor);

ntre dou operaiuni de cutare structura de date nu sufer modificri sau


pot avea loc operaiuni de inserare/tergere/modificare.
De asemenea, sortarea elementelor unor liste dup anumite criterii constituie

o parte esenial a oricrei aplicaii.


Dei majoritatea limbajelor de programare actuale ofer una sau mai multe
tehnici implicite (built in) de cutare a unor elemente n diverse structuri de
date, precum i de stocare a elementelor ntr-o anumit ordine,

totui orice

programator trebuie s fie contient de complexitatea operaiilor ce se execut n


asemnea proceduri. Iat de ce prezentm n continuare cei mai cunoscui, i mai
simpli, algoritmi de cutare i sortare pe structuri statice de date. Algoritmii
pentru structuri dinamice de date comport o complexitate ceva mai ridicat i
vor fi tratai n seciuni distincte. Trebuie s precizm c nu exist un cel mai
bun algoritm, fiecare deinnd propriile puncte tari i slabe din punct de vedere
al vitezei de execuie sau a cantitii de memorie.

3.1.1.

Cutarea n mulimi complet ordonate

Pentru a simplifica problema, vom considera c datele sunt stocate n vectori


i c exist un singur criteriu de cutare. De asemenea vom lua n considerare
doar cazul n care elementele vectorului sunt strict ordonate, pentru liste
neordonate fiind necesar parcurgerea secvenial element cu element, caz ce
poate fi uor pus n practic.
Unul din cei mai cunoscui algoritmi de cutare pe mulimi ordonate este
devide-et-impera. Scopul acestui algoritm este de a returna poziia la care se
gsete valoarea cutat n list.
Astfel, presupunem c se caut valoarea A n secvena T[p..q]. reamintim c
are loc T[p] < T[p+1] < < T[q]. Descrierea algoritmului poate fi definit astfel:

se determin m cu pmq ca fiind poziia de mijloc a listei (m=(p+q)/2);

dac A= T[m] atunci cutarea se termin cu succes;

dac A< T[m] atunci cutarea continu cu subsecvena T[p .. m-1];

dac A> T[m] atunci cutarea continu cu subsecvena T[m+1 .. q].

75

Aadar, verific dac elementul cutat nu este cumva egal cu cel aflat la
jumtatea listei. Dac este mai mic dect valoarea de la mijlocul listei, vom relua
cutarea doar n segmentul de valori din stnga iar dac este mai mare dect
valoarea de la mijlocul listei vom relua cutarea doar n segmentul din dreapta .

Figura 3-20 Schema logic pentru reprezentarea algoritmului de cutare Divide Et Impera

Iat i implementarea n VisualBasic a algoritmului:


Listing 3.1 Divide et Impera n VB
Sub cauta_DivideEtImpera(vector, valCheie)
inceput = LBound(vector)
extrag primul index al vectorului primit ca parametru
sfarsit = UBound(vector)
extrag ultimul index al vectorului primit ca parametru
mijloc = Int((sfarsit + inceput) / 2)
Do While vector(mijloc) <> valCheie And inceput < sfarsit
If valCheie > vector(mijloc) Then
inceput = mijloc + 1

76
Else
sfarsit = mijloc - 1
End If
mijloc = Int((sfarsit + inceput) / 2)
Loop
If vector(mijloc) = valCheie Then
Debug.Print ("valoarea " & valCheie & "se afla la pozitia:" & mijloc)
Else
Debug.Print ("valoarea " & valCheie & "nu se gaseste in multime")
End If
End Sub

Pentru a testa procedura cauta_DivideEtImpera() construim o rutin


care va furniza datele de test reprezentate sub for ma vectorului Multime :
Sub test(valCautata)
Dim Multime(1 To 6)
Multime(1) = -3
Multime(2) = -2
Multime(3) = 20
Multime(4) = 53
Multime(5) = 75
Multime(6) = 80
Call cauta_DivideEtImpera(Multime, valCautata)
End Sub

n final se invoc procedura test(), eventual din fereastra Immediate (meniul


ViewImmediate Window) a mediului VB ca n figura 3-2 .

77

Figura 3-21 Testarea procedurii cauta_divideEtImpera().

3.1.2.

Problema sortrii

Dac problema cutrii este una relativ simpl d.p.d.v. al algoritmului


prezentat mai devreme, o problem ceva mai complex o constituie ordonarea
elementelor unui vector; astfel, transformarea unui vector X ntr-un vector pentru
care:
X[i] <= X[i+1] , 1 <= i <= n-1,
folosind o cantitate minim de memorie suplimentar, se numete sortare.
BubbleSort
Unul dintre cei mai cunoscui i utilizai algoritmi de sortare este i cel mai
slab din punctul de vedere al eficienei. Este vorba de algoritmul BubbleSort
(metoda bulelor). Ideea algoritmului este foarte simpl. Dorim s obinem un
vector pentru care s fie ndeplinit condiia:
X[i] <= X[i+1] , 1 <= i <= n-1.
Dac aceast condiie este ndeplinit de la nceput, atunci nu trebuie s
se mai execute nici o transformare asupra irului. Dac ns gsim o pereche de
valori (i, i+1) pentru care X[i] > X[i+1] vom corecta acest aspect schimbnd

78

ntre ele cele dou elemente. Deci o prim aproximaie a algoritmului ar putea s
fie urmtoarea:
pentru fiecare pereche de valori execut
{
dac nu sunt n ordinea corect atunci
schimb valorile ntre ele
}
Se pune ns ntrebarea dac o astfel de parcurgere a vectorului este
suficient; s considerm de exemplu irul de valori:
9

Dac parcurgem elementele vectorului o singur dat, utiliznd algoritmul


prezentat vom obine:
6

Se observ c cel mai mare element a ajuns n ultima poziie, dar celelalte
valori nu sunt nc pe poziiile corecte. Pentru exemplul considerat (care este cel
mai dezavantajos posibil din punct de vedere al ordonrii iniiale), se observ c
sunt necesare N-1 parcurgeri ale vectorului. Dac ns irul valorilor este de la
nceput ordonat, acest fapt se constat dup o singur parcurgere. Aadar,
numrul de parcurgeri necesar depinde de ordinea iniial a elementelor ce
formeaz vectorul.
n cazul unui vector oarecare trebuie s se execute parcurgeri repetate,
pn ce se constat c s-a obinut un vector ordonat. Procesul de sortare poate fi
accelerat dac se ine seama de faptul c dup o parcurgere o parte dintre
elementele vectorului (ncepnd de la cel de-al doilea din ultima pereche
modificat) sunt deja sortate.

Elemente sortate la
parcurgerile anterioare

Elemente analizate la urmtoarea


parcurgere

+1

Ultima modificare
Elementele localizate la dreapta locaiei ultimei interschimbri nu mai
trebuie analizate la urmtoarea parcurgere, pentru c acestea sunt deja sortate
deci numrul de perechi analizate trebuie actualizat la sfritul fiecrei
parcurgeri, aa cum se procedeaz n algoritmul urmtor (prezentat n pseudocod
i schem logic).

79

BubbleSort(X, N)
Begin
NP = N 1 //NP este nceputul prii sortate din list
DO
UltimaModificare = 0
pentru fiecare pereche i de la 1 la NP execut
{
dac ordine incorect atunci
{
interschimb valorile
UltimaModificare = i
}
}
NP = UltimaModificare 1
WHILE UltimaModificare > 1
END

80

Figura 3-22 Schema logic pentru BubbleSort (consideram plaja de valori a indexului elementelor listei: 1-N)

Iat n continuare i implemenetarea algoritmului n VisualBasic:

81
Listing 3-2 Procedura VB pentru BubbleSort
Sub bubbleSort(vector)
Debug.Print ("lista initiala (neordonata):")
afiseazaVector (vector)
nrPasi = UBound(vector) 1
minIndex = LBound(vector)
Do
ultimaModificare = 0
For i = minIndex To nrPasi
If vector(i) > vector(i + 1) Then
temp = vector(i)
vector(i) = vector(i + 1)
vector(i + 1) = temp
ultimaModificare = i
End If
Next
nrPasi = ultimaModificare - 1
Debug.Print ("pas intermediar:")
afiseazaVector (vector)
Loop While ultimaModificare > 1
Debug.Print ("lista sortata:")
afiseazaVector (vector)
End Sub
Sub afiseazaVector(v)
sir = ""
For i = LBound(v) To UBound(v)
sir = sir & v(i) & ","
Next
Debug.Print (sir)
End Sub

Se observ c implementarea VB comport o mic modificare fa de


algoritmul prezentat n figura 3-3: utilizm functiile Lbound() si Ubound() pentru a
afla limita minima, respectiv maxim a indexului elementelor vectorului (vezi i
seciunea 2.1 despre tablouri). Procedura afiseazaVector() are sarcina de a
afia elementele vectorului i este apelat i n cadrul buclei DoWhile tocmai
pentru a evidenia strile tranzitorii prin care trece lista de elemente la fiecare
parcurgere.
n final, pentru a testa algoritmul, construim o procedur care s defineasc o
list de numere aleator generate (funcia Rnd ) i care s invoce procedura
bubleSort() prezentat mai sus.
Sub testSortare()
Dim MultimeNeordonata(6)
For i = 0 To 6
MultimeNeordonata(i) = Int(Rnd * 80)
Next
Call bubbleSort(MultimeNeordonata)

vor fi generate numere intregi 1-80

End Sub

La rndul ei, procedura testSortare() poate fi apelat direct din fereastra

Immediate a mediului VB, dup cum se observ i n figura ce urmeaz ( a se


observa faii intermediari de sortare afiai):

82

Figura 3-23 Testarea procedurii bubbleSort().

Sortarea prin inserie


Una dintre familiile importante de tehnici de sortare se bazeaz pe metoda
juctorului de bridge (atunci cnd i aranjeaz crile), prin care fiecare
element este inserat n locul corespunztor n raport cu elementele sortate
anterior.
Principiul de baz al algoritmului de sortare prin inserie este urmtorul: se
presupune c subsecvena (X[1], , X[k-1]) este sortat. Se caut n aceast
subsecven locul i al elementului X[k] i se insereaz X[k] n poziia i. Poziia i
este determinat astfel:

i = 1 dac X[k] < X[1];

1 < i < k i satisface X[i-1] <= X[k] < X[i];

i=k dac X[k] >= X[k-1].


Poziia elementului i este determinat prin cutare secvenial de la

dreapta la stnga simultan cu deplasarea elementelor mai mari dect X[i] cu o


poziie la dreapta. Cu alte cuvinte:

lista se parcurge de la stnga spre dreapta

la fiecare pas al parcurgerii listei elementul curent este memorat ntr-o


variabil distinct (s zicem temp)

83

procesul de parcurgere ncepe cu cel de-al doilea element al listei; dac este
mai mare dect primul rmne pe loc, iar dac nu (este mai mic dect
primul), primul trece pe locul celui de-al doilea iar cel de-al doilea trece pe
primul

pentru al treilea element al listei procesul se reia:


o

se memoreaz n variabila temp

se parcurge lista napoi pn gsim un element <= temp ; la acest


moment locul valorii memorate n temp este imediat dup elementul
mai mic dect temp (dac gsim un asemenea element, procesul de
cutare napoi se oprete pentru c toate elementele la stnga sunt
deja sortate n paii anteriori); odat cu parcurgerea napoi, elementele
> temp se deplaseaz cu o poziie la dreapta.

Dac, n urma cutrii n submulimea din stnga nu se gsete nici un


element <=temp, nseamn c valoarea memorat n temp este cea
mai mic la momentul actual i o plasm pe prima poziie

Procesul se repet pentru al patrulea element, .a.m.d

84

Lista iniial

sortate

sortate

sortate

sortate

30
1
25
10
17

30

1
30
25
10
17

1
30

1
25
30
10
17

1
25
30

1
10
25
30
17

1
10
25
30

30
1
25
10
17

1
30
25
10
17

25

1
25
30
10
17

10

1
10
25
30
17

17

1
10
17
25
30

30
25
10
17

25
10
17

25

1
30
10
17

10
17
10

1
25
30
17

17
17

1
10
25
30

Lista sortat

Iat i schema logic a acestui algoritm

85

Figura 3-24 Algoritmul InsertSort. (domeniul de valori al indexului vectorului se consider 1 : N)

Listing 3-3 Algoritmul InsertSort implementat n VB


Sub insertSort(vector)

86
Debug.Print ("MULTIMEA INITIALA (neordonata): " & getStringFromVector(vector) &
Chr(13))
For i = LBound(vector)+1 To UBound(vector)
temp = vector(i)
Debug.Print ("
valoarea temp la pasul- " & i & " - este :" & temp)
locGasit = False
k = i - 1
Do While (Not locGasit) And k >= LBound(vector)
If temp > vector(k) Then
locGasit = True
Else

'(deplasez elementul mai mare cu o pozitie la dreapta)

vector(k + 1) = vector(k)
k = k - 1
End If
Loop
vector(k + 1) = temp
Debug.Print ("
dupa executia pasului - " & i & " - vectorul
& getStringFromVector(vector))

arata astfel: "

Next
Debug.Print (Chr(13) & "MULTIMEA ORDONATA: " & getStringFromVector(vector))
End Sub
Function getStringFromVector(v)
sir = ""
For i = LBound(v) To UBound(v)
sir = sir & v(i) & ","
Next
getStringFromVector = sir
End Function

Iat i procedura care va furniza datele de test :


Sub testSortare()
Dim MultimeNeordonata(6)
For i = 0 To 6
MultimeNeordonata(i) = Int(Rnd * 80) ' genereaza numere aleatoare 1-80
Next
Call insertSort(MultimeNeordonata)
End Sub

Cteva comentarii asupra implementrii VB:

n VB, pentru a porni procesul repetitiv de cutare a poziiei de la


elementul

al

Ubound(vector))

doilea,
utilizm

(For

i=Lbound(vector)+1

funciile

LBound(vector)

to
i

Ubound(vector) pentru a obine limita inferioar, respectiv limita


superioar a indexului elementelor. n cazul de fa, elementele
vectorului sunt indexate de la 0 (n precedura testSortare(),
vectorul

pentru

test

este

declarat

mod

clasic,

Dim

MultimeNeordonata(6), adic 7 elemente: de la 0 la 6).


Elementele vectorului MultimeNeordonata se genereaz aleator

87

prin utilizarea funciei Rnd care returneaz un numr aleator real


cuprins ntre limitele 0 i 1

Pentru fiecare pas al buclei FOR se afieaz valoarea elementului


curent (memorat n variabila temp) a crui poziie este cutat n
subirul ordonat din stnga poziiei acestuia (operatorul &
concateneaz operanzii ntr-un singur ir de caractere):

Debug.Print ("

valoarea temp la pasul- " & i & " - este :" & temp

De asemenea, pentru fiecare pas al buclei FOR, dup execuia


prelucrilor specifice, se afieaz coninutul curent al vectorului
parial ordonat.

Debug.Print ("
dupa executia pasului - " & i & " - vectorul
getStringFromVector(vector))

arata astfel: " &

n final (dup ieirea din bucla FOR) se afieaz vectorul ordonat


(CHR(13) returneaz caracterul specific pentru a obine o linie
liber)

Debug.Print (Chr(13) & "MULTIMEA ORDONATA: " & getStringFromVector(vector))

Pentru afiarea vectorului (n diferite ipostaze) s-a construit


funcia

getStringFromVector()

care

preia

un

tablou

unidimensional ca argument i returneaz un ir de caractere


obinut din elementele vectorului separate prin virgul

Figura 3-25 testarea algoritmului insertSort

88

3.2.

Recursivitate

Prin recursivitate se inelege faptul ca un subprogram se apeleaza pe el


insui, apelul fiind generat atunci cand subprogramul este inca activ.
Exista dou tipuri de recursivitate:
1) recursivitate directa - cand un subprogram se autoapeleaza in
corpul sau ;
2) recursivitate indirecta - cand avem doua subprograme (x si y), iar
x face apel la y si invers ;
ntr-o form general, o funcie recursiv poate s arate astfel:
Function functie_1( parametri )
...
if conditie then
return valoare
else
return functie_1(valori_parametri)
End Function
Se observ c nu exist o sintax specializat pentru a specifica
recursivitatea, simplul fapt c n corpul subrutinei exist un apel la ea
nsi fiind suficient pentru a obine o subrutin recursiv. Lucrurile se
petrec ntocmai ca pentru orice proces de invocare a unei subrutine: rutina
principal i suspend execuia n timp ce controlul este transferat unei
alte instane a aceleiai funcii.
Se folosesc algoritmi recursivi atunci cand calculele aferente sunt
descrise in forma recursiva.
Ca prim exemplu vom apela la N factorial. Funcia N factorial poate fi
descris n dou moduri:
1 liniar fact(N)=N x N-1 x N-2 x 1
2 recursiv fact(N) = 1 daca n=1
= N x fact(N-1) pentru n>1
Astfel, prima variant (descrierea liniar) poate fi implementat ntr-un
algoritm prin iteraie (structura de control repetitiv vezi n capitolul 1.2
seciunea dedicat structurilor fundamentale de control) .
Cea de-a doua variant de descriere a funciei va fi implementat
printr-un algoritm recursiv.
Un subprogram recursiv trebuie scris astfel incat sa respecte regulile :
a) Subprogramul trebuie sa poata fi executat cel putin o data
fara a se autoapela ;

89

b) Procesul de autoapel va avea la baz o asemenea logic nct s


se tind spre situaia de execuie fara autoapel.
Cu alte cuvinte, ntr-o funcie recursiv ntotdeauna va exista un test de
genul
IF cond THEN return valoare ELSE apel recursiv
Iat algoritmul recursiv pentru N factorial implementat n VB:
Function factorialRecursiv(n)
If n = 1 Then
factorialRecursiv = 1
Else
factorialRecursiv = n * factorialRecursiv(n - 1)
End If
End Function

Figura 3-26 Testarea functiei recursive factorialRecursiv()

90

Apel funcie
(invocare)

FactorialRecursiv(1)
N=1

Return 1

Transfer rezultat
FactorialRecursiv(2)
N=2

Return 2
FactorialRecursiv(3)
N=3
Debug.print( FactorialRecursiv(4) )

Return 6

N=4

FactorialRecursiv(4)

Return 24
Figura 3-27 Paii parcuri la execuia funciei factorialRecursiv() cu n=4

Ce se intimpla de fapt? Mai nti se apeleaza funcia factorialRecursiv()


de n-1 ori fara a ajunge la un rezultat. Fiecare instan a funciei (vzut
ca proces separat n memorie) i suspend execuia ateptnd un rezultat
de la funcia apelat. La cel de-al n-lea apel, parametrul actual n este 1 i
algoritmul nu mai intr pe ramura False a structurii IF ci pe ramura True.
n acest caz funcia returneaz valoarea 1 i i oprete execuia (nu se
suspend ci se ncheie definitiv), moment n care se declaneaz un
proces n cascad de returnare de valori de la o funcie la alta pe niveluri
descresctoare.

Limbajul gestioneaz funciile cu execuia suspendat

prin intermediul unei stive (vezi capitolul 2 dedicat structurilor de date


dinamice), prima funcie apelat (factorialRecursiv(4)) fiind ultima
care primete un rezultat.
Pentru implementarea recursivitatii se foloseste o zona de memorie in
care se poate face salvarea temporar a unor valori. La fiecare appel
recursiv al unui subprogram se salveaza in aceasta zona de memorie
starea curenta a execuiei sale (toate valorile variabilelor la moemntul
suspendrii execuiei).
Dei variabilele locale ale subprogramului apelant au aceleai nume cu
cele ale subprogramului apelat, orice referire la aceti identificatori se
asociaza ultimului set de valori alocate in zona de memorie. Zona de
memorie ramne alocat pe tot parcursul executiei subprogramului apelat

91

si se dealoc n momentul revenirii in programul apelant. Zona de


memorie nu este gestionata explicit de programator ci de catre limbaj.
La terminarea executiei subprogramului apelat recursiv, se reface
contextul programului din care s-a facut apelul. Datorita faptului ca la
fiecare autoapel se ocupa o zona de memorie, recursivitatea este eficienta
numai daca numarul de autoapelari nu este prea mare pentru a nu se
ajunge la umplerea zonei de memorie alocata.
Recursivitatea ofera avantajunl unor soluii algoritmice mai clare pentru
probleme de o anumit natur. Ea prezint ins dezavantajul unui timp
mai mare de execuie i a unui spaiu de memorie alocat mai mare. Este
de preferat ca atunci cand programul recursiv poate fi transformat intrunul iterativ sa se faca apel la cel din urm.
n continuare vom prezenta alte cteva exemple de algoritmi recursivi clasici.
Sirul lui Fibonacci ( descoperit in 1202 de catre Leonardo Pisano (Leonardo
din Pisa), cunoscut sub numele de Leonardo Fibonacci) este definit prin
urmtoarea recuren:

fib:N->N
fib(n)=1, daca n=0 sau n=1
=fib(n-2)+fib(n-1), daca n>1
Iat cteva din numerele acestui ir: 1 , 1 , 2 , 3 , 5 , 8 , 13
Iat i implementarea algoritmului recursiv in VB:
Function fibonacciNumber(n)
If n = 1 Or n = 0 Then
Debug.Print (1)
fibonacciNumber = 1
Else
fibonacciNumber = fibonacciNumber(n - 1) + fibonacciNumber(n - 2)
End If

Se observ c a fost introdus i un apel de afiare a valorii 1 n scopul de a


sesiza de cte se trece prin acelai pas.

92

Figura 3-28 Apeluri recursive pentru aflarea numrului de pe poziia 5 din irul Fibonacci

Dup testarea acestui algoritm cu N=40 s zicem, se va observa ct este de


ineficient (ca timp de execuie) deoarece recalculeaza de mai multe ori

aceleai valori.
Iat i o rezolvare iterativ a aceluiai algoritm, care necesit timp liniar.
Function fib2(n)
i = 1
j = 1
For k = 2 To n
Debug.Print (j)
j = i + j
i = j - i
Next
fib2 = j
End Function

Se va observa, la testarea acestui ultim algoritm cu acelai N=40, c timpul

de execuie este sensibil mai scurt.


Testarea celor dou variante de rezolvare demonstreaz afirmaia c algoritmii
recursivi ofer o rezolvare mai elegant i mai uor inteligibil a anumitor
probleme, dar comport un risc d.p.d.v al optimizrii vitezei de execuie.
Inversarea unui text. Presupunem c dorim s construim o funcie care, pe
baza unui ir de caractere primit ca parametru s returneze irul respectiv n
ordine invers (de la drepta la stnga. Funcia poate fi descris recursiv astfel:

textInvers(text) = text dac lungimea textului este 1 (1 caracter)


= ultimChar + textInvers(text - ultimChar) daca lungime text
>1

93

TextInvers(abcd)=d+(textInvers(abc))

cba
= c+ textInvers(ab)
= b+textInvers(a)

dcba
ba
a

=a
Iat i implementarea algoritmului n VB

Figura 3-29 Implementarea algoritmului textInversat() in VB si testarea functiei

Pentru detalii despre funciile predefinte VB Right(), Left(), Len(), vezi


cap 12 din lucrarea Finaru,L., Brava,I. - VB-Primii pai i urmtorii