Algoritmi Si Tehnici de Programare - Partea I - Material Suport

Embed Size (px)

DESCRIPTION

Algoritmi Si Tehnici de Programare - Partea I - Material Suport

Citation preview

  • Academia de Studii Economice din Bucureti

    Facultatea de Cibernetic, Statistic i Informatic Economic Catedra de Informatic Economic

    Cristian Uscatu Ctlina Cocianu

    Ctlin Silvestru

    Algoritmi n programarea calculatoarelor

    Material didactic pentru ID

    Acest material are la baz lucrarea Programarea calculatoarelor. Algoritmi n programare

    autori I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu, M. Mircea publicat la Editura ASE Bucureti, 2007

    Editura ASE Bucureti

    2010

  • Algoritmi n programare 2

    Copyright 2011, Cristian Uscatu, Ctlina Cocianu, Ctlin Silvestru Toate drepturile asupra acestei ediii sunt rezervate autorului Editura ASE Piaa Roman nr. 6, sector 1, Bucureti, Romnia cod 010374 www.ase.ro www.editura.ase.ro [email protected]

    Refereni:

    Prof. univ. dr. Ion Gh. ROCA Prof. univ. dr. Gabriel ZAMFIR

    ISBN 978-606-505-465-3

  • * Material didactic pentru ID * 3

    Titlul cursului: Algoritmi n programare Introducere: Cursul Algoritmi n programare se adreseaz studenilor facultii de Cibernetic, Statistic i Informatic Economic din cadrul Academiei de Studii Economice din Bucureti. Conform planului de nvmnt, cursul se desfoar n semestrul 1 al anului 2 de studiu.

    Cursul Algoritmi n programare este destinat iniierii studenilor n cteva aspec-te ale programrii calculatoarelor. Limbajul utilizat pentru demonstrarea concep-telor i aplicaiile practice este C standard (ANSI C). Obiectivele principale ale

    cursului vizeaz nsuirea de ctre studeni a cunotinelor teoretice i a abilitilor practice de lu-cru referitoare la urmtoarelor elemente din cadrul programrii calculatoarelor:

    tipurile dinamice de date i modul de lucru cu date alocate dinamic (masive de date); analiza, proiectarea, implementarea i utilizarea a subprogramelor; structurile de date externe (fiiere) i abiliti de lucru cu acestea.

    Cursul Algoritmi n programare este structurat n patru uniti de nvare, corespun-

    ztoare elementelor principale studiate (date dinamice i subprograme cte o unitate de nv-are, fiiere de date 2 uniti de nvare).

    n cadrul procesului de instruire pot fi utilizate ca resurse suplimentare materia-lele puse la dispoziie de biblioteca facultii, att n cadrul slii de lectur ct i prin serviciul de mprumut.

    De asemenea, laboratoarele Catedrei de Informatic Economic pot fi utilizate pentru studiu individual pe toat durata programului de lucru, atunci cnd nu se desfoar ore (programarea orelor n laboratoare poate fi consultat la secretari-atul Catedrei). Calculatoarele din laboratoare ofer medii de programare adecvate pentru dez-voltarea abilitilor de lucru n limbajul C i posibilitatea de accesare a bibliotecii virtuale a instituiei.

    Evaluarea cunotinelor se va realiza prin intermediul lucrrilor susinute pe par-cursul semestrului astfel:

    o prob practic, constnd n rezolvarea a dou probleme de programare din cadrul tematicii cursului;

    o lucrare scris. Ambele teste se susin n timpul orelor aferente temelor de control din calendarul disciplinei.

    Cele dou teste contribuie la formarea notei finale astfel:

    proba practic constituie 40% din nota final; lucrarea scris constituie 50% din nota final; din oficiu se acord 10%.

  • Algoritmi n programare 4

    Cuprins 1. Tipuri dinamice de date....................................................................................................... 6

    Obiectivele unitii de nvare ............................................................................................... 6

    1.1. Tipuri de date dinamice............................................................................................... 6

    1.2. Declararea i iniializarea pointerilor ........................................................................ 7

    1.3. Utilizarea pointerilor.................................................................................................... 8

    1.3.1. Operaii cu pointeri ................................................................................................ 8

    1.3.2. Legtura ntre pointeri i masive........................................................................ 10

    1.4. Alocarea dinamic a memoriei.................................................................................. 12

    1.5. Modificatorul const .................................................................................................... 13

    1.6. Tratarea parametrilor din linia de comand........................................................... 14

    Rspunsuri i comentarii la testele de autoevaluare ........................................................... 14

    Rezumat................................................................................................................................... 15

    Bibliografia unitii de nvare............................................................................................ 15

    2. Subprograme ...................................................................................................................... 16

    Obiectivele unitii de nvare ............................................................................................. 16

    2.1. Construirea i apelul subprogramelor ..................................................................... 16

    2.2. Transferul datelor ntre apelator i apelat............................................................... 19

    2.2.1. Transferul prin parametri................................................................................... 19

    2.2.2. Simularea transmiterii parametrilor prin adres ............................................. 21

    2.2.3. Comunicaia prin variabile globale .................................................................... 22

    2.3. Pointeri spre funcii.................................................................................................... 23

    2.4. Funcii cu numr variabil de parametri .................................................................. 27

    2.5. Calcul recursiv............................................................................................................ 30

    2.6. Exemple de aplicaii cu subprograme recursive...................................................... 32

    Rspunsuri i comentarii la testele de autoevaluare ........................................................... 37

    Rezumat................................................................................................................................... 39

    Bibliografia unitii de nvare............................................................................................ 39

  • * Material didactic pentru ID * 5

    3. Articolul i fiierul .............................................................................................................. 40

    Obiectivele unitii de nvare ............................................................................................. 40

    3.1. Articol: caracteristici generale i mod de declarare................................................ 40

    3.2. Referirea articolului i a elementelor componente.................................................. 42

    3.3. Articole cu structuri complexe .................................................................................. 45

    3.4. Constante de tip articol .............................................................................................. 46

    3.5. Fiierul i articolul ...................................................................................................... 47

    3.6. Metode de organizare a fiierelor i tipuri de acces ................................................ 48

    3.7. Structura sistemului de fiiere sub MS-DOS/Windows .......................................... 50

    3.8. Operaii de prelucrare a fiierelor ............................................................................ 52

    3.8.1. Nivelul inferior de prelucrare a fiierelor ........................................................ 53

    3.8.2. Nivelul superior de prelucrare a fiierelor ....................................................... 56

    Rspunsuri i comentarii la testele de autoevaluare ........................................................... 63

    Rezumat................................................................................................................................... 63

    Bibliografia unitii de nvare ............................................................................................ 63

    4. Algoritmi de prelucrare a fiierelor de date..................................................................... 64

    Obiectivele unitii de nvare ............................................................................................. 64

    4.1. Caracteristici generale ale algoritmilor de prelucrare a fiierelor ........................ 64

    4.2. Algoritmi de prelucrare a fiierelor binare care nu necesit actualizare.............. 69

    4.3. Algoritmi de prelucrare a fiierelor binare care necesit actualizare ................... 77

    4.3.1. Codificarea extern prin numere relative ........................................................ 77

    4.3.2. Codificarea intern prin numere relative ........................................................ 79

    4.3.3. Corespondena intern dintre chei i numere relative.................................... 80

    4.4. Sortarea fiierelor binare memorate dens................................................................ 90

    4.5. Interclasarea fiierelor binare memorate dens ........................................................ 94

    4.6. Prelucrarea masivelor memorate n fiiere binare.................................................. 95

    4.6.1. Prelucrarea vectorilor ........................................................................................ 95

    4.6.2. Prelucrarea matricelor....................................................................................... 96

    Rspunsuri i comentarii la testele de autoevaluare ........................................................... 98

    Bibliografia unitii de nvare ............................................................................................ 98

    Bibliografie .............................................................................................................................. 98

  • Algoritmi n programare 6

    1. Tipuri dinamice de date Cuprins Obiectivele unitii de nvare ............................................................................................... 6 1.1. Tipuri de date dinamice............................................................................................... 6 1.2. Declararea i iniializarea pointerilor ........................................................................ 7 1.3. Utilizarea pointerilor.................................................................................................... 8

    1.3.1. Operaii cu pointeri ................................................................................................ 8 1.3.2. Legtura ntre pointeri i masive........................................................................ 10

    1.4. Alocarea dinamic a memoriei.................................................................................. 12 1.5. Modificatorul const .................................................................................................... 13 1.6. Tratarea parametrilor din linia de comand........................................................... 14 Rspunsuri i comentarii la testele de autoevaluare ........................................................... 14 Rezumat................................................................................................................................... 15 Bibliografia unitii de nvare............................................................................................ 15 Obiectivele unitii de nvare

    Dup studierea acestei uniti de nvare, studenii vor avea cunotine teoretice i abiliti practice despre tipurile dinamice de date utilizate n programarea calculatoa-relor i vor putea utiliza aceste tipuri de date i structurile de tip masiv de date pen-

    tru rezolvarea problemelor de programare. Concret, se vor asimila cunotine i abiliti de lu-cru privind:

    tipurile de date pointer; operaii cu datele de tip pointer i aritmetica pointerilor; legtura dintre pointeri i masivele de date, n limbajul C; alocarea dinamic a datelor; tratarea parametrilor primii n linia de comand.

    1.1. Tipuri de date dinamice

    Pointerul este un tip de dat predefinit, care are ca valoare adresa unei zone de memo-rie (figura 1.1).

    Pointer Zona de memorie indicat de pointer

    Memoria intern

    Segmen:offset

    Fig. 1.1. Un pointer este adresa unei alte zone de memorie

    BogdanHighlight

  • * Material didactic pentru ID * 7

    Folosirea pointerilor prezint urmtoarele avantaje: nlocuirea expresiilor cu indici nmulirile din formula de calcul al rangului se transfor-

    m n adunri i deplasri; posibilitatea alocrii dinamice a memoriei; folosirea tipurilor procedurale de date; calculul adreselor.

    n operaiile cu pointeri se folosesc urmtorii operatori specifici:

    Operatori Simbol Utilizare Operator de refereniere * tip* Operator de refereniere & &nume

    Operator de derefereniere * *nume * definete un nou tip de dat (pointer la tip); & extrage adresa unei variabile (creeaz o referin); * acceseaz coninutul zonei de memorie indicate de pointer.

    Cei doi operatori au efect invers: *&nume nume. Exemplu 1. *&nume reprezint valoarea de la adresa variabilei nume (valoarea variabilei nume).

    1.2. Declararea i iniializarea pointerilor

    Fie TIP un tip de dat oarecare n limbajul C (inclusiv void). Declararea TIP* nume; este o declaraie de pointer. TIP* este un nou tip de dat denumit pointer spre TIP, iar nume este o variabil de tipul pointer spre TIP.

    Exemple 2. int* n; n este o variabil de tip pointer spre ntreg;

    3. struct complex {a,b:real;}* x; x este o variabil de tip pointer spre o structur de ti-pul complex; 4. void* p; p este o variabil de tip pointer spre void; p poate primi ca valoare adresa unei zone de memorie de orice tip.

    Dac TIP este un tip oarecare (mai puin void) atunci tipul TIP* este adresa unei zone de memorie de un tip cunoscut. Operaiile care se pot efectua asupra zonei respective de me-morie snt definite de tipul acesteia. Dac TIP este void, atunci TIP* este adresa unei zone de memorie de tip necunoscut. Deoarece nu se cunoate tipul zonei de memorie, nu snt definite operaiile care se pot efectua asupra ei.

    Pentru pointerii din exemplele anterioare se rezerv n memoria principal (n segmen-tul de date) cte o zon de 4B n care se va memora o adres.

    Cnd variabila nume nu este iniializat prin declarare, ea primete implicit valoarea NULL. La execuie, poate primi ca valoare adresa unei variabile numai de tipul TIP. Dac TIP este void, atunci nume poate primi adresa oricrei variabile, de orice tip.

  • Algoritmi n programare 8

    Exemple 4. int* nume; int a; float b; nume = &a; este o atribuire corect; nume are ca valoare adresa variabilei a. nume = &b; este o atribuire incorect; nume poate primi ca valoare doar adresa

    unei variabile ntregi. 5. void* nume; pointer fr tip

    int a; float b; variabile de tip ntreg, respectiv real nume = &a; atribuire corect nume = &b; atribuire corect; nume poate primi ca valoare adresa oricrei

    variabile, de orice tip. Iniializarea pointerilor se poate realiza ca n exemplul precedent sau, ca i pentru ce-

    lelalte variabile, la declarare, astfel: int a; int* nume=&a; Se observ folosirea operatorului de refereniere & pentru a crea o referin ctre vari-

    abila a. La alocarea dinamic a memoriei se folosete o alt metod pentru iniializarea unui pointer. Operatorul de derefereniere se utilizeaz att pentru definirea tipului pointer, ct i pentru referirea datelor de la adresa indicat de pointer.

    Exemplu 6. int a,b,c; int* nume; void* nume2; b=5; nume=&a; *nume=b; c=*nume+b; nume2=&b; *(int*)nume2=10; c=*(int*)nume2;

    Se observ folosirea conversiei de tip (typecasting), atunci cnd se lucreaz cu pointeri

    spre tipul void (fr tip). Chiar dac un pointer spre tipul void poate primi ca valoare adresa unei variabile de orice tip, pentru a putea lucra cu ea este necesar gestionarea corect a tipu-lui operanzilor.

    Teste de autoevaluare 1. Care snt operatorii specifici lucrului cu pointeri n limbajul C? Dai exemple de utilizare a lor.

    2. Care snt cele dou tipuri de pointeri? Care snt diferenele dintre ele? 1.3. Utilizarea pointerilor 1.3.1. Operaii cu pointeri

    Asupra pointerilor se pot efectua operaii aritmetice. Fie secvena: int *nume,*nume2, c, a, b; nume=&a; nume2=&a;

  • * Material didactic pentru ID * 9

    Incrementare/decrementare Dac nume este pointer spre un tip TIP, prin incrementare/decrementare, valoarea lui

    nume se incrementeaz/decrementeaz cu numrul de octei necesari pentru a memora o dat de tip TIP, adic cu sizeof(TIP).

    nume++ nume are ca valoare o adres care este incrementat i primete valoarea nume+sizeof(int) (care este adresa lui b);

    nume2-- nume are ca valoare o adres care este decrementat i primete valoa-rea nume-sizeof(int) (care este adresa lui c);

    Situaia iniial este urmtoarea:

    nume nume2 c a b

    4B 4B 2B 2B 2B

    Dup cele dou operaii:

    nume nume2 c a b

    4B 4B 2B 2B 2B Analog se execut operaiile ++nume i --nume.

    Exemplu 7. float v[20]; float* p; int i; p=&v[i]; unde i poate avea valori ntre 0 i 19

    n urma atribuirii ++p sau p++, p va avea ca valoare adresa lui v[i] plus 4 octei, adic adresa lui v[i+1]. Adunarea/scderea unui ntreg

    n general, dac p este un pointer spre un tip TIP, atunci cnd se adun un ntreg n la pointerul p, rezultatul va fi tot un pointer spre TIP, care are ca valoare adresa memorat n p, la care se adun de n ori numrul de octei necesari pentru a memora o dat de tip TIP, adic n*sizeof(TIP). Asemntor se execut scderea unui ntreg dintr-un pointer. nume+n nume primete valoarea nume+n*sizeof(int) nume-n nume primete valoarea nume-n*sizeof(int)

    Exemplu 8. Fie p i q pointeri spre tipul float (float* p, *q). Presupunnd c p a fost iniializat

    cu valoarea 0x0fff:0x3450, n urma operaiei q=p+3, q primete valoarea 0xfff:0x345c (se adu-n 3*4 octei). n urma operaiei q=p-2, q primete valoarea 0xffff:0x344a (se scad 2*4 octei). Operaiile descrise anterior se folosesc frecvent n lucrul cu masive. Compararea a doi pointeri

    Limbajul C permite compararea a doi pointeri ntr-o expresie, folosind oricare din ope-ratorii relaionali (==, !=, , =).

    Rezultatul expresiei nume op nume2 (unde op este unul din operatorii precizai anteri-or) este adevrat (nenul) sau fals (zero) dup cum nume este egal, mai mare sau mai mic dect nume2. Doi pointeri snt egali dac adresele care constituie valorile lor snt egale. Privind memoria intern liniar, ncepnd de la adresa 0 (zero), un pointer p este mai mare dect altul q, dac adresa pe care o conine p este mai ndeprtat de nceputul memoriei dect adresa coni-nut de q.

  • Algoritmi n programare 10

    Este permis i compararea unui pointer cu o valoare constant. Uzual se folosete comparaia cu valoarea NULL pentru a verifica dac pointerul a fost iniializat (un pointer ne-iniializat are valoarea NULL), folosind unul din operatorii == sau !=. Valoarea NULL este definit n stdio.h astfel: #define NULL 0

    De multe ori se prefer comparaia direct cu zero (nume==0 sau nume!=0). n loc de nu-me==0 se poate folosi expresia nume. Aceasta se interpreteaz astfel: dac nume nu a fost iniia-lizat, atunci are valoarea NULL (adic 0), deci expresia este fals. n caz contrar valoarea ex-presiei este nenul, deci adevrat. Asemntor se folosete expresia !nume.

    Exemplu 9. float* p,q,r,t; float a,b; p=&a; q=&b; r=&a; a=5; b=7; if(t) printf("Pointer initializat!\n"); else printf("Pointer neinitializat!\n"); if(p==r) printf("Pointeri egali\n"); else printf("Pointeri diferiti\n"); if(p>q) printf("%d\n",a); else printf("%d\n",b);

    Pe ecran se va afia: Pointer neinitializat! Pointeri egali 7 deoarece t are valoarea NULL, variabilele p i r au ca valoare adresa lui a, iar q conine adresa lui b, care este mai mare dect a lui a (datorit faptului c a a fost alocat primul). Diferena dintre doi pointeri

    Fie secvena: int m[50],* a, * b; a=&m[i]; b=&m[j];

    unde i i j snt ntregi n intervalul [0..49]. Expresia a-b are valoarea i-j, interpretat ca dis-tan ntre adresele a i b, exprimat n zone de memorie de lungime sizeof(int).

    Valoarea unei expresii diferen se calculeaz astfel: se face diferena ntre cele dou adrese (n octei), apoi se mparte la dimensiunea tipului de dat referit de cei doi pointeri (tipul int n exemplul de mai sus vezi figura 1.2). Cei doi pointeri trebuie s refere acelai tip de dat, altfel rezultatul nu are semnificaie (trebuie s aib tipuri identice). Operaia este util n lucrul cu masive.

    m

    a b

    i j

    Fig.1.2. Reprezentarea semnificaiei variabilelor din exemplul anterior

    Atenie: vorbim despre diferena dintre doi pointeri (nelegnd distana dintre cele dou adrese), nu despre scderea a doi pointeri.

    1.3.2. Legtura ntre pointeri i masive

    n limbajul C numele unui masiv este un pointer ctre tipul de dat al elementele masivului.

  • * Material didactic pentru ID * 11

    Pentru masivele unidimensionale: int m[50]; m are tipul int* int* p; p are tipul int*

    Diferena const n faptul c zona de memorie ctre care puncteaz m este rezervat la compilare (ceea ce nu se ntmpl n cazul pointerilor declarai ca atare). De aceea m nici nu poate primi valori n timpul execuiei programului (nu se poate schimba adresa memorat n m). El memoreaz adresa primului element din masiv. Referirea unui element m[i] este echi-valent cu *(m+i) coninutul de la adresa m+i. Limbajul C nu face nici un fel de verificri n privina depirii limitelor indicilor masivului, de aceea expresiile m[500] sau m[-7] vor fi considerate corecte de compilator, existnd riscul unor erori logice. Este sarcina programato-rului s se asigure c indicii nu vor depi limitele. Pentru masivele bidimensionale: int m[50][50]; m are semnificaia urmtoare: m[i][j] *(*(m+i)+j), re-prezint coninutul de la adresa j plus coninutul de la adresa memorat n m plus i. Aceasta poate fi interpretat astfel: m este un pointer spre un vector de pointeri, fiecare element al vec-torului fiind la rndul lui un pointer spre o linie a matricei (un vector de elemente de tip float).

    Figura 1.3. poate fi utilizat pentru a nelege mai bine cum se acceseaz elementele unui masiv bidimensional.

    Atenie: aceast figur NU reprezint modul de alocare n memorie a unei matrice sta-tice! Doar pentru matricele alocate dinamic zonele de memorie snt alocate n acest fel.

    m

    m[0] m[1] m[2] m[3] m[4]

    m[49]

    m[0,0] m[0,1] m[0,49]

    m[0,0] m[0,1] m[0,49]

    m[2,0] m[2,1] m[2,49]

    m[3,0] m[3,1] m[3,49]

    m[4,0] m[4,1] m[4,49]

    m[49,0] m[49,1] m[49,49 Fig.1.3. Reprezentarea modului de alocare dinamic a spaiului necesar

    pentru memorarea unei matrice 50x50

    Analog pot fi interpretate masivele cu mai multe dimensiuni. Exemplu 10. Un masiv cu trei dimensiuni float m[10][10][10] poate fi interpretat ca un pointer

    spre un vector de pointeri spre matrice; Un masiv cu n dimensiuni este tratat ca un pointer spre un vector de pointeri ctre masive cu n-1 dimensiuni.

    Pentru a lucra cu elementele unui masiv static se poate folosi adresarea indexat (m[i] pentru vectori sau m[i][j] pentru matrice) sau adresarea elementelor prin pointeri (*(m+i) pentru vectori sau *(*(m+i)+j) pentru matrice etc).

    Mai mult, pentru vectori se poate declara un pointer iniializat cu adresa de nceput a masivului, iar elementele masivului s fie referite prin intermediul acestui pointer.

    Exemplu 11. float* v[10]; float* p; p=v;

  • Algoritmi n programare 12

    Dup atribuire, pointerul p conine adresa de nceput a masivului i poate fi folosit pentru re-ferirea elementelor masivului. De exemplu, v[3] i p[3] refer aceeai zon de memorie.

    Test de autoevaluare 3. S se scrie secvena de program care citete de la tastatur elementele unei matrice, folosind expresii cu pointeri pentru adresarea elementelor matricei.

    1.4. Alocarea dinamic a memoriei

    Pentru a memora o dat de un anumit tip n heap este necesar s se declare un pointer ctre acel tip de dat, apoi s se rezerve memoria necesar. Pentru a rezerva spaiu n heap se folosete funcia standard:

    void* malloc(unsigned n); Funcia rezerv o zon de n octei n heap i returneaz adresa acesteia. Deoarece funcia re-turneaz pointer spre void este necesar conversia rezultatului spre tipul dorit, astfel: int* nume; nume=(int *) malloc(sizeof(int)); rezerv n heap spaiu pentru o valoare de tip ntreg.

    Eliberarea unei zone de memorie rezervate anterior se face prin funcia standard:

    void free(void* p); Funcia primete ca parametru un pointer (indiferent de tip) spre zona de memorie pe care tre-buie s o elibereze.

    Limbajul C ofer posibilitatea de a aloca contiguu zone de memorie pentru mai multe date de acelai tip, prin funcia standard:

    void* calloc(unsigned nr_elem, unsigned dim_elem); Funcia calloc rezerv o zon contigu de memorie pentru mai multe elemente de acelai tip, ntorcnd un pointer spre zona respectiv. Exist i o variant a lui malloc care returneaz n mod explicit un pointer ndeprtat (far):

    void* farmalloc(unsigned long n);

    Pentru eliberarea unei zone de memorie rezervate prin farmalloc se folosete funcia standard:

    void farfree(void* p);

    Exemple 12. int* masiv; masiv=(int*)calloc(50,sizeof(int)); rezerv spaiu de memorie pentru un vector cu 50 de elemente ntregi.

    13. Alocarea de spaiu n heap pentru o matrice se face conform figurii 1.3 pentru a putea ac-cesa elementele la fel ca n cazul unei matrice statice, prin dubl indexare;

    int** m; int n,p; /* se aloc spaiu pentru vectorul cu adresele celor n linii ale matricei */ m=(int**)malloc(m*sizeof(int*)); for(int i=0;i

  • * Material didactic pentru ID * 13

    14. S se scrie o funcie care s citeasc cel mult n numere ntregi i le pstreze n zona de memorie a crei adres de nceput este dat printr-un pointer. Funcia returneaz numrul va-lorilor citite. int cit_nr(int n, int* p) { int nr, i; int* q=p+n; // q este adresa unde se termina zona // rezervata pentru cele n numere i=0; while(p

  • Algoritmi n programare 14

    1.6. Tratarea parametrilor din linia de comand n linia de comand a unui program pot s apar parametri (sau argumente). Acetia snt iruri de caractere desprite prin spaii. Programul poate accesa argumentele prin inter-mediul parametrilor predefinii ai funciei main:

    void main(int argc, char* argv[]) unde argc conine numrul de parametri ai programului, incrementat cu 1.

    Exemplu 15. Dac programul nu are nici un parametru, argc are valoarea 1, dac programul are

    doi parametri, argc are valoarea 3 etc. Variabila argv este un vector de pointeri care conine adresele de memorie unde s-au

    stocat irurile de caractere care constituie parametrii programului. Primul ir (cu adresa argv[0]) conine identificatorul fiierului (inclusiv calea complet) care memoreaz progra-mul executabil. Urmtoarele iruri conin parametrii n ordinea n care au aprut n linia de comand (parametrii n linia de comand snt iruri de caractere separate prin spaii). Interpre-tarea acestor parametri cade n sarcina programului.

    Exemplu 16. S se scrie un program care afieaz parametrii din linia de comand.

    #include

    main(int argc, char *argv[]) { int i; printf("Fisierul executabil: %s\n", argv[0]); for(i=1;i

  • * Material didactic pentru ID * 15

    4. int i; printf("Nr. elemente: "); scanf("%d ", &n); *v=(float*)malloc(*n*sizeof(float)); for(i=0;i

  • Algoritmi n programare 16

    2. Subprograme Cuprins Obiectivele unitii de nvare ............................................................................................. 16 2.1. Construirea i apelul subprogramelor ..................................................................... 16 2.2. Transferul datelor ntre apelator i apelat............................................................... 19

    2.2.1. Transferul prin parametri................................................................................... 19 2.2.2. Simularea transmiterii parametrilor prin adres ............................................. 21 2.2.3. Comunicaia prin variabile globale .................................................................... 22

    2.3. Pointeri spre funcii.................................................................................................... 23 2.4. Funcii cu numr variabil de parametri .................................................................. 27 2.5. Calcul recursiv............................................................................................................ 30 2.6. Exemple de aplicaii cu subprograme recursive...................................................... 32 Rspunsuri i comentarii la testele de autoevaluare ........................................................... 37 Rezumat................................................................................................................................... 39 Bibliografia unitii de nvare............................................................................................ 39 Obiectivele unitii de nvare

    Dup studierea acestei uniti de nvare, studenii vor avea cunotine teoretice i abiliti practice necesare pentru lucrul cu subprograme. Ei vor putea analiza pro-blemele i construi subprogramele care le rezolv corect. Concret, se vor asimila cu-

    notine i abiliti de lucru privind: tipurile de subprograme; structura i apelul subprogramelor: transferul parametrilor ntre apelator i apelat; lucrul cu parametri de tip simplu, masiv, subprogram; lucrul cu liste de parametri cu lungime variabil; lucrul cu subprograme recursive.

    2.1. Construirea i apelul subprogramelor

    Conform teoriei programrii, subprogramele snt clasificate n funcii, care returneaz un singur rezultat prin numele funciei i oricte prin parametri de ieire i proceduri, care returneaz oricte rezultate, toate prin intermediul parametrilor de ieire.

    Un program C este un ansamblu de funcii care realizeaz activiti bine definite. Exis-t o funcie, numit main(), care este apelat la lansarea n execuie a programului. Subpro-gramele C snt, n mod nativ, funcii. Pot fi construite subprograme care nu returneaz nici un rezultat prin numele lor, comportndu-se ca o procedur (conform definiiei din teorie). Sistemele C au colecii de biblioteci care conin funcii standard. Textul surs al unui program C poate fi partiionat n mai multe fiiere. Fiecare fiier const dintr-un set de funcii i declaraii globale. Fiierele care constituie partiia pot fi compilate i, eventual, testate sepa-rat, dar numai unul va conine funcia main().

    BogdanHighlight

  • * Material didactic pentru ID * 17

    Funciile C snt formate din antet i un corp. Antetul are forma:

    tip nume([lista-parametri-formali])

    unde: tip poate fi un tip simplu de dat. Dac lipsete, este considerat tipul implicit (int pen-

    tru unele compilatoare, void pentru altele); nume este un identificator care reprezint numele funciei; lista-parametrilor-formali conine parametrii formali sub forma:

    [tip1 identificator1[,tip2 identificator[,tip3 identificator ]]]

    Parametrii snt separai prin virgul. La limit, lista poate fi vid. Pentru fiecare para-

    metru trebuie specificat tipul, chiar dac mai muli parametri snt de acelai tip (nu este posi-bil definirea de liste de parametri cu acelai tip).

    Pentru funciile care nu ntorc o valoare prin numele lor, tipul funciei va fi void sau va fi omis.

    Corpul este o instruciune compus: conine declaraiile locale i instruciunile execu-tabile care implementeaz algoritmul. Corpul funciei se execut pn la executarea ultimei in-struciuni sau pn la executarea instruciunii return. Forma ei general este:

    return(expresie); sau return expresie; sau return;

    Prima i a doua form snt folosite n cazul funciilor care returneaz o valoarea prin

    numele lor. Prin executarea acestei instruciuni se evalueaz expresia, valoarea sa este atribui-t funciei i se ncheie execuia funciei. A treia form este folosit n cazul funciilor care nu returneaz nici o valoare prin numele lor (poate chiar s lipseasc). Dac este prezent, efectul ei este ncheierea execuiei funciei.

    Tipul expresiei din instruciunea return trebuie s coincid cu tipul funciei. Atenie: corect este tipul rezultatului ntors de funcie prin numele su. Vom vedea mai trziu c sintagma tipul funciei are un alt neles, mai complex. n limbajul C nu este admis imbricarea, adic definirea unui subprogram n cadrul al-

    tui subprogram i nu snt permise salturi cu instruciunea goto (instruciune de salt necondii-onat) n afara subprogramului curent.

    Declararea unui subprogram apare, n cadrul fiierului surs, naintea primului apel. Exist cazuri particulare n care, fie funciile se apeleaz unele pe altele (de exemplu, cazul recursivitii mutuale), fie definiia nu se afl n fiierul surs. Pentru a oferi compilatorului posibilitatea s efectueze verificarea validitii apelurilor, snt prevzute declaraii ale subpro-gramelor fr definirea corpului lor (declaraii anticipate). Aceste declaraii se numesc proto-tipuri i apar n afara oricrui corp de funcie. Sintaxa general este:

    tip nume ([lista-parametri-formali]); Prototipul este de fapt un antet de funcie dup care se scrie caracterul ; (punct i vir-gul). Numele parametrilor pot lipsi, fiind suficient specificarea tipurilor lor. Prototipul tre-buie inserat n program naintea primului apel al funciei. Domeniul de valabilitate a declara-iei unui subprogram este limitat la partea care urmeaz declaraiei din fiierul surs.

  • Algoritmi n programare 18

    Prototipurile funciilor standard se afl n fiiere header (cu extensia .h). Utilizarea unei funcii din bibliotec impune includerea fiierului asociat, cu directiva #include.

    Fiind funcii, subprogramele C se apeleaz ca operanzi n expresii, prin numele funci-ei urmate de lista parametrilor reali. Expresia care conine apelul poate la limit s conin un singur operand i chiar s fie o instruciune de tip expresie. n aceste cazuri valoarea returnat de funcie se pierde, nefiind folosit n nici un fel.

    Exemple 1. S se scrie o funcie care calculeaz cel mai mare divizor comun dintre dou nume-

    re ntregi nenule, utiliznd algoritmul lui Euclid i un apelator pentru testare. #include int cmmdc(int a, int b) /*definirea functiei cmmdc*/ { int r,d=a,i=b; do {r=d%i; d=i; i=r;} while(r0); return i; } void main() { int n1,n2; printf("Numerele pentru care se va calcula cmmdc:"); scanf("%d%d",&n1,&n2); if(n1&&n2) printf("\ncmmdc=%d",cmmdc(n1,n2)); else printf("Numerele nu snt nenule!"); }

    2. Acelai exemplu folosind un prototip pentru funcia cmmdc:

    #include int cmmdc(int, int); /* prototipul functiei cmmdc*/ void main() { int n1,n2; printf("Numerele pentru care se va calcula cmmdc:"); scanf("%d%d",&n1,&n2); if(n1&&n2) printf("\ncmmdc=%d",cmmdc(n1,n2)); else printf("Numerele nu snt nenule! "); } int cmmdc(int a, int b) /*definirea functiei cmmdc*/ { int r,d=a,i=b; do {r=d%i; d=i; i=r;} while(r0); return i; }

    Teste de autoevaluare 1. Care este diferena teoretic dintre un subprogram de tip funcie i un subprogram de tip procedur?

    2. Ce tipuri de subprograme pot fi scrise n limbajul C? 3. Ce este un prototip?

  • * Material didactic pentru ID * 19

    2.2. Transferul datelor ntre apelator i apelat

    n practica programrii, s-au conturat dou posibiliti de transfer al datelor ntre ape-lator i apelat: prin parametri i prin variabile globale. Prin utilizarea variabilelor globale nu se face un transfer propriu-zis, ci se folosesc n comun anumite zone de memorie. Aceast practic este nerecomandat. 2.2.1. Transferul prin parametri

    Principial, transferul parametrilor se poate face prin valoare sau prin adres. n limba-jul C este implementat numai transferul prin valoare (valoarea parametrului real este copiat n stiv iar subprogramul lucreaz numai cu aceast copie). Operaiile efectuate asupra unui parametru formal scalar (care nu este masiv) nu modific, la ieirea din subprogram, parame-trul real corespunztor. Dezvoltrile ulterioare (C++) au implementat i transferul prin adres.

    Transferul valorii este nsoit de eventuale conversii de tip realizate pe baza informai-ilor de care dispune compilatorul despre subprogram (tipurile parametrilor). Dac prototipul precede apelul subprogramului i nu exist o sublist variabil de parametri, conversiile se fac similar atribuirilor.

    Exemplu 3. tip_returnat nume(tip_parametru p); p este transferat prin valoare

    Folosind transferul prin valoare se pot transmite numai parametri de intrare n subpro-gram. Pentru a putea folosi parametri de ieire trebuie simulat transferul prin adres. n acest scop, se vor efectua explicit operaiile care se fac automat la transferul prin adres din alte limbaje: se transmite ca parametru adresa parametrului real iar n subprogram se lucreaz cu indirectare (pentru a accesa valoarea parametrului, se derefereniaz adresa primit).

    Exemplu 4. tip_returnat nume(tip_parametru *p); p este transferat prin valoare, fiind

    adresa parametrului real.

    Pentru parametrii de tip masiv, simularea transferului prin adres se face n mod im-plicit, datorit modului de construire a masivelor n C: numele masivului este un pointer. La apel, n stiv se va transfera adresa masivului iar referirea elementelor se face automat prin calcul de adrese (vezi capitolul Tipuri dinamice de date).

    Urmtoarele prototipuri snt echivalente: tip_returnat nume1(float v[], int n); tip_returnat nume2(float *v, int n);

    Exemple 5. S se calculeze produsul scalar dintre doi vectori. Rezultatul se ntoarce prin nume-

    le funciei: float ps(float x[], float y[], int n) { int i,prod=0; for(i=0;i

  • Algoritmi n programare 20

    n a doua variant de rezolvare, rezultatul se ntoarce prin parametru, simulnd transferul prin adres:

    void ps(float x[], float y[], int n, float *prod) { int i; *prod=0; for(i=0;i

  • * Material didactic pentru ID * 21

    Exemple 8. S se calculeze produsul dintre o matrice i un vector. #include float * prod(float a[][30], float v[],int m, int n) { float *p;int i,j; p=(float *)malloc(sizeof(float)*m); for(i=0;i

  • Algoritmi n programare 22

    Exemple 9. Fie un subprogram care calculeaz suma elementelor unui vector v de lungime n. void suma(float s, float v[], int n) { int i; for(s=0,i=0;i

  • * Material didactic pentru ID * 23

    Domeniile de valabilitate a referirilor variabilelor declarate snt urmtoarele: b poate fi referit doar n funcia z; c poate fi referit doar n funcia main; d poate fi referit doar n instruciunea compus r; a este global i poate fi referit de oriunde.

    Atenie: este impropriu spus transfer prin variabile globale, deoarece nu se realizeaz un transfer propriu-zis. De fapt o zon de memorie este accesat de mai multe entiti (subprograme), toate avnd posibilitatea utilizrii i modificrii valorii din acea zon.

    Datorit lipsei controlului asupra modificrilor, acest mod de transmitere a datelor nu este re-comandat. Se prefera utilizarea acestei metode doar atunci cnd este vorba de valori comune, general valabile ntr-o aplicaie i care se modific relativ rar (de exemplu calea ctre fiierul de date cu care se lucreaz).

    Teste de autoevaluare 5. Cum se realizeaz fizic transferul unui parametru prin valoare, respectiv prin adre-s? Care este efectul asupra proiectrii subprogramelor?

    2.3. Pointeri spre funcii

    n limbajul C, numele unei funcii este un pointer care indic adresa de memorie unde ncepe codul executabil al funciei. Aceasta permite transmiterea funciilor ca parametri n subprograme precum i lucrul cu tabele de funcii. n acest scop trebuie parcurse urmtoarele etape: a. Declararea unei variabile de tip procedural (pointer spre funcie):

    tip_rezultat (*nume_var)(lista_parametri_formali); unde nume_var este o variabil de tip procedural i are tipul pointer spre funcie cu parame-trii lista_parametri_formali i care returneaz o valoare de tipul tip_rezultat. Lui nume_var i se poate atribui ca valoare doar numele unei funcii de prototip corespunztor acestui tip:

    tip_rezultat nume_f(lista_parametrilor_formali); b. Descrierea funciei care utilizeaz parametrul procedural:

    void f(, tip_rezultat (*nume)(lista_parametrilor_formali), ) { tip_rezultat x; x=(*nume)(lista_parametrilor_actuali); }

    unde nume este parametrul formal de tip procedural. c. Apelul funciei cu parametri procedurali:

    tip_rezultat nume_functie(lista_parametrilor_formali) { } void main() { f(, nume_functie, ); }

  • Algoritmi n programare 24

    Exemplu 12. Fie o funcie care efectueaz o prelucrare asupra unui vector. Nu se cunoate apri-

    ori tipul prelucrrii, aceasta fiind descris de o alt funcie, primit ca parametru. Pot exista mai multe funcii care descriu prelucrri diferite asupra unui vector i oricare din ele poate fi transmis ca parametru.

    float suma(float *v, int n) { for(int i=0, float s=0; i

  • * Material didactic pentru ID * 25

    Exemplu 13. S se aproximeze soluia unei ecuaii de forma f(x)=0 prin metoda biseciei.

    #include #include #include /*prototipul functiei bisectie*/ void bisectie(float,float,float(*f)(float),float,long,int *,float *); /*prototipul functiei pentru care se aplica metoda bisectiei*/ float fct(float); /* functia principala*/ void main() { float a,b,eps,x; int cod; long n; float (*functie)(float); clrscr(); printf("Introduceti capetele intervalului:"); scanf("%f%f",&a,&b); printf("\nEroarea admisa:"); scanf("%f",&eps); printf("\nNumarul maxim de iteratii:"); scanf("%li",&n); functie=fct; bisectie(a,b,functie,eps,n,&cod,&x); if(!cod) printf("\nNu se poate calcula solutia aproximativa"); else printf("\n Solutia aproximativa este: %f",x); } /*descrierea functiei pentru care se aplica metoda bisectiei*/ float fct(float x) { return x*x*x-3*x+14; } /*functia ce implementeaza metoda bisectiei*/ void bisectie(float a,float b,float (*f)(float),float eps,long n, int *cod,float *x) { int gata=0; long c; for(c=0;(c

  • Algoritmi n programare 26

    dimensiunea vectorului de sortat i numrul de octei din reprezentarea tipului elemen-telor vectorului;

    pointerul la o funcie de comparare, cu argumente de tip void *, care s permit la apel att schimbarea de tip, ct i descrierea efectiv a relaiei de ordine. Deoarece tipul elementelor vectorului nu este cunoscut la momentul descrierii proce-

    durii de sortare, operaia de atribuire nu poate fi folosit, ea fiind nlocuit de o funcie de co-piere a unui numr prestabilit de octei, de la o adres surs la una destinaie. O astfel de func-ie exist n biblioteca mem.h, sintaxa ei fiind:

    void *memmove(void *destinaie, const void *surs, unsigned n)

    Pentru accesarea adresei elementului de rang i din vector se folosete formula (char *)v+i*nr_octeti. Fiierul surs care conine funcia de sortare descris anterior este urmtorul: //fisier exp_tip.cpp #include include void sort(void *v, int n, int dim, int (*compara)(const void * ,const void * )) { int i,j; void *aux; aux=malloc(dim); for(i=0;i

  • * Material didactic pentru ID * 27

    Exemplu de apel pentru un vector de cuvinte (iruri de caractere):

    #include #include #include #include "exp_tip.cpp" int compara(const void *a, const void *b) { if(strcmp((char *)a, (char *)b)>0)return 1; else return 0; } void main() { typedef char cuvant[10]; cuvant vect[20]; int n; clrscr(); printf("Dimensiunea vectorului de cuvinte:"); scanf("%d",&n); printf("\nCuvintele:"); for(int i=0;i

  • Algoritmi n programare 28

    va_end ncheie operaia de extragere a valorilor parametrilor i trebuie apelat nainte de

    revenirea din funcie. Prototipul funciei este:

    void va_end(va_list ptlist);

    Problema numrului de parametri i tipurilor lor este tratat de programator.

    Exemplu 15. S se calculeze cel mai mare divizor comun al unui numr oarecare de numere n-

    tregi. #include #include #include int cmmdc_var(int,...); // functie cu numar variabil de parametri int cmmdc(int, int); void main() { int x,y,z,w; clrscr(); scanf("%d%d%d%d",&x,&y,&z,&w); printf("\nCmmdc al primelor 3 numere:%d\n",cmmdc_var(3,x,y,z)); printf("\nCmmdc al tuturor numerelor:%d\n",cmmdc_var(4,x,y,z,w)); } int cmmdc(int x,int y) //cel mai mare divizor comun a doua numere { int d=x,i=y,r; do{ r=d%i; d=i;i=r; } while(r); return d; } int cmmdc_var(int nr,...) //cel mai mare divizor comun a nr numere { va_list ptlist; /*initializarea lui ptlist cu adresa de inceput a listei de parametri*/ va_start(ptlist,nr); //extragerea primului parametru, de tip int x=va_arg(ptlist,int); for(int i=1;i

  • * Material didactic pentru ID * 29

    #include #include #include void inter(double *,int,double *,int,double *); void inter_var(double *,int nr,...); void main() { int n1,n2,n3,n4; double x1[10],x2[10],x3[10],x4[10],z[50]; clrscr(); scanf("%d%d%d%d",&n1,&n2,&n3,&n4); for(int i=0;i

  • Algoritmi n programare 30

    Teste de autoevaluare 8. S se scrie o funcie cu numr variabil de parametri care calculeaz produsul unui ir de maxim n matrice. Funcia trebuie s aloce spaiu de memorie pentru masivul re-

    zultat i s trimit ctre apelator adresa acestui spaiu, mpreun cu dimensiunile masivului rezultat i un cod de eroare (nu orice ir de matrice se pot nmuli). Funcia primete ca para-metri numrul de matrice care particip la operaie, adresele i dimensiunile lor, in ordinea: adres matrice, nr. linii, nr. coloane, adres matrice, nr. linii, nr. coloane . 2.5. Calcul recursiv

    Recursivitatea este tehnica de programare n care un subprogram se autoapeleaz.

    Limbajul C face parte din clasa limbajelor de programare care admit scrierea de funcii recur-sive.

    n continuare snt prezentate cteva exemple simple de subprograme C prin intermedi-ul crora snt calculate recursiv valorile fgf,C,!n kn oo , unde k,n N i f, g funcii, :g,f R R. De asemenea, este ilustrat maniera n care snt efectuate apelurile recursive i trata-rea condiiilor de terminare.

    Exemplu 17. Calculul valorii n! pentru n dat poate fi efectuat pe baza formulei recursive

    ( )

    >==

    0n,!1nn0n,1

    !n .

    Fie fact(n) funcia C care calculeaz n!. Dac n 1, evaluarea lui fact(n) rezult prin multiplicarea cu n a valorii calculate de apelul fact(n-1), cu fact(0)=1. Cu alte cuvinte, apelul funciei fact(n) realizeaz calculul imediat dac n=0, altfel presupune un nou apel al acele-iai funcii pentru valoarea argumentului decrementat. Cazurile n care este posibil evalua-rea imediat se numesc condiii de terminare.

    n limbajul C, funcia fact este long fact(unsigned n) { if (!n) return 1; return n*fact(n-1); }

    Exemplu

    18. Utilizarea formulei ( )!kn!k!nC kn = pentru calculul combinrilor ( k,n N date)

    este ineficient i uneori imposibil deoarece n!, pentru n 13 nu poate fi reprezentat n calcu-lator ca dat de un tip ntreg, chiar dac numrul knC este relativ mic i poate fi reprezentat prin intermediul unui tip ntreg. Pe baza relaiei de recuren 1k 1n

    k1n

    kn CCC

    += , valoarea knC

    poate fi calculat astfel. Fie comb(n,k) funcia care calculeaz knC . Conform relaiei de recu-ren, dac n k1, atunci evaluarea corespunztoare apelului comb(n,k) revine la nsumarea rezultatelor obinute prin apelurile comb(n-1,k) i comb(n-1, k-1), unde comb(n,0)=1, n0. Dac evalurile comb(n-1,k) i comb(n-1, k-1) snt realizate n acelai mod, rezult c apelul comb(n,k) va determina o secven de apeluri ale aceleiai funcii pentru valori ale argumente-lor din ce n ce mai mici, pn cnd este ndeplinit una din condiiile terminale comb(n,0)=1, comb(k,k)=1.

  • * Material didactic pentru ID * 31

    Soluia recursiv a evalurii knC este: long comb(unsigned n, unsigned k) { if (k>n) return 0; if ((k==0)||(k=n)) return1; return comb(n-1,k)+comb(n-1,k-1); } Funciile C recursive pentru calculul knC,!n , unde k,n N realizeaz apeluri recursive

    directe. Schema unui apel recursiv poate fi descris astfel: se verific dac este ndeplinit cel puin una din condiiile terminale; dac este ndeplinit o condiie terminal, atunci calculul este ncheiat i controlul este returnat unitii apelante, n caz contrar este iniiat calculul pentru noile valori ale parametrilor, calcul care presupune unul sau mai multe apeluri recursive.

    Mecanismul prin care este efectuat apelul unui subprogram se bazeaz pe utilizarea

    stivei memoriei calculatorului. Fiecare apel determin introducerea n stiv a valorilor para-metrilor reali, a adresei de revenire i a variabilelor locale. La momentul execuiei, aceste in-formaii snt extrase cu eliminare din stiv, eliberndu-se spaiul ocupat.

    n cazul subprogramelor recursive, mecanismul funcioneaz astfel: este generat un numr de apeluri succesive cu ocuparea spaiului din stiv necesar efecturii apelurilor pn la ndeplinirea unei condiii de terminare; apelurile snt executate n ordinea invers celei n care au fost generate, iar operaia de inserare n stiv poate produce depirea spaiul de memorie rezervat.

    De exemplu, n cazul apelului fact(3), secvena de apeluri recursive este: fact(2),

    fact(1), fact(0). n continuare execuia determin fact(0)=1, fact(1)=1*fact(0)=1, fact(2)=2*fact(1)=2, fact(3)=3*fact(2)=6.

    Evoluia determinat de apelul fact(3) n stiv este ilustrat n figurile 2.1.a i 2.1.b, unde () reprezint adresa de revenire n punctul de unde a fost efectuat apelul fact(3).

    3

    Fact=3*Fact(2)

    2 Fact=2*Fact(1)

    3 Fact=3*Fact(2)

    (o)

    (o)

    2 Fact=2*Fact(1)

    3 Fact=3*Fact(2)

    1 Fact=1*Fact(0)

    2 Fact=2*Fact(1)

    3 Fact=3*Fact(2)

    1 Fact=1*Fact(0)

    0 Fact=1

    (o)

    (o)

    Fig. 2.1.a Evoluia n stiv pn la verificarea condiiei de terminare n=0

  • Algoritmi n programare 32

    2 Fact=2*Fact(1)

    3 Fact=3*Fact(2)

    1 Fact=1

    2 Fact=2

    3 Fact=3*Fact(2)

    3 Fact=6 (o)

    (o)

    Fig. 2.1.b Eliberarea stivei dup execuia de-terminat de condiia de terminare

    Apelurile recursive ale unui subprogram S1 pot fi i indirecte, n sensul c este efectu-at un apel al unui alt subprogram S2 i S2 iniiaz un apel al lui S1 (recursivitate mutual).

    Exemplu 19. De exemplu, s se calculeze valorie funciei h=fgf , unde f,g:RR snt funcii

    date. Pentru funciile f, g definite prin

    ( ) ( ) >+

    +=

    >

  • * Material didactic pentru ID * 33

    Exemplu 21. Calculul valorii funciei Ackermann.

    Funcia Ackermann este definit pentru argumentele m,n numere naturale prin

    ( ) ( )( )( )

    =

    =+=

    altfel,1n,ma,1ma0n,1,1ma

    0m,1nn,ma

    Funcia C Ackermann calculeaz valoarea funciei a pentru m, n parametri naturali dai. long Ackermann(unsigned m, unsigned n) { if (!m) return n+1; if (!n) return Ackermann(m-1,1); return Ackermann(m-1,Ackermann(m,n-1)); } Exemplu 22. Problema calculului celui mai mare divizor comun dintre dou numere naturale a

    i b poate fi rezolvat recursiv, conform definiiei urmtoare,

    ( )

    >>

    ==

    ab),ab,a(ba),b,ba(

    ba,ab,a

    Funcia C cmmdc(a,b) este long cmmdc(long a, long b) { if (a==b) return a; if (a>b) return cmmdc(a-b,b); return cmmdc(a,b-a); }

    Exemplu 23. Problema turnurilor din Hanoi ilustreaz foarte bine avantajele recursivitii. Pro-blema poate fi enunat astfel: fie trei tije a, b, c; pe tija a snt plasate n discuri de di-

    ametre diferite, n ordinea descresctoare a acestora (de jos n sus). Se cere ca cele n discuri de pe tija a s fie deplasate pe tija c astfel nct s fie ndeplinite condiiile:

    - la fiecare mutare este deplasat unul dintre discurile aflate pe poziia superioar pe una din tije;

    - oricare din discuri poate fi aezat numai pe un disc de diametru mai mare; - tija b poate fi folosit pentru deplasri intermediare.

    Notnd cu P(n,a,c) problema transferului celor n discuri de pe tija a pe tija c, pentru

    rezolvarea ei putem raiona n modul urmtor. Dac s-a rezolvat problema P(n-1,a,b), atunci discul de diametru maxim care se afl nc pe tija a este deplasat pe tija c i n continuare se rezolv problema P(n-1,b,c). Soluia recursiv este prezentat n funcia Hanoi.

  • Algoritmi n programare 34

    Exemplu: presupunnd c discurile snt numerotate n ordinea cresctoare a diametrelor cu etichetele 1, 2, 3, o soluie a problemei pentru n=3 poate fi descris astfel.

    Tija a Tija b Tija c Mutarea efectuat 1 2 3

    a c

    2 3

    1 a b 3 2 1 c b 3 1

    2 a c

    1 2

    3 b a 1 2 3 b c 1 2

    3 a c

    1 2 3

    #include #include void Hanoi(unsigned n,unsigned a, unsigned b,unsigned c) { if(n>0) { Hanoi(n-1,a,c,b); printf("Transfer disc de pe tija %u pe tija %u\n",a,b); Hanoi(n-1,c,b,a); } } void main() { unsigned n,a,b,c; clrscr(); printf("n=");scanf("%u",&n); Hanoi(n,1,2,3);getch(); }

    Exemplu 24. Sortarea cresctoare prin inserare

    Pentru sortarea cresctoare a unei secvene de numere reale se poate raiona astfel: dac P(n) este problema sortrii cresctoare a secvenei a1, a2, , an i P(n-1) este problema sortrii primelor n-1 componente, atunci soluia problemei P(n) rezult din soluia problemei P(n-1) prin inserarea lui an n soluia problemei P(n-1). Fiecare problem intermediar P(k),

    n,...,2k = este rezolvat aplicnd aceeai metod P(1) este o problem gata rezolvat (con-diie terminal).

    Funcia insera realizeaz inserarea valorii x n vectorul v n poziia corect. Funcia recursiv inssort realizeaz sortarea vectorului cu n componente prin inserie.

    void insera(float *v,int *n,float x) { for(int i=0;(iv[i]);i++); for(int j=*n;j>=i+1;j--)v[j]=v[j-1]; v[i]=x;(*n)++; } void inssort(float *v,int n) { if(n) { inssort(v,n-1);int m=n-1; insera(v,&m,v[n-1]); } }

  • * Material didactic pentru ID * 35

    Exemplu 25. Pot fi realizate desene prin compunerea ntr-o manier recursiv a unor figuri ge-

    ometrice primitiv (de baz). Compunerea const n repetarea primitivelor considerate i a re-zultatelor obinute prin rotirea lor ntr-un sens sau cellalt. Astfel, dac mulimea de primitive H0 const dintr-un punct i pentru compunere este considerat un segment de lungime h, atunci: H1 rezult din patru exemple (copii, realizri, instane, clone) de primitive din H0 unite prin segmente de lungime h; H2 rezult din 16 exemple din H0 unite prin 15 segmente de lun-gime h/2 .a.m.d. De asemenea, H2 se poate obine prin interconectarea a patru copii ale lui H1 rotite cu unghiuri drepte i prin interconectarea punctelor izolate prin segmente de aceeai lungime. Generaliznd, o curb Hn rezult din patru copii ale unei curbe Hn-1, punctele izolate fiind unite prin segmente de lungime hn=h/2n. Curbele rezultate se numesc curbele Hilbert Hi, i0.

    H1 H2 H3 Dac cele patru pri ale unei curbe Hilbert Hk snt notate A, B, C, D i se reprezint

    prin sgei rutinele care deseneaz segmentele care le interconecteaz, atunci rezult urmtoa-rele scheme recursive.

    BAAD:A

    BAAD:A

    ABBC:B

    DCCB:C

    CDDA:D

    Prin executarea urmtoarei surse C snt obinute curbele Hilbert H4 (exemplul a fost scris n mediul Borland C 3.11). #include #include #include #include const n=5; const h0=480; int i=0; int h; int x,y,x0,y0,gm; int gd=DETECT; void A(int); void B(int); void D(int); void C(int); void main() { clrscr(); initgraph(&gd,&gm,"D:\BC\BGI"); setbkcolor(0); setcolor(4); h=h0;y0=x0=h/2; do{ i++;h/=2; x0+=h/2;y0+=h/2;

    x=x0;y=y0;moveto(x,y); A(i); } while(i0) { D(i-1);x-=h;lineto(x,y); A(i-1);y-=h;lineto(x,y); A(i-1);x+=h;lineto(x,y); B(i-1); } } void B(int i) { if (i>0) { C(i-1);y+=h;lineto(x,y); B(i-1);x+=h;lineto(x,y); B(i-1);y-=h;lineto(x,y); A(i-1); } }

  • Algoritmi n programare 36

    void C(int i) { if (i>0) { B(i-1);x+=h;lineto(x,y); C(i-1);y+=h;lineto(x,y); C(i-1);x-=h;lineto(x,y); D(i-1); } } void D(int i) { if (i>0) { A(i-1);y-=h;lineto(x,y); D(i-1);x-=h;lineto(x,y); D(i-1);y+=h;lineto(x,y); C(i-1); } }

    Curba Hilbert obinut este:

    Exemplu 26. n cazul curbelor Hilbert, toate unghiurile determinate de segmentele care unesc

    punctele snt de msur 900. Dac se consider ca valori pentru msurile unghiurilor determi-nate de aceste segmente 450, 900, 1350, rezult curbele Sierpinski Sn, n1.

    Curba lui Sierpinski pentru n=2 este urmtoarea:

    Recursia pentru obinerea curbelor Sierpinski poate fi descris astfel. S: A B C D A: A B D A B: B C A B C: C D B C D: D A C D

    unde sgeile duble indic segmente de lun-gime 2h.

    Urmtorul program deseneaz curbele Sierpinski S4 (exemplul a fost scris n mediul Borland C 3.11) #include #include #include #include const n=4; const h0=412; int i=0; int h; int x,y,x0,y0,gm; int gd=DETECT; void A(int); void B(int); void D(int); void C(int); void main() { clrscr(); initgraph(&gd,&gm,"d:\bc\bgi");

    setbkcolor(15); setcolor(8); h=h0/4; x0=2*h; y0=3*h; do{ i++; x0-=h;h/=2;y0+=h; x=x0;y=y0; moveto(x,y); A(i);x+=h;y-=h;lineto(x,y); B(i);x-=h;y-=h;lineto(x,y); C(i);x-=h;y+=h;lineto(x,y); D(i);x+=h;y+=h;lineto(x,y);} while(i!=n); getch(); closegraph(); } void A(int i) { if (i>0) { A(i-1);x+=h;y-=h;

  • * Material didactic pentru ID * 37

    lineto(x,y); B(i-1);x+=2*h; lineto(x,y); D(i-1);x+=h;y+=h; lineto(x,y); A(i-1); } } void B(int i) { if (i>0) { B(i-1);x-=h;y-=h; lineto(x,y);C(i-1); y-=2*h; lineto(x,y); A(i-1);x+=h;y-=h; lineto(x,y); B(i-1); } } void C(int i)

    { if (i>0) { C(i-1);x-=h;y+=h; lineto(x,y); D(i-1);x-=2*h; lineto(x,y); B(i-1);x-=h;y-=h; lineto(x,y); C(i-1); } } void D(int i) { if (i>0) { D(i-1);x+=h;y+=h; lineto(x,y); A(i-1);y+=2*h; lineto(x,y); C(i-1);x-=h;y+=h; lineto(x,y); D(i-1); } }

    Rezultatul execuiei programului este prezentat n urmtoarea figur.

    Teste de autoevaluare 9. S se scrie un subprogram recursiv pentru calcularea sumei elementelor unui vec-tor.

    10. S se scrie un subprogram recursiv pentru determinarea elementului minim dintr-un vec-tor. 11. S se scrie un subprogram recursiv pentru determinarea elementului minim i a elementu-lui maxim dintr-un vector. 12. S se scrie un subprogram recursiv pentru determinarea elementelor irului lui Fibonacci. 13. Scriei un subprogram pentru rezolvarea problemei cutrii binare n vectori sortai. Fie v un vector de numere reale sortat cresctor i k un numr real dat. S se identifice (dac exist) o valoare poz, astfel nct v[poz]=k.

    Rspunsuri i comentarii la testele de autoevaluare 1. Pe lng rezultatele (oricte) care pot fi ntoarse prin parametrii, subprogramele de tip funcie permit i ntoarcerea unui rezultat de tip simplu prin numele lor, ceea ce

    ofere posibilitatea realizrii apelului ca operand ntr-o expresie, care va folosi rezultatul apelu-lui pentru evaluare.

  • Algoritmi n programare 38

    2. n limbajul C se pot scrie numai subprograme de tip funcie. 3.

    #include #include #include float** inmultire(float **a,float **b,int n) { int i,j,k; float **c; c=(float **)malloc(n*sizeof(float *)); for(i=0;i

  • * Material didactic pentru ID * 39

    printf("Elementele vectorului\n"); float v[100]; for(unsigned i=0;ils) return -1; int mij=(li+ls)/2; if(v[mij]==k) return mij; if(v[mij]>k) return cauta_binar(v,li,mij-1,k); return cauta_binar(v,mij+1,ls,k);

    }

    Rezumat n cadrul acestei uniti de nvare au fost studiate urmtoarele aspecte ale program-rii calculatoarelor cu privire la lucrul cu subprograme:

    cunotine teoretice despre subprograme, n general i n limbajul C; construcia i apelul subprogramelor n limbajul C; transferul datelor ntre apelator i apelat, prin variabile globale i prin parametri (prin

    valoare i prin simularea transferului prin adres); pointeri la funcii i trimiterea funciilor ca parametri ctre alte funcii; funcii cu numr variabil de parametri; subbrograme recursive.

    Dup ncheierea studierii acestei uniti de nvare, studenii au cunotinele i abilit-ile necesare lucrului cu subprograme n vederea rezolvrii problemelor complexe de progra-mare prin rezolvarea separat a subproblemelor componente.

    Bibliografia unitii de nvare

    1. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu, M. Mircea - Programarea calculatoarelor. Algoritmi n programare, Ed. ASE Bucureti, 2007 2. I. Gh. Roca, B. Ghilic-Micu, C. Cocianu, M. Stoica, C. Uscatu - Programarea calculatoa-relor. tiina nvrii unui limbaj de programare. Teorie i aplicaii, Ed. ASE Bucureti, 2003 3. Liviu Negrescu - Limbajele C i C++ pentru nceptori, vol. I, II, Ed. Microinformatica, Cluj-Napoca, 1994 4. I.Gh. Roca & colectiv - Bazele elaborrii programelor. Exerciii rezolvate i propuse, Ed. ASE Bucureti, 1998 5. A. Iorgulescu - Metode numerice i programe Pascal, Ed. Inforec, Bucureti, 1996 (para-grafele 2.2.1, 2.2.2, 2.2.3, 4.2.1, 4.2.2)

  • Algoritmi n programare 40

    3. Articolul i fiierul Cuprins Obiectivele unitii de nvare ............................................................................................. 40 3.1. Articol: caracteristici generale i mod de declarare ............................................... 40 3.2. Referirea articolului i a elementelor componente.................................................. 42 3.3. Articole cu structuri complexe .................................................................................. 45 3.4. Constante de tip articol.............................................................................................. 46 3.5. Fiierul i articolul...................................................................................................... 47 3.6. Metode de organizare a fiierelor i tipuri de acces................................................ 48 3.7. Structura sistemului de fiiere sub MS-DOS/Windows.......................................... 50 3.8. Operaii de prelucrare a fiierelor............................................................................ 52

    3.8.1. Nivelul inferior de prelucrare a fiierelor ........................................................ 53 3.8.2. Nivelul superior de prelucrare a fiierelor....................................................... 56

    Rspunsuri i comentarii la testele de autoevaluare ........................................................... 63 Rezumat................................................................................................................................... 63 Bibliografia unitii de nvare............................................................................................ 63 Obiectivele unitii de nvare

    Dup studierea acestei uniti de nvare, studenii vor avea cunotine teoretice i abiliti practice necesare pentru lucrul cu structuri de date interne eterogene i cu structuri de date externe (fiiere de date). Concret, se vor asimila cunotine i abili-

    ti de lucru privind: tipul de dat articol; tipurile de fiiere de date; metode de organizare a fiierelor i tipuri de acces la datele coninute; utilizarea articolelor interne pentru prelucrarea fiierelor de date; operaii generale de prelucrare a fiierelor de date.

    3.1. Articol: caracteristici generale i mod de declarare

    Articolul este o structur de date eterogen, cu acces direct la elementele sale, ntre ca-

    re exist o relaie de ordine ierarhic. Articolul poate fi reprezentat sub form de arbore, ale crui noduri snt asociate com-

    ponentelor structurii. Componentele de pe ultimul nivel snt scalare i se numesc date elemen-tare sau cmpuri. Datele de pe celelalte niveluri, denumite date de grup, se constituie prin agregarea datelor de pe nivelurile inferioare. Data de grup de cel mai nalt nivel (rdcina ar-borelui) corespunde articolului n ansamblu. Conceptual, datele de grup de pe diverse niveluri au aceleai proprieti ca i articolul, ceea ce permite ca aceast structur s fie construit re-cursiv, prin descompunerea n structuri cu aceleai proprieti (figura 4.1).

  • * Material didactic pentru ID * 41

    Declararea mpreun a tipului articol i a variabilelor de acest tip se realizeaz con-form sintaxei:

    struct tip_articol{lista_cimpuri} var1, var2, , varn; unde tip_articol este identificatorul asociat tipului articol, iar var1, var2,, varn snt identifi-catorii asociai variabilelor de tipul articol declarat.

    Unele elemente ale declaraiei pot lipsi (dar nu toate deodat). Dac lipsesc elementele var1, var2,, varn, atunci tip_articol trebuie s fie prezent, fiind numai o declarare explicit de tip nou, utilizabil ulterior la alte declarri. Dac lipsete tip_articol, atunci trebuie s fie prezent lista de variabile (nevid), caz n care este vorba de o declarare de variabile de tip ar-ticol, fr ns a declara i un tip utilizator nou. n continuare, tip_articol este un tip nou de date, iar var1, var2,, varn snt variabile de tipul tip_articol. Variabilele pot fi declarate i ca masive, ale cror elemente snt de tip articol: var1[dim1][dim2][dimn].

    DATA

    ZI LUNA AN

    dat de grup (articol)

    date elementare

    NUME ADRESA DATA NATERII

    PERSOANA

    dat de grup (articol)

    dat de grup (articol)

    ZI LUNA AN date elementare

    b)

    a)

    Fig. 3.1. Exemple de structuri de articole

    O variabil de tip articol poate fi declarat i ulterior definirii tipului: struct tip_articol var1; Descrierea constituie o definire implicit de un nou tip de dat. Este posibil definirea

    explicit a unui nou tip de dat, adugnd cuvntul rezervat typedef n faa declarrii (n acest caz nu mai pot fi declarate simultan i variabile). Lista_cimpuri este o niruire de declaraii de cmpuri separate prin punct i virgul, asemntoare declaraiilor de variabile, de forma tip_cimp nume_cimp. Cmpurile unei struc-turi pot fi variabile simple, masive sau alte articole. Lista cmpurilor nu poate fi vid.

    Exemplu 1. Definirea tipului de dat numr complex, a unei variabile simple i a unui masiv

    unidimensional cu elemente de acest tip se poate face n oricare din urmtoarele variante (pentru un numr complex se vor reine partea real i partea imaginar): a) struct COMPLEX{float r,i;}a,b[100]; b) struct COMPLEX{float r,i;};

    struct COMPLEX a,b[100]; c) struct COMPLEX{float r,i;};

    COMPLEX a,b[100]; d) struct {float r,i;}COMPLEX;

    COMPLEX a,b[100]; e) typedef struct {float r,i;} COMPLEX;

    COMPLEX a,b[100];

  • Algoritmi n programare 42

    f) typedef struct COMPLEX{float r,i;}; struct COMPLEX a,b[100];

    g) typedef struct COMPLEX{float r,i;}; COMPLEX a,b[100];

    Din punct de vedere practic, utilizarea tipului articol este strns legat de prelucrarea fiierelor. n lucrul cu variabilele de tip articol se recomand declararea identificatorului de tip. n acest mod, identificatorul de tip articol poate fi folosit n definirea mai multor variabile. n procesul de descriere a unui articol, arborele se parcurge n preordine (de la rdcin spre extremiti i de la stnga la dreapta).

    Exemplu 2. Pentru exemplele din figura 3.1, declararea poate fi realizat prin definire recursiv,

    astfel: struct tip_data { unsigned zi; char luna[3]; int an; };

    struct persoana { char nume[30]; char adresa[50]; struct tip_data data_nasterii; } angajat;

    Dac nu ar fi existat declaraia tipului articol tip_data, atunci tipul persoana putea fi scris astfel:

    struct persoana { char nume[30]; char adresa[50]; struct { unsigned zi; char luna[3]; int an; } data_nasterii; } angajat;

    Variabilele de tip articol se reprezint intern ca succesiuni de cmpuri elementare, cu

    reprezentarea intern i lungimea fizic specifice tipurilor lor. Lungimea zonei de memorie rezervat pentru variabila de tip articol rezult din nsumarea lungimilor cmpurilor. Aceasta nu poate depi 65520 octei (ca orice variabil de tip structurat). Pentru structura unui articol i dovedete utilitatea operatorul sizeof, care asigur determinarea lungimii zonei de me-morie asociate unei variabile sau unui tip de date.

    Exemplu 3. Considernd declaraiile anterioare, expresia sizeof(data_nasterii) are valoarea 8,

    iar sizeof(angajat) are valoarea 90.

    Din punct de vedere fizic, identificatorii cmpurilor din descrierea articolului reprezin-t deplasri fa de nceputul acestuia. Adresa fizic a unui cmp rezult din nsumarea adresei articolului cu deplasarea sa. Structura arborescent a articolelor poate fi exprimat sugestiv i prin machete, care evideniaz componentele, natura, lungimea declarat i lungimea fizic ale acestora (figurile 3.2 i 3.3). 3.2. Referirea articolului i a elementelor componente

    Datele de tip articol pot fi referite n dou moduri: global sau pe componente. Referi-rea global este permis numai n operaia de atribuire, cu condiia ca ambele variabile (surs i destinaie) s fie articole de acelai tip.

  • * Material didactic pentru ID * 43

    Referirea pe componente (prin numele lor) este o reflectare a faptului c articolul este o structur cu acces direct. Referirea unor componente de tip articol din structura altui articol este posibil numai n operaia de atribuire, n condiiile precizate anterior la referirea global. n cele ce urmeaz se are n vedere numai referirea componentelor de tip dat elementar, si-tuate pe ultimul nivel al structurii.

    Referirea cmpurilor unei structuri se face prin calificare, folosind operatorul . (punct). n referirea prin calificare, asigurarea identificrii unice a cmpurilor se realizeaz prin asocie-rea numelui acestora cu numele articolului care le conine. Construcia rmne la aceast for-m n cazul n care structura are numai dou niveluri: articolul i cmpurile elementare ale acestuia.

    Exemplu 4. Folosind tipul COMPLEX definit anterior, avem: a.r , a.i - se refer partea real, respectiv imaginar a variabilei a b[10].r - se refer partea real a celui de-al 11-lea element al vectorului b

    #include main() { struct articol {char nume[40]; char adresa[30]; int an, luna, zi;} struct articol pers; strcpy(pers.nume, "Popescu Ion"); strcpy(pers.adresa, "Bucuresti, Pta. Romana 6"); pers.an=1979; pers.luna=3; pers.zi=15; }

    n articolele cu structur recursiv se realizeaz calificarea progresiv cu articolele de pe nivelurile superioare, primul calificator fiind numele articolului rdcin. n lanul de cali-ficri, numele articolului rdcin este nume de variabil, celelalte fiind nume de cmpuri ale articolului. Dac anumite componente snt structuri de date de alte tipuri (de exemplu masive sau iruri de caractere), n referirea elementelor lor se aplic, pe lng calificare, regulile spe-cifice acestor structuri.

    Exemplu 5. Referirea prin calificare a cmpurilor articolului angajat de tipul persoana (vezi

    exemplele anterioare) se realizeaz astfel: angajat.nume; angajat.adresa; angajat.data_nasterii.zi; angajat.data_nasterii.luna; angajat.data_nasterii.an

    n aceste referiri, angajat este identificatorul variabilei articol, celelalte elemente snt identifi-catori de cmpuri. Construciile angajat.nume i angajat.adresa corespund referirii globale a cmpurilor respective, care snt iruri de caractere. Pentru a referi, de exemplu, primul caracter din ir, se scrie: angajat.nume[0].

    Exemplu 6. Se presupune un articol cu structura din figura 3.2.

    Vnzri lunare Cod Magazin Luna 1 Luna 2 Luna 12

    ntreg real Real real 2 4 4 4

    Fig. 3.2. Structura de articol pentru exemplul 6

  • Algoritmi n programare 44

    Articolul se declar astfel: struct magazin { int cod_magazin; float vanzari_lunare[12]; } articol;

    Articolul are 50 de octei, iar referirea cmpurilor se realizeaz astfel: articol.cod_magazin articol.vanzari_lunare[i], cu i=0,1,,11.

    Exemplu 7. Se presupune un articol cu structura din figura 3.3.

    Materia prim 1 ... Materia prim 30 Cod

    produs Numr materii prime

    Cod Norma de consum

    ... Cod Norma de consum

    ntreg ntreg ntreg real ... ntreg real 2 1 2 4 ... 2 4

    Fig. 3.3. Structura de articol pentru exemplul 7 Cu toate c numrul de materii prime utilizate poate fi variabil de la un produs la altul, n des-crierea articolului se alege valoarea maxim a acestuia:

    struct a { int cod_mat; float norma; }; struct produs { int cod_produs; unsigned char nr_mat; struct a materii_prime[30]; } articol ;

    Referirea cmpurilor se realizeaz astfel:

    articol.cod_produs; articol.nr_mat; articol.materii_prime[i].cod_mat; articol.materii_prime[i].norma;

    Constantele de tip articol snt cu tip i pstreaz caracteristicile acestora. n momentul

    compilrii se rezerv zone de memorie pentru acestea, iar cmpurile articolelor snt iniializate cu valorile precizate de utilizator. Declararea constantelor presupune definirea anterioar a ti-pului articol. Valoarea iniial trebuie s fie de acelai tip cu cmpul cruia i corespunde. Cnd arti-colul conine la rndul su alt articol, identificarea cmpului care se iniializeaz se face pe ni-veluri, folosind perechi corespunztoare de acolade.

    Exemple 8. #include void main() { //exemplul 1 struct persoana { char nume[40]; char adresa[30]; struct { int zi, luna, an;} datan; }; //exemplul 2 struct magazin { int cod_magazin; float vanzari_lunare[12]; };

  • * Material didactic pentru ID * 45

    //exemplul 3 struct a { int cod_mat; float norma;}; struct produs { int cod_produs; unsigned char nr_mat; struct a materii_prime[30]; }; //Initializarea articolului din exemplul 1: struct persoana p={"Popescu Ion", "Bucuresti, Magheru 14", 2, 4, 1960}; //sau cu evidentierea structurii data nasterii: struct persoana p1={"Popescu Ion", "Bucuresti, Magheru 14", {2, 4, 1960}}; printf("\n%i",p1.datan.an); //Initializarea articolului din exemplul 2: struct magazin gigel_srl={200, 1,2,3,4,5,6,7,8,9,10,11,12}; //sau cu evidentierea structurii de masiv: struct magazin gigel_srl1={200, {1,2,3,4,5,6,7,8,9,10,11,12}}; printf("\n%6.2f",gigel_srl1.vanzari_lunare[10]); //Initializarea articolului din exemplul 3 (doar primele 4 materii //prime, restul de 26 vor fi initializate automat cu valori nule: struct produs z={243,5,{{2420,25.4},{3251,70.21},{1421,8.4},{51,7.2}}}; printf("\n%6.2f",z.materii_prime[2].norma); } Teste de autoevaluare 1. Clasificai tipul de date articol, conform clasificrii tipurilor de date.

    3.3. Articole cu structuri complexe

    n activitatea de programare pot fi ntlnite aplicaii care reclam utilizarea articolelor cu structur variabil. La iniializarea cmpurilor unui astfel de articol, constanta de tip articol se asociaz unei singure structuri, deoarece zona de memorie rezervat pentru articol este uni-c. Pentru acest tip de articol, limbajul pune la dispoziia utilizatorilor tipul predefinit reuniu-ne (union), care se comport ca i tipul struct cu o singur diferen: la un moment dat al exe-cuiei programului, n zona de memorie rezervat articolului nu este memorat dect unul dintre cmpurile acestuia.

    Declararea tipului reuniune se realizeaz astfel:

    union nume_tip { tip_cimp1 cimp1; tip_cimp2 cimp2; ................ tip_cimpn cimpn;};

    Lungimea zonei de memorie rezervate pentru o variabil de tip reuniune va fi egal cu maximul dintre lungimile cmpurilor componente. Gestiunea coninutului respectivei zone de memorie va trebui realizat de ctre programator.

    Exemplu 9. Se presupune un articol cu structura din figura 3.4.

    Forma de nvmnt zi id

    Nume Data naterii An de studiu

    bursa valoare loc de munc data angajrii char[40] zi luna an int char float char[30] zi lun an

    Fig. 3.4. Articol cu structur variabil

  • Algoritmi n programare 46

    Declararea i iniializarea cmpurilor unui student la zi pentru structura articolului din figura 3.4 se realizeaz astfel:

    #include void main() { //Declararea articolului cu structura variabila: struct articol { char nume[40]; struct { int zi, luna, an;} datan; int an_st; char forma_inv; union { struct {char bursa; float valoare;} zi; struct {char loc_m[30]; struct {int zi, luna, an;} data_ang; } id; } parte_vb; }; //Initializarea cimpurilor unui student la zi: struct articol a={"Popescu Felix",{4,1,1974} ,1,'Z',{'D',250.5}}; printf("\nData nasterii: %i.%i.%i, Forma de inv.: %c, Val. bursa: %6.2f", a.datan.zi, a.datan.luna, a.datan.an, a.forma_inv, a.parte_vb.zi.valoare); }

    Din punct de vedere fizic, existena prii variabile ntr-un articol genereaz, la compi-

    lare, deplasri egale fa de nceputul articolului pentru toate variantele de descriere. Astfel, pentru descrierea din exemplul de mai sus se genereaz deplasarea 49 fa de nceputul artico-lului, att pentru cmpul bursa, ct i pentru loc_m.

    Teste de autoevaluare 2. Descriei n limbajul C tipul de dat vehicul corespunztor urmtoarei reprezentri tabelare. Alegei tipurile i dimensiunile potrivite pentru fiecare cmp.

    propulsie

    uman animal mecanic mas vitez maxim lungime lime nr. lo-curi nr. roi tip animal

    nr. animale

    tip com-bustibil cilindree putere

    consum (l/100km)

    3.4. Constante de tip articol Constantele de tip articol pot fi constante cu tip (variabile iniializate la compilare) i constante obiect, pentru care n momentul compilrii se rezerv zone de memorie, iar cmpurile articolelor snt iniializate cu valorile precizate de utilizator.

    Valoarea iniial trebuie s fie de acelai tip cu cmpul cruia i corespunde. Cnd arti-colul conine la rndul su alt articol, identificarea cmpului care se iniializeaz se face pe ni-veluri, folosind perechi corespunztoare de acolade. Constantele cu tip joac rol de variabile care se iniializeaz cu o valoare n faza de compilare, ele putnd s-i modifice valoarea pe parcursul execuiei programului.

    tip nume_const = {lista_valori};

    Constantele obiect snt variabile iniializate la declarare, pentru care se rezerv me-morie, dar coninutul lor nu poate fi modificat pe parcursul programului.

    const tip nume_const = {lista_valori};

  • * Material didactic pentru ID * 47

    Exemplu 10. Constant cu tip.

    #include void main() { struct persoana { char nume[40]; char adresa[30]; struct { int zi, luna, an;} datan; }; persoana pers={"Popescu Ion", "Bucuresti; Magheru 14", {2, 4, 1960}}; //constanta cu tip pers.datan.zi=4; }

    Exemplu 11. Constant obiect.

    #include void main() { struct persoana { char nume[40]; char adresa[30]; struct {int zi, luna, an;} datan; }; const persoana pers={"Popescu Ion", "Bucuresti; Magheru 14", {2, 4, 1960}}; //constanta obiect // pers.datan.zi=4; genereaza eroare la compilare } Teste de autoevaluare 3. Iniializai constante cu tip i constante obiect de tipul vehicul, pe care l-ai definit la tema de autoevaluare nr. 2.

    3.5. Fiierul i articolul Prelucrarea automat a datelor presupune un sistem de organizare a acestora dup me-tode i procedee specifice. Organizarea datelor este un proces complex care include identifica-rea, clasificarea i descrierea proprietilor acestora, gruparea lor n colecii, reprezentarea pe purttori tehnici, definirea i realizarea procedurilor de prelucrare etc.

    Deoarece datele se memoreaz, de obicei, pe purttori tehnici de informaii, dar se pre-lucreaz numai cnd snt prezente n memoria intern, acestea trebuie organizate att extern ct i intern. n organizarea extern a datelor se identific dou niveluri de abordare, dup cum se are n vedere acest proces din perspectiva utilizatorului sau a purttorilor fizici externi pe care se nregistreaz datele. Cele dou niveluri de abordare, numite logic, respectiv fizic, precum i realizarea trecerii de la unul la cellalt, n condiiile specifice diverselor sisteme de calcul, se bazeaz pe o serie de concepte, cum ar fi: fiierul i articolul, purttorul tehnic de date, meto-da de organizare i modul de acces, operaiile de prelucrare etc. Fiierul reprezint termenul generic care desemneaz structurile de date externe. El es-te o mulime (colecie) de date omogene din punct de vedere al semnificaiei i al cerinelor de prelucrare. n purttorul extern, fiierul are, pe lng partea de date, i alte informaii de identi-ficare (etichete).

  • Algoritmi n programare 48

    Privit din punctul de vedere al prelucrrii, un fiier este o colecie ordonat de date, numite articole. Articolul este constituit dintr-o mulime ordonat de valori ale unor caracte-ristici ce aparin, uzual, unei singure entiti (obiect, fenomen, proces etc.) din domeniul de activitate abordat. De exemplu, ntr-un fiier care conine datele personale ale salariailor dintr-o unitate economic, un articol grupeaz valorile caracteristicilor unei singure persoane.

    Componentele articolului destinate diverselor caracteristici snt denumite cmpuri de date. Depinznd de natura, ordinul de mrime i forma de reprezentare extern a valorilor aso-ciate, fiecare cmp de date are o lungime, exprimat uzual n octei. Lungimea unui articol es-te dat de suma lungimilor cmpurilor care l compun. Dup cum toate articolele dintr-un fii-er au sau nu aceeai lungime, se face distincie ntre fiierele cu articole de lungime fix sau variabil. Modul de implementare fizic a celor dou tipuri de fiiere difer de la un sistem la altul i chiar de la un limbaj la altul.

    Pe purttorul fizic extern, partea de date a fiierului se prezint ca o succesiune de oc-tei cu un coninut binar fr semnificaie informaional. n momentul prelucrrii, prin des-crieri i operaii adecvate, din succesiunea memorat extern se decupeaz" entiti (articole, blocuri, linii sau cmpuri) cu structuri corespunztoare prelucrrii. Tipul entitii care se de-cupeaz" depinde de tipul fiierului.

    3.6. Metode de organizare a fiierelor i tipuri de acces Principiile i regulile dup care se memoreaz articolele unui fiier pe purttorul ex-tern, cu asigurarea proteciei i regsirii acestora, constituie metoda de organizare. n evoluia organizrii datelor externe s-au cristalizat mai multe metode, dintre care, cele mai uzuale snt secvenial, relativ i indexat. Principala difereniere ntre metodele de organizare o repre-zint tipurile de acces admise. Tipul de acces reprezint modalitatea de regsire (localizare) a articolelor din fiier. Noiunea de acces trebuie aplicat att pentru operaia de scriere, ct i pentru cea de citire a datelor. Poziia din/n care se face citirea/scrierea n cadrul fiierului este indicat de un pointer. Accesul la datele nregistrate pe un purttor tehnic poate fi secvenial sau direct, n funcie de modul n care se stabilete pointerul.

    Accesul secvenial este posibil la toi purttorii tehnici de date i presupune nscrierea nregistrrilor n ordinea furnizrii lor sau regsirea n ordinea n care au fost nscrise n suport (figura 3.5).

    Traversare

    A1 A2 ... Ak-1 Ak ... An EOF

    P(Ak)=f (P(Ak-1))

    Fig. 3.5. Principiul de realizare a accesului secvenial la articole

    Pointerul de fiier avanseaz, n scriere i citire, de la o entitate (articol, bloc, linie sau cmp) la alta. Dac pointerul se exprim prin deplasare fa de nceputul fiierului, atunci, ma-tematic, acest lucru se poate exprima astfel: P(A1) = 0; P(Ak) = f(P(Ak-1)) = P(Ak-1)+lartk-1; pentru k=2,n; unde Ak este articolul k i lartk este lungimea articolului k.

  • * Material didactic pentru ID * 49

    O problem important care se pune la consultarea (citirea) n acces secvenial este controlul ajungerii la sfritul fiierului. Dup citirea ultimei entiti (articol, bloc, linie sau cmp), pointerul indic marcatorul de sfrit de fiier - EOF (figura 3.6).

    Poziia pointerului dup citirea ultimului articol

    A1 A2 ... Ak-1 Ak ... An EOF

    Fig. 3.6. Pointerul dup citirea ultimului articol din fiier

    n limbajele de programare se regsesc dou modaliti de sesizare a sfritului de fiier: a) Sesizarea sfritului de fiier n cadrul operaiei de citire (limbajele FORTRAN, CO-BOL, C). Sfritul este sesizat la citirea marcatorului de sfrit de fiier. Situaia din figura 5.2 nu este considerat sfrit de fiier. Abia la urmtoarea citire se ntmpl acest lucru (pointerul de fiier avanseaz dup marcatorul de sfrit de fiier). b) Sesizarea sfritului de fiier independent de operaia de citire (limbajele BASIC, PASCAL). n acest caz, dac pointerul este pe marcatorul de sfrit de fiier (dup ultimul ar-ticol, bloc, linie, cmp, ca n figura 5.2) se consider sfrit de fiier. Urmtoarea citire produ-ce eroare de intrare/ieire (I/E). Proiectarea algoritmilor de prelucrare a fiierelor este determinat de modalitatea n care se sesizeaz sfritul de fiier.

    Accesul direct este posibil numai la fiierele care au o anumit organizare, au ca enti-tate de transfer articolul sau blocul i snt memorate pe discuri magnetice. Accesul direct se bazeaz pe existena unui algoritm implementat n sistem care asigur regsirea (localizarea) articolelor n funcie de o informaie de regsire. Valoarea pointerului este determinat direct, fr s depind de valoarea sa anterioar: P(Ak)=f(irk), unde Ak este articolul k, iar irk este o informaie de regsire a articolului k. n funcie de algoritmul i informaia de regsire, exist dou tipuri de acces direct: dup cheie i dup numrul relativ al articolului. n cazul accesului direct dup cheie, articolul este regsit prin aplicarea unui algoritm asupra unei informaii de identificare de tip cheie: P(Ak)=f(cheiek). n cazul accesului direct dup numrul relativ - care se mai numete, simplu, acces relativ - (figura 3.7), articolul este localizat n fiier prin numrul su, stabilit, n cadrul fiierului, de la valoarea zero: P*(Ak)=(k-1); P(Ak)=P*(Ak)lart. P*(Ak) reprezint poziia exprimat n numr relativ, iar P(Ak) reprezint poziia exprimat prin deplasare, n octei, fa de nceputul fiierului (la unele sisteme numrul relativ este stabilit de la unu: P*(Ak)=k). La scriere, articolul Ak (numrul relativ k-1) se memoreaz pe poziia sa, celelalte k-1 articole anterioare putnd s nu existe (pe suport exist ns rezervat loc pentru ele). La citire, articolul Ak (cu numrul relativ k-1, kn) este localizat direct i coninutul lui se transfer n memoria intern.

    Fiierele organizate secvenial, cu articole de lungime variabil, admit numai accesul

    secvenial. Fiierele organizate secvenial, cu articole sau blocuri de lungime fix, admit att accesul secvenial ct i pe cel relativ. Acest lucru deriv din faptul c accesul relativ este rea-lizat de sistem printr-o deplasare secvenial fa de nceputul acestuia, deplasare care este egal cu valoarea expresiei: numr_relativ