You are on page 1of 206

Cuprins

next

up

previous

Next: Introducere. Operatori. Expresii. Up: carte Previous: carte

Cuprins
q

Introducere. Operatori. Expresii.


r r r

Primul program n C. Structura generala a unui program C Comparatie C - Pascal Variabile. Operatori. Expresii
s

Operatii aritmetice, expresii si operatori specifici limbajului C

Probleme propuse

Functii. Functii de biblioteca


r r

Functii definite de utilizator Functii de biblioteca


s s s s

Functii de intrare-iesire Functii matematice Functii de conversie Exemple rezolvate

Probleme propuse

Operatii la nivel de bit


r r r r

Operatori la nivel de bit Utilizarea operatorilor Probleme rezolvate Probleme propuse

Caractere, siruri de caractere. Tablouri


r r r

Operatii cu caractere Tablouri unidimensionale Siruri de caractere


s

Observatii asupra sirurilor de caractere

http://labs.cs.utt.ro/labs/pc/html/node1.html (1 of 4) [22.07.2003 16:17:59]

Cuprins

r r

Probleme rezolvate Probleme propuse

Prelucrarea fisierelor
r r

Tratarea fisierelor n C Operatii asupra fisierelor


s s s s s

Deschiderea/nchiderea fisierelor Alte functii referitoare la fisiere Citirea si modificarea indicatorului de pozitie Transferul caracterelor si al sirurilor de caractere Citirea si scrierea cu format

r r

Probleme rezolvate Probleme propuse

Compilarea independenta a fisierelor


r

Etapele compilarii unui program C


s s s

Preprocesarea Compilarea Link-editare De ce mai multe fisiere ? Reguli de structurare pe mai multe fisiere Lucrul n modul "project" Definirea tipului abstract stiva Evaluarea unei expresii n notatie poloneza

Structurarea programelor C pe mai multe fisiere


s s s

Tipuri de date abstracte


s s

Probleme propuse

Pointeri
r r r r

Introducere Operatii cu pointeri Pointeri ca argumente ale functiilor Pointeri si tablouri

http://labs.cs.utt.ro/labs/pc/html/node1.html (2 of 4) [22.07.2003 16:17:59]

Cuprins

r r r r

Pointeri la functii Folosirea neadecvata a operatiilor cu pointeri Problema rezolvata Problema propusa

Liste liniare simplu nlantuite


r r

Aspecte ale implementarii listelor liniare Problema rezolvata


s s

Codul sursa Comentarea programului

Problema propusa

Liste liniare multiplu nlantuite


r r

Implementarea listelor multiplu nlantuite Problema rezolvata


s s

Sursa programului Comentarea programului

Problema propusa

Tipul abstract arbore binar ordonat


r

Arbori binari
s s s s

Cautarea n arbori binari ordonati Inserarea n arbori binari ordonati Stergerea n arbori binari ordonati Parcurgerea arborilor binari Sursa programului Comentarea programului

Problema rezolvata
s s

Problema propusa

Probleme propuse spre rezolvare


r r

Setul 1 Setul 2

http://labs.cs.utt.ro/labs/pc/html/node1.html (3 of 4) [22.07.2003 16:17:59]

Cuprins

q q

Bibliografie About this document ...

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node1.html (4 of 4) [22.07.2003 16:17:59]

Introducere. Operatori. Expresii.

next

up

previous

contents

Next: Primul program n C. Up: carte Previous: Cuprins Cuprins

Introducere. Operatori. Expresii.


Subsections q Primul program n C. Structura generala a unui program C
q q

Comparatie C - Pascal Variabile. Operatori. Expresii


r

Operatii aritmetice, expresii si operatori specifici limbajului C

Probleme propuse

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node2.html [22.07.2003 16:18:00]

Primul program n C. Structura generala a unui program C

next

up

previous

contents

Next: Comparatie C - Pascal Up: Introducere. Operatori. Expresii. Previous: Introducere. Operatori. Expresii. Cuprins

Primul program n C. Structura generala a unui program C


Toate programele scrise n limbajul C au n comun mai multe elemente esentiale. Pentru nceput, vom urmari aceste elemente studiind cteva programe simple. Unul dintre programele "clasice" prezentate ca introducere n mare parte a literaturii de specialitate este Hello, World !:

#include <stdio.h> void main(void) { printf("Hello, World !\n"); }

Dupa compilarea si rularea acestui program, pe ecran va fi afisat:


Hello, World !

Orice program scris n C respecta o anumita "compozitie", toate programele au n comun o anumita structura. Astfel, orice program C este alcatuit din functii care contin instructiuni. Dintr-o perspectiva generala, un program are structura:
directive preprocesor
http://labs.cs.utt.ro/labs/pc/html/node3.html (1 of 2) [22.07.2003 16:18:01]

Primul program n C. Structura generala a unui program C

declaratii si definitii globale functii

Pentru exemplul anterior, prima linie:


#include <stdio.h>

este o directiva preprocesor. Aceste directive au ntotdeauna ca si prim caracter simbolul #. Directiva include are ca efect includerea n program a fisierului header stdio.h. Acest mecanism de includere permite programatorului sa foloseasca functii gata implementate si puse la dispozitie prin intermediul bibliotecilor de functii. Includerea fisierelor header (adica fisiere antet care contin declaratiile functiilor de biblioteca) se executa de catre compilator n faza de preprocesare, o prima faza a compilarii n care au loc diferite operatii asupra codului sursa nainte ca acesta sa fie efectiv compilat. Urmatoarea linie cu care se continua executia programului este functia main. Orice program C este compus din functii, dintre care functia main are o semnificatie speciala, aceasta fiind functia care se executa la lansarea programului. n acest caz, functia main nu are parametri si nu returneaza nici un rezultat, fapt marcat prin tipul void, adica tipul vid, un tip de date particular limbajului C (mai multe despre functii si modul n care se transmit parametri si se returneaza valori, n capitolul urmator). Corpul functiei main (si al oricarei functii) este cuprins ntre acolade, care n C sunt delimitatori de bloc (echivalent cu begin - end din Pascal). Corpul functiei n acest exemplu contine o singura instructiune:
printf("Hello, World !\n");

n aceasta linie de program se apeleaza functia printf, apartinnd bibliotecii stdio si are ca actiune afisarea valorilor transmise ca parametru. n acest caz, parametrul este sirul de caractere "Hello, World ! $\backslash$ n". Caracterul $\backslash$ n reprezinta caracterul linie noua.
next up previous contents

Next: Comparatie C - Pascal Up: Introducere. Operatori. Expresii. Previous: Introducere. Operatori. Expresii. Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node3.html (2 of 2) [22.07.2003 16:18:01]

Comparatie C - Pascal

next

up

previous

contents

Next: Variabile. Operatori. Expresii Up: Introducere. Operatori. Expresii. Previous: Primul program n C. Cuprins

Comparatie C - Pascal
n general, majoritatea celor care nvata limbajul C sunt familiarizati cu Pascal, motiv pentru care prezentam n tabelul 1.1 o comparatie ntre principalele elemente diferite ale celor doua limbaje.
Tabela 1.1: Exemplificari ale diferentei ntre Pascal si C Element declarare variabile tipuri n Pascal var nume_var : tip ; integer real fundamentale boolean string n C tip nume_var ; int double sau float nu exista, se foloseste 0 si 1 se folosesc tablouri (char[]) sau pointeri (char *) tip[lung_tablou] struct sau union nu exista while (conditie) if (conditie) for (v=min; v $<$max; v++) case :=
http://labs.cs.utt.ro/labs/pc/html/node4.html (1 of 2) [22.07.2003 16:18:01]

tipul tablou alte tipuri

array[min..max] of tip record set of while conditie do

sintaxa unor instructiuni

if conditie then for v:= min to max do

switch =

Comparatie C - Pascal

= operatori
$<>$

== !=

AND OR NOT

&& $\vert\vert$ ! % doar functii functii de biblioteca: printf, scanf, ... { ...} /* ...*/

modulo subprograme functii si proceduri operatii de I/O delimitatori de bloc comentarii instructiuni: readln, writeln, ... begin ...end { ...}

next

up

previous

contents

Next: Variabile. Operatori. Expresii Up: Introducere. Operatori. Expresii. Previous: Primul program n C. Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node4.html (2 of 2) [22.07.2003 16:18:01]

Variabile. Operatori. Expresii

next

up

previous

contents

Next: Operatii aritmetice, expresii si Up: Introducere. Operatori. Expresii. Previous: Comparatie C Pascal Cuprins

Variabile. Operatori. Expresii


La fel ca n primul paragraf, vom studia un mic exemplu comentat.

#include <stdio.h> #define FEET 0.303 void main(void) { /* program de conversie pasi - metri */ int dist1; double dist2; printf("Introduceti distanta in pasi\n"); scanf("%d",&dist1); dist2=dist1*FEET; printf("Distanta in metri este: %lf metri\n",dist2); }

Vom ncepe explicatiile cu a doua linie a programului. Dupa cum s-a aratat n primul paragraf, caracterul # semnifica o directiva preprocesor. Directiva define are ca efect substituirea textuala n cadrul programului a identificatorului FEET cu valoarea 0.303.

http://labs.cs.utt.ro/labs/pc/html/node5.html (1 of 2) [22.07.2003 16:18:01]

Variabile. Operatori. Expresii

Urmatoarea linie reprezinta nceputul functiei main. Corpul acestei functii ncepe (dupa comentariile ignorate de compilator) cu definirea a doua variabile, dist1 si dist2 de tip ntreg, respectiv real dubla precizie (pentru real dubla precizie, se foloseste tipul double). Definirea variabilelor se poate face doar la nceputul functiei sau n afara functiei (pentru variabile globale). Urmatoarea instructiune este apelul functiei printf si are ca efect tiparirea unui mesaj pe ecran. Functia scanf citeste de la tastatura o valoare ntreaga (specificata prin descriptorul de format %d) si o memoreaza n variabila dist1. n lista de argumente a lui scanf trebuie precizate nu variabilele care se citesc, ci adresele acestora (de unde folosirea operatorului de adresa &). Mai mult despre aceste functii, n capitolul urmator. Dupa citirea variabilei dist1, se calculeaza valoarea dist2, prin nmultirea cu valoarea 0.303 (obtinuta prin nlocuirea constantei FEET). Se observa ca cele doua valori sunt de tipuri diferite (dist1 de tip ntreg, iar FEET de tip real dubla precizie). C-ul este un limbaj foarte flexibil n ceea ce priveste conversia ntre tipuri si atribuiri ntre variabile de tipuri diferite, astfel rezultatul unei operatii este de tipul operandului "mai mare" din punct de vedere al reprezentarii (n cazul nostru, int se reprezinta pe mai putini octeti dect double). Daca variabila din stnga atribuirii este de un tip egal sau mai mare ca expresia rezultata n dreapta, operatia de atribuire are loc fara probleme. Daca nsa n stnga atribuirii se afla o variabila mai "slaba", rezultatul expresiei din stnga va fi trunchiat corespunzator. Ultima linie din cadrul functiei main este un apel al functiei printf pentru afisarea valorii variabilei dist2, valoare reala care impune folosirea descriptorului de format %lf.
Subsections q Operatii aritmetice, expresii si operatori specifici limbajului C
next up previous contents

Next: Operatii aritmetice, expresii si Up: Introducere. Operatori. Expresii. Previous: Comparatie C Pascal Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node5.html (2 of 2) [22.07.2003 16:18:01]

Operatii aritmetice, expresii si operatori specifici limbajului C

next

up

previous

contents

Next: Probleme propuse Up: Variabile. Operatori. Expresii Previous: Variabile. Operatori. Expresii Cuprins

Operatii aritmetice, expresii si operatori specifici limbajului C


Limbajului C ofera o foarte mare libertate programatorului, libertate nentlnita n nici un alt limbaj de programare, fapt ce explica popularitatea sa. Aceasta particularitate se reflecta cel mai mult n manipularea tipurilor, deoarece compilatorul de C (spre deosebire de cel de Pascal) nu face verificari referitoare la compatibilitatea tipurilor. Cea mai evidenta "libertate" se regaseste la tipul caracter (char). Tipul caracater este de fapt un tip ntreg reprezentat pe un octet (asemanator cu tipul byte din Pascal). Astfel, secventa urmatoare de cod este perfect legala, acest tip de "artificii" de programare fiind des ntlnite:

int i; char c; c='A'; i=c; printf("codul ASCII al caracterului %c este %d\n",i,i); i='A'+1; printf("si urmatorul caracter este %c cu codul %d\n",i,i);

Folosirea descriptorului de format %c specific caracterelor duce la interpretarea variabilei ntregi i ca o variabila caracter, si deci la tiparirea caracterului cu codul ASCII egal cu valoarea lui i. De fapt, un caracter este memorat intern prin codul sau ASCII, de aici si tratarea unitara a caracterelor si intregilor.

http://labs.cs.utt.ro/labs/pc/html/node6.html (1 of 4) [22.07.2003 16:18:02]

Operatii aritmetice, expresii si operatori specifici limbajului C

Un operator foarte folosit n C este operatorul de incrementare ++. Astfel, secventele: i++; sau ++i; sunt echivalente cu: i=i+1;. Diferenta ntre cele doua forme de scriere a operatorului de incrementare (format postfix si format prefix) consta n modul n care se face incrementarea lui i: dupa sau nainte de folosirea valorii variabilei

int i,j,k; i=5;

k=i++; /* dupa aceasta instructiune, k va avea valoarea 5, iar i 6; atribuirea are loc inainte de incrementare*/ j=++i; /* dupa aceasta instructiune, i va lua valoarea 7, iar j tot 7 atribuirea are loc dupa incrementare*/

n mod analog se comporta si operatorul de decrementare

$--$

http://labs.cs.utt.ro/labs/pc/html/node6.html (2 of 4) [22.07.2003 16:18:02]

Operatii aritmetice, expresii si operatori specifici limbajului C

Un alt mod de a compune operatorii este prin folosirea operatorului = dupa un operator aritmetic (+ - * / %) sau un operator la nivel de bit (vezi capitolul 3). De exemplu: a+=3; nseamna: a=a+3;. Limbajul C permite si atribuiri multiple, de tipul: a=b=c=2; n asemenea atribuiri, evaluarea se face de la dreapta spre stnga. Dupa cum s-a aratat n paragrafele anterioare, n C nu exista tipul boolean, valorile de adevar true-false fiind reprezentate de 0 si 1, astfel ca rezultatul unei comparatii poate fi folosit n cadrul unei atribuiri: a=b $>$3; Aceasta are ca efect atribuirea valorii 1 sau 0 (functie de b mai mare ca 3 sau nu) variabilei a. O alta particularitate a limbajului C este posibilitatea de a initializa variabile n momentul definitiei. Secventa: int i=5; defineste variabila i ca fiind de tip ntreg, avnd valoarea initiala 5. Un operator specific C-ului este operatorul de secventiere , (reprezentat prin virgula). Astfel: i=(j++, a $<$b++);

http://labs.cs.utt.ro/labs/pc/html/node6.html (3 of 4) [22.07.2003 16:18:02]

Operatii aritmetice, expresii si operatori specifici limbajului C

are ca efect evaluarea expresiei j++, dupa care se evalueaza expresia a $<$b++, rezultatul acestei ultime evaluari fiind cel atribuit lui i. Dupa cum s-a aratat n exemplele anterioare, n C se efectueaza automat conversia dintre tipuri n cazul atribuirii. La fel se ntmpla si n cazul transmiterii de parametri in functii. Programatorul poate controla explicit aceste conversii folosind operatorul de casting (). ntre paranteze se scrie tipul la care se doreste sa se faca conversia, iar parantezele se plaseaza naintea variabilei sau expresiei de convertit. Un exemplu este prezentat n secventa:
float b; b=3/(float)2;

Folosind operatorul de casting, b va avea valoarea 1.5. n absenta acestui operator, la mpartirea lui 3 la 2, ambele valori fiind ntregi, rezultatul ar fi fost trunchiat la 1, dupa care ar fi fost atribuit variabilei b. Toti operatorii prezentati pna acum au fost unari sau binari (cu unul sau doi operanzi). n C exista si un operator ternar (cu trei operanzi). Acesta este operatorul conditional ? :, echivalent cu instructiunea if. Astfel, secventa:
x=(a<b)?a:b;

este echivalenta cu:


if (a<b) x=a; else x=b;
next up previous contents

Next: Probleme propuse Up: Variabile. Operatori. Expresii Previous: Variabile. Operatori. Expresii Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node6.html (4 of 4) [22.07.2003 16:18:02]

Probleme propuse

next

up

previous

contents

Next: Functii. Functii de biblioteca Up: Introducere. Operatori. Expresii. Previous: Operatii aritmetice, expresii si Cuprins

Probleme propuse
1. Sa se ruleze secventa urmatoare, urmarind pas cu pas evolutia programului. Sa se explice ce efect are executia programului prezentat. Cu ajutorul help-ului mediului de programare, se vor studia functiile de biblioteca apelate. #include <stdio.h> #include <stdlib.h> #define PROMPT ':' void main(void) { int a,b; char c; int rez; while (putchar(PROMPT), scanf("%d%c%d",&a,&c,&b)!=EOF) { switch (c) { case '+': rez=a+b; break; case '-': rez=a-b; break; case '*': rez=a*b; break; case '/': if (b==0) { printf("\nImpartire la 0"); exit(1); } rez=a/b; break; default: printf("\nOperatie necunoscuta"); exit(1);
http://labs.cs.utt.ro/labs/pc/html/node7.html (1 of 3) [22.07.2003 16:18:02]

Probleme propuse

} printf("\n%d%c%d=%d",a,c,b,rez); } } 2. Fiind date definitiile: int i=3,j=5; determinati valoarea urmatoarelor expresii, precum si valorile lui i si j, dupa evaluarea celor 4 expresii. 1. (i/2) +4 2. (j%3) * i 3. (i++) - ( $--$ j) 4. j = (i += 2) 3. Fiind date definitiile: int a=2, b=2, c=1, d=0, e=4; determinati valoarea urmatoarelor expresii: 1. a++ / ++c * $--$ e 2.
$--$ b * c++ - a

3. -b - $--$ c 4. ++a - $--$ e 5. e / $--$ a * b++ / c++ 6. a%=b=d=1+e/2 4. Fiind date definitiile: int i=2, j=4; precizati care vor fi valorile lui i si j dupa executia urmatoarei instructiuni: j = (i++, i-j); 5. Rulati urmatorul program pas cu pas vizualiznd valorile variabilelor din program. Justificati rezultatele obtinute.

http://labs.cs.utt.ro/labs/pc/html/node7.html (2 of 3) [22.07.2003 16:18:02]

Probleme propuse

void main(void) { int a,b,c; float z; a=25000; b=15000; c=a+b; z=a+b; z=(float)a+b; c=a/b; c=a%b; c=a>b; z=a/b; z=a/(float)b; c=a=b; c=a!=b; a=3; b=11; c=a++ + ++b; a=0; b=1; c=a&&b; c=a||b; c=!a; a=2; b=5; c=(a-5,b++); c*=a+b; c=(a>b)?a:b; }

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node7.html (3 of 3) [22.07.2003 16:18:02]

Functii. Functii de biblioteca

next

up

previous

contents

Next: Functii definite de utilizator Up: carte Previous: Probleme propuse Cuprins

Functii. Functii de biblioteca


Subsections q Functii definite de utilizator
q

Functii de biblioteca
r

Functii de intrare-iesire
s s

declarate n stdio.h declarate n conio.h

r r r

Functii matematice Functii de conversie Exemple rezolvate

Probleme propuse

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node8.html [22.07.2003 16:18:02]

Functii definite de utilizator

next

up

previous

contents

Next: Functii de biblioteca Up: Functii. Functii de biblioteca Previous: Functii. Functii de biblioteca Cuprins

Functii definite de utilizator


Functiile reprezinta un aspect important al programarii, independent de limbajul utilizat. Ele permit ncapsularea unor rutine n cadrul unor "cutii negre", astfel ca programatorul care se foloseste de anumite functii trebuie sa cunoasca doar actiunea lor - ce fac ele, nu si modul cum sunt implementate. n plus, functiile permit structurarea programului pe blocuri, separnd astfel zonele de cod ce ndeplinesc actiuni diferite si conferind o mai mare lizibilitate a codului. La fel ca n capitolul precedent, vom analiza modul n care utilizatorul poate defini si apela o functie urmarind un exemplu. Se va defini o functie pentru a verifica daca restul mpartirii a doua numere este 0; cu ajutorul acestei functii se verifica apoi divizibilitatea cu 3 a primelor 100 numere naturale.

#include <stdio.h> int divizibil(int, int); void main(void) { int i; for (i=1; i<=100; i++) if (divizibil(i,3)) printf("numarul %d se divide cu 3\n",i); else printf("numarul %d nu se divide cu 3\n",i); }

http://labs.cs.utt.ro/labs/pc/html/node9.html (1 of 4) [22.07.2003 16:18:03]

Functii definite de utilizator

int divizibil(int a, int { if (a%b) /* a modulo b este returneaza 0 */ return 0; else /* a modulo b este divizibil cu b) return 1; }

b)

diferit de 0,

0 (a este */

Observatie: O alta implementare a functiei divizibil este prezentata mai jos:


int divizibil(int a, int b) { return !(a%b); }

Definirea unei functii se face n maniera:


tip_returnat nume_functie(declaratia parametrilor) { definitii locale instructiuni }

Definirea unei functii se poate face oriunde n cadrul codului sursa, sau chiar n alte fisiere, nsa nu poate fi facuta n interiorul altei functii. n exemplul anterior, a doua linie a programului reprezinta declaratia sau prototipul functiei divizibil. Aceasta are rolul de a anunta numele functiei, tipul returnat si tipul si numarul parametrilor. Nu este obligatorie prezenta prototipului, dar daca acesta lipseste, iar functia este apelata naintea declaratiei ei, unele
http://labs.cs.utt.ro/labs/pc/html/node9.html (2 of 4) [22.07.2003 16:18:03]

Functii definite de utilizator

compilatoare (mai vechi) vor da mesaje de avertizare n momentul compilarii. Prototipurile au fost introduse n standardul ANSI C (versiunile mai vechi de C nu prevedeau prototipuri de functii) pentru a permite compilatorului sa faca anumite verificari legate de numarul parametrilor functiei si de conversii ilegale ntre tipul parametrilor si cel al argumentelor. n exemplu anterior, functia divizibil are doi parametri ntregi si returneaza o valoare ntreaga. Valoarea returnata de o functie se transmite prin instructiunea return, care are ca efect si parasirea executiei functiei. n cazul ca functia nu are parametri sau nu returneaza nici o valoare, se foloseste tipul vid void. Spre deosebire de alte limbaje (ca de ex. Pascal) unde mecanismul de transmitere a parametrilor catre functii este prin adresa sau prin valoare, n C exista doar transmiterea prin valoare. La transmiterea prin valoare, modificarile asupra parametrilor efectuate n interiorul functiei nu se propaga si n afara functiei, dupa cum se poate observa si din executia exemplului urmator:

#include <stdio.h> void schimba(int a, int b) { int k; k=a; a=b; b=k; printf("in cadrul functiei, dupa schimbare a=%d b=%d\n",a,b); } void main(void) { int a=1, b=4; printf("inainte de apelul functiei a=%d b=%d\n",a,b); schimba(a,b); printf("dupa apelul functiei a=%d b=%d\n",a,b); }

http://labs.cs.utt.ro/labs/pc/html/node9.html (3 of 4) [22.07.2003 16:18:03]

Functii definite de utilizator

Chiar daca mecanismul de transmitere a parametrilor este doar prin valoare, n C se pot transmite parametri si prin adresa, ntr-un mod indirect, folosind pointeri (dupa cum se va arata n capitolele urmatoare).
next up previous contents

Next: Functii de biblioteca Up: Functii. Functii de biblioteca Previous: Functii. Functii de biblioteca Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node9.html (4 of 4) [22.07.2003 16:18:03]

Functii de biblioteca

next

up

previous

contents

Next: Functii de intrare-iesire Up: Functii. Functii de biblioteca Previous: Functii definite de utilizator Cuprins

Functii de biblioteca
Limbajul C a fost conceput ca un limbaj relativ redus, evitndu-se elemente care nu au fost considerate strict necesare sau care ar reduce flexibilitatea si viteza de executie. Prin urmare, C nu are ncorporate facilitati de prelucrare directa a sirurilor de caractere, multimilor, listelor, tablourilor. Din acest motiv, nu exista definit un tip de date pentru sirurile de caractere, folosindu-se pentru siruri tablouri de caractere (char[]) sau pointeri la caracter (char *). De asemenea, nu sunt prevazute n limbaj facilitati de intrare/iesire (nu exista instructiuni READ sau WRITE), de alocare dinamica de memorie sau metode de acces la fisiere. Pentru aceste operatii, cea mai mare parte a implementarilor de C ofera colectii standard de functii de biblioteca. Aceste functii au o varietate de optiuni. n plus, fiecare programator isi poate construi propria sa biblioteca de functii care sa nlocuiasca sau sa extinda colectia de functii standard ale limbajului. n cele ce urmeaza, vom trece n revista functiile de biblioteca cele mai uzuale (mai putin functiile pentru tratarea sirurilor de caractere si functiile relative la fisiere, care vor fi prezentate n capitolele urmatoare).
Subsections q Functii de intrare-iesire
r r

declarate n stdio.h declarate n conio.h

q q q

Functii matematice Functii de conversie Exemple rezolvate

http://labs.cs.utt.ro/labs/pc/html/node10.html (1 of 2) [22.07.2003 16:18:03]

Functii de biblioteca

next

up

previous

contents

Next: Functii de intrare-iesire Up: Functii. Functii de biblioteca Previous: Functii definite de utilizator Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node10.html (2 of 2) [22.07.2003 16:18:03]

Functii de intrare-iesire

next

up

previous

contents

Next: declarate n stdio.h Up: Functii de biblioteca Previous: Functii de biblioteca Cuprins

Functii de intrare-iesire
Subsections q declarate n stdio.h
q

declarate n conio.h

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node11.html [22.07.2003 16:18:03]

declarate n stdio.h

next

up

previous

contents

Next: declarate n conio.h Up: Functii de intrare-iesire Previous: Functii de intrare-iesire Cuprins

declarate n stdio.h getchar Prototip: int getchar(void); Efect: returneaza un caracter citit de la tastatura sau constanta simbolica EOF daca s-a ntlnit sfrsitul fisierului de intrare (perechea CTRL-Z). Observatie: Functia asteapta apasarea tastei Enter.

putchar Prototip: int putchar(int c); Efect: afiseaza caracterul c pe ecran; returneaza caracterul afisat sau valoarea EOF la detectia unei erori.

gets Prototip: char *gets(char *s); Efect: citeste un sir de caractere s de la tastatura pna la ntlnirea caracterului newline ( $\backslash$ n); returneaza adresa sirului citit sau valoarea NULL daca s-a citit

http://labs.cs.utt.ro/labs/pc/html/node12.html (1 of 4) [22.07.2003 16:18:03]

declarate n stdio.h

CTRL-Z. Caracterul newline nu este memorat n sir. Observatie: Deoarece este imposibil de prevazut cte caractere vor fi citite de la tastatura ntr-o operatie de introducere de siruri, si deoarece gets nu verifica lungimea alocata sirului destinatie, folosirea acestei functii n programele importante poate duce la efecte "neplacute" (prin scrierea datelor citite peste zone de memorie alocate altor variabile). Acest "bug" a dus la "spargerea" multor sisteme vechi care foloseau gets pentru citirea parolei. puts Prototip: int puts(char *s); Efect: afiseaza pe ecran sirul s urmat de caracterul newline.

printf Prototip: int printf(char *format, arg1, arg2, ...); Efect: afiseaza pe ecran valorile din lista de argumente, conform formatului specificat. Sirul format poate contine caractere ordinare, care se vor afisa ca atare, si descriptori de format prefixati de caracterul %. Un descriptor de format poate contine n ordine urmatoarele:
q q q

un semn minus care indica alinierea la stnga n cadrul formatului a valorii afisate; un numar care specifica lungimea minima a cmpului de afisare; un punct care separa lungimea cmpului de afisare de precizia de afisare (de ex. numarul de zecimale pentru valorile reale);

n tabelul 2.1 sunt prezentate caracterele de conversie cele mai uzuale ce pot aparea n descriptorii de format.
Tabela 2.1: Descriptori de format

http://labs.cs.utt.ro/labs/pc/html/node12.html (2 of 4) [22.07.2003 16:18:03]

declarate n stdio.h

Caracter d,i o x, X u c s f lf

Valoare ntreg zecimal ntreg octal fara semn ntreg hexazecimal fara semn ntreg zecimal fara semn caracter sir de caractere real simpla precizie real dubla precizie

scanf Prototip: int scanf(char *format, adr1, adr2,...); Efect: citeste caractere de la tastatura, conform formatului, si nscrie valorile citite la adresele specificate. Functia returneaza numarul de cmpuri citite cu succes sau valoarea EOF la ntlnirea sfrsitului fisierului de intrare. Sirul format poate contine:
q q q

caractere blank sau tab care sunt ignorate; caractere ordinare care trebuie sa fie citite corespunzator de la intrare; specificatori de conversie, la fel ca la printf.

Specificatorii de conversie determina modul de conversie a cmpurilor de intrare. Un cmp de intrare se defineste ca o secventa de caractere, altele dect spatiile albe ale limbajului: blank, tab, newline, carriage return, formfeed, tab vertical. De exemplu, pentru citirea unei linii de forma: 6 Mar 1996

http://labs.cs.utt.ro/labs/pc/html/node12.html (3 of 4) [22.07.2003 16:18:03]

declarate n stdio.h

se va scrie urmatoarea secventa:


int zi, an; char luna[4]; scanf("%d %s %d", &zi, luna, &an);

Se observa ca la variabilele zi si an s-a folosit operatorul de adresa &; la variabila luna, el nu apare deoarece n limbajul C numele unui tablou este echivalent cu adresa sa (este un pointer catre primul sau element). Observatie: Pentru mai multe informatii privind functiile scanf si printf consultati fisierul de help prezent n mediul de programare utilizat.

sscanf Prototip: int sscanf(char *sir,char *format, adr1, adr2,...); Efect: citeste date cu formatare; spre deosebire de scanf la care citirea se face de la tastatura (dispozitivul standard de intrare), la sscanf citirea datelor se face dintr-un sir.

next

up

previous

contents

Next: declarate n conio.h Up: Functii de intrare-iesire Previous: Functii de intrare-iesire Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node12.html (4 of 4) [22.07.2003 16:18:03]

declarate n conio.h

next

up

previous

contents

Next: Functii matematice Up: Functii de intrare-iesire Previous: declarate n stdio.h Cuprins

declarate n conio.h getch Prototip: int getch(void); Efect: citeste un caracter de la tastatura fara sa-l afiseze pe ecran; returneaza caracterul citit.

getche Prototip: int getche(void); Efect: citeste un caracter de la tastatura si-l afiseaza pe ecran; returneaza caracterul citit.

ungetch Prototip: int ungetch(int c); Efect: reinsereaza caracterul c n buffer-ul tastaturii, astfel nct urmatorul caracter care va fi citit este cel reinserat.
Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node13.html [22.07.2003 16:18:04]

Functii matematice

next

up

previous

contents

Next: Functii de conversie Up: Functii de biblioteca Previous: declarate n conio.h Cuprins

Functii matematice
Functiile prezentate n tabelul 2.2 sunt declarate in fisierul antet math.h.
Tabela 2.2: Functii matematice din biblioteca math Prototipul functiei double acos(double x); double asin(double x); double atan(double x); double atan2(double y, double x); double ceil(double x); double cos(double x); double exp(double x); double fabs(double x); double floor(double x); double log(double x); double log10(double x); double pow(double x, double y); double sin(double x); double sqrt(double x); double tan(double x); Efect arccosinus de x arcsinus de x arctangenta de x arctangenta de y/x cel mai mic intreg mai mare sau egal cu x cosinus de x exponentiala $e^x$ valoarea absoluta a lui x cel mai mare intreg mai mic sau egal cu x ln de x lg de x x la puterea y sinus de x radicalul lui x tangenta lui x

next

up

previous

contents

Next: Functii de conversie Up: Functii de biblioteca Previous: declarate n conio.h Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node14.html [22.07.2003 16:18:04]

Functii de conversie

next

up

previous

contents

Next: Exemple rezolvate Up: Functii de biblioteca Previous: Functii matematice Cuprins

Functii de conversie
Prezentam n tabelul 2.3 doua functii de conversie a unui sir de caractere ntr-o valoare ntreaga, respectiv ntr-o valoare reala. Aceste functii sunt declarate n fisierul antet stdlib.h.
Tabela 2.3: Functii de conversie sir - valoare numerica Prototip int atoi(char *s); double atof(char *s); Efect converteste sirul s ntr-o valoare ntreaga converteste sirul s ntr-o valoare reala

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node15.html [22.07.2003 16:18:04]

Exemple rezolvate

next

up

previous

contents

Next: Probleme propuse Up: Functii de biblioteca Previous: Functii de conversie Cuprins

Exemple rezolvate
1. Sa se scrie un program care citeste o succesiune de linii ce contin date calendaristice n formatul: zi/luna/an. Se cere sa se afiseze liniile scrise corect conform formatului specificat anterior. #include <stdio.h> void main(void) { char linie[80]; int zi, luna, an; while (gets(linie)!=NULL) if (sscanf(linie, "%d/%d/%d", &zi, &luna, &an)==3) printf("%s\n", linie); } 2. Sa se realizeze programul care citeste o secventa de numere reale, terminata cu Ctrl-Z si afiseaza dupa fiecare citire suma valorilor absolute citite pna n acel moment. Afisarea sumei se face cu o precizie de 3 cifre zecimale. #include <stdio.h> #include <math.h> void main(void) { double suma=0, valoare; while(1) { printf("\nDati un numar: "); if (scanf("%lf", &valoare)==EOF) break; printf("\t %.3lf\n", suma+=fabs(valoare)); } } Observatie: Unii autori recomanda, pe ct posibil, evitarea unei bucle while(1) si iesirea prin instructiunea break, deoarece prin aceasta practica se distruge lizibilitatea programelor. Conditia de iesire din bucla e bine sa apara ca si conditie pentru while, chiar daca aceasta nseamna lungirea

http://labs.cs.utt.ro/labs/pc/html/node16.html (1 of 2) [22.07.2003 16:18:05]

Exemple rezolvate

cu 2-3 linii a secventei. 3. Se citeste de la tastatura un text terminat cu Ctrl-Z. Se cere sa se afiseze toate numerele ntregi continute n text. #include <stdio.h> #include <stdlib.h> #include <ctype.h> #define N 15 void main(void) { char c; /* caracterul citit la un moment dat */ char s[20]; /* buffer cu caract. ce compun un numar */ int numere[N]; /* tablou cu numerele citite */ int i=0, j=0; c=getchar(); while (c!=EOF) if (isdigit(c)) /* incepe un numar */ { i=0; s[i++]=c; while (isdigit(c=getchar())) s[i++]=c; s[i]='\0'; numere[j++]=atoi(s); } else c=getchar(); /* afisarea numerelor */ for (i=0; i<j; i++) printf("\n %6d", numere[i]); } Observatie: Pentru a testa daca un caracter este cifra s-a folosit functia isdigit() declarata n fisierul antet ctype.h (va fi prezentata n capitolele urmatoare). Dupa ce s-au citit caracterele corespunzatoare unui numar, folosind functia atoi se face conversia n numarul ntreg corespunzator. Numerele ntlnite n cadrul textului se memoreaza n tabloul numere.
next up previous contents

Next: Probleme propuse Up: Functii de biblioteca Previous: Functii de conversie Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node16.html (2 of 2) [22.07.2003 16:18:05]

Probleme propuse

next

up

previous

contents

Next: Operatii la nivel de Up: Functii. Functii de biblioteca Previous: Exemple rezolvate Cuprins

Probleme propuse
1. Scrieti instructiunea care va afisa urmatoarele linii: H. Smith /78 \ aaa #67 "ggg" mmm 2. Aratati ce afiseaza urmatorul program: #include <stdio.h> void main(void) { int i=43; char c='A'; float f=55.45; printf("%5d %.1f %c\n",i,f,c); printf("%d %d %d \n",i, (int)f, c); printf("%c %d\n", c+1, c); } 3. Sa se implementeze o functie int putere(int x, int n); care ridica pe x la puterea n. Sa se scrie un program care calculeaza patratele si cuburile primelor 10 numere naturale folosind functia putere. 4. Sa se scrie un program care citeste de la tastatura un numar real x si un caracter ce reprezinta optiunea utilizatorului privind operatia ce trebuie efectuata cu numarul respectiv, dupa care afiseaza rezultatul operatiei. Prezentam mai jos optiunile posibile: ''e'' - e la puterea x ''l'' - ln de x ''r'' - radicalul lui x ''m'' - valoarea absoluta a lui x.

Cristian Gavrila 2001-10-02


http://labs.cs.utt.ro/labs/pc/html/node17.html [22.07.2003 16:18:05]

Operatii la nivel de bit

next

up

previous

contents

Next: Operatori la nivel de Up: carte Previous: Probleme propuse Cuprins

Operatii la nivel de bit


Subsections q Operatori la nivel de bit
q q q

Utilizarea operatorilor Probleme rezolvate Probleme propuse

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node18.html [22.07.2003 16:18:05]

Operatori la nivel de bit

next

up

previous

contents

Next: Utilizarea operatorilor Up: Operatii la nivel de Previous: Operatii la nivel de Cuprins

Operatori la nivel de bit


Spre deosebire de alte limbaje de nivel nalt, de exemplu Pascal Standard, C ofera o familie de 6 operatori la nivel de bit, furniznd astfel facilitati specifice, de obicei, limbajelor de asamblare. Acestia permit scrierea unor programe care lucreaza ndeaproape cu sistemul hardware al calculatorului. Operatorii la nivel de bit se aplica unor ntregi, adica obiecte de tipul char, short, int, long, cu sau fara semn, iar rezultatele obtinute sunt de asemenea ntregi. Fata de ceilalti operatori ai limbajului, ei opereaza asupra fiecarui bit din reprezentarea interna a operanzilor, tratndu-l independent de valorile celorlalti biti. Acesti operatori sunt:
$\thicksim$

operatorul unar de negare & operatorul binar si


$\vert$

operatorul binar sau ^ operatorul binar sau exclusiv


$<<$

operatorul de deplasare la stnga


$>>$

operatorul de deplasare la dreapta.

http://labs.cs.utt.ro/labs/pc/html/node19.html (1 of 2) [22.07.2003 16:18:06]

Operatori la nivel de bit

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node19.html (2 of 2) [22.07.2003 16:18:06]

Utilizarea operatorilor

next

up

previous

contents

Next: Probleme rezolvate Up: Operatii la nivel de Previous: Operatori la nivel de Cuprins

Utilizarea operatorilor
Un exemplu tipic de utilizare a operatorilor la nivel de bit este implementarea unei multimi ca vector de biti. n acest caz, un bit dintr-un ntreg fara semn se asociaza unui element din multime, iar valoarea 1, respectiv 0 a unui bit semnifica prezenta, respectiv absenta elementului din multime. Numarul de elemente din multime este limitat la numarul de biti disponibili. n acest caz operatorul binar & este interpretat ca si intersectie, iar $\vert$si reuniune. ca Alte utilizari ale acestor operatori se ntlnesc n programele dedicate operatiilor hardware. Indiferent de scopul n care sunt utilizati operatorii, maniera n care sunt folositi este n general aceeasi. n cele ce urmeaza, se vor descrie pe scurt principiile de baza ale utilizarii lor. Atentie! Operatorii la nivel de bit nu modifica valoarea operanzilor (se comporta ca si operatorii aritmetici obisnuiti), astfel o operatie n 2 va rezulta ntr-un nou numar, fara a modifica valoarea variabilei n. Pentru a modifica valoarea variabilei n trebuie sa avem o atribuire: n = n 2; n general, operatorul si (&) este folosit pentru a masca anumiti biti dintr-un numar: n = n & 177

http://labs.cs.utt.ro/labs/pc/html/node20.html (1 of 3) [22.07.2003 16:18:06]

Utilizarea operatorilor

va pune pe 0 bitii din n corespunzatori zero-urilor din reprezentarea binara a numarului 177 (adica 10110001), bitii corespunzatori unu-rilor ramnnd nemodificati. Operatorul sau ( $\vert$ comporta asemanator, doar ca elementul neutru nu este 1 ca ) se la si, ci 0. Trebuie facuta distinctia ntre operatorii la nivel de bit (& si $\vert$operatorii logici ) si (&& si fi 1. Operatorii de deplasare
$<<$

). De exemplu, $\vert\vert$

daca x=1 si y=2, atunci x & y va fi 0, iar x && y va

si

$>>$

realizeaza deplasarea bitilor din operandul

stng cu attea pozitii cte sunt indicate de operandul drept. n cazul deplasarii la stnga ( $<<$ ) bitii din stnga se vor pierde, iar n dreapta numarului vor fi introduse cifre de 0. n cazul deplasarii la dreapta, bitii din dreapta se pierd, iar n stnga se introduc biti de 0, n caz ca numarul era de tip fara semn (unsigned, char) sau biti egali cu bitul de semn (cel mai din stnga bit) n cazul numerelor de tip cu semn. Operatorul de negare $\thicksim$ realizeaza complementarea tuturor bitilor unui numar. Se impun doua observatii legate de acest operator:
1. n general, daca dorim setarea pe 1 a unor biti de la nceputul unui numar, nu vom folosi o expresie de tipul x = x & 252 (adica un numar cu primele cifre binare 1), deoarece nu putem fi siguri niciodata pe cti octeti este reprezentata variabila x (chiar daca stim exact de ce tip este variabila, lungimea reprezentarii depinde de arhitectura calculatorului si de sistemul de operare). Astfel, se 3 (unde 252). va prefera folosirea unor expresii de tipul x = x & $\thicksim$ 3 = $\thicksim$ 2. deoarece reprezentarea interna a numerelor cu semn poate diferi ntre arhitecturi sau sisteme de operare diferite, operatorul de negare pe biti reduce portabilitatea programelor ntre diferite sisteme de calcul. Din acest motiv se recomanda folosirea acestui operator doar cu numere de tip fara semn.
next up previous contents

Next: Probleme rezolvate Up: Operatii la nivel de Previous: Operatori la nivel de Cuprins Cristian
http://labs.cs.utt.ro/labs/pc/html/node20.html (2 of 3) [22.07.2003 16:18:06]

Utilizarea operatorilor

Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node20.html (3 of 3) [22.07.2003 16:18:06]

Probleme rezolvate

next

up

previous

contents

Next: Probleme propuse Up: Operatii la nivel de Previous: Utilizarea operatorilor Cuprins

Probleme rezolvate
Sa se scrie o functie getbits(x,p,n) care returneaza, aliniat la dreapta, un cmp de n biti dintr-un ntreg fara semn x, ncepnd cu pozitia p a lui x, dupa cum se arata n figura 3.1. Se considera ca bitul cel mai putin semnificativ al lui x are pozitia 0.

\begin{figure}\begin{center} \epsfig{file=getbits.eps} \end{center}\end{figure}

Figura 3.1: Functia getbits #include <stdio.h> unsigned getbits(unsigned x, int p, int n) { return (x >> (p+1-n)) & ~(~0 << n); }

http://labs.cs.utt.ro/labs/pc/html/node21.html (1 of 2) [22.07.2003 16:18:06]

Probleme rezolvate

void main(void) { unsigned x; int p=6,n=3; printf("Numar initial: "); scanf("%u", &x); printf("Valoarea extrasa: %u\n", getbits(x,p,n)); }

Se observa ca n functia getbits:


q

secventa

$x >> (p+1-n)$

aliniaza la dreapta bitii de extras

secventa $\thicksim (\thicksim 0 creeaza masca de extragere, adica 000...0111


<< n)$

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node21.html (2 of 2) [22.07.2003 16:18:06]

Probleme propuse

next

up

previous

contents

Next: Caractere, siruri de caractere. Up: Operatii la nivel de Previous: Probleme rezolvate Cuprins

Probleme propuse
1. Sa se scrie o functie setbits(x,p,n,y), care returneaza un ntreg x avnd n biti ncepnd de la pozitia p egali cu cei mai din dreapta n biti ai ntregului y, ca n figura 3.2. Restul bitilor lui x ramn nemodificati.

\begin{figure}\begin{center} \epsfig{file=setbits.eps} \end{center}\end{figure}

Figura 3.2: Functia setbits 2. Sa se scrie o functie bin(x) care afiseaza reprezentarea binara a unui ntreg x, utiliznd operatorii de deplasare la nivel de bit. 3. Se considera multimi cu elemente ntregi avnd valori n intervalul [1...n]. Aceste multimi se implementeaza ca vectori de biti: char tab[n/8+1], n care sunt setati bitii corespunzatori elementelor prezente n multime. Sa se implementeze urmatoarele operatii (functii) cu aceste multimi: r afisarea elementelor unei multimi: void afiseaza(char mult[]); r adaugarea unui element la o multime: void adauga(int x,char mult[]); r verificarea prezentei unui element n multime: int prezent(int x,char mult[]); r reuniunea a doua multimi:
http://labs.cs.utt.ro/labs/pc/html/node22.html (1 of 2) [22.07.2003 16:18:07]

Probleme propuse

void reuniune(char mult1[],char mult2[],char mult3[]); r intersectia a doua multimi: void intersectie(char mult1[],char mult2[],char mult3[]); r diferenta a doua multimi: void diferenta(char mult1[],char mult2[],char mult3[]); Se va scrie un program care permite, pe baza unui meniu, selectarea acestor operatii.
next up previous contents

Next: Caractere, siruri de caractere. Up: Operatii la nivel de Previous: Probleme rezolvate Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node22.html (2 of 2) [22.07.2003 16:18:07]

Caractere, siruri de caractere. Tablouri

next

up

previous

contents

Next: Operatii cu caractere Up: carte Previous: Probleme propuse Cuprins

Caractere, siruri de caractere. Tablouri


Subsections q Operatii cu caractere
q q

Tablouri unidimensionale Siruri de caractere


r

Observatii asupra sirurilor de caractere

q q

Probleme rezolvate Probleme propuse

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node23.html [22.07.2003 16:18:07]

Operatii cu caractere

next

up

previous

contents

Next: Tablouri unidimensionale Up: Caractere, siruri de caractere. Previous: Caractere, siruri de caractere. Cuprins

Operatii cu caractere
Tipul predefinit, destinat n C lucrului cu caractere, este tipul char. Spatiul de memorie asociat variabilelor acestui tip este 1 octet; un caracter se memoreaza ca numarul ntreg corespunzator codului ASCII al caracterului respectiv. Prin urmare, n C un caracter poate aparea n operatii numerice. Valorile acestui tip sunt cuprinse n intervalul [-128...127] n cazul caracterelor cu semn, respectiv [0...255] n cazul celor fara semn. Biblioteca C standard ofera o gama larga de functii pentru manipularea caracterelor. Aceste functii sunt grupate n doua categorii:
q q

functii de citire si scriere a caracterelor (declarate n fisierul stdio.h) functii de clasificare si conversie a caracterelor.

O parte din functiile din prima categorie au fost tratate n Capitolul 2. n continuare prezentam cteva functii din a doua categorie. La unele dintre acestea vor fi date ca exemplu variante posibile de implementare. int isalpha(int c); Efect: returneaza o valoare nenula daca c este litera ['' A''...''Z'', ''a''...''z'']; Exemplu de implementare:
int isalpha(int c) { return c>='A' && c<='Z' || c>='a' && c<='z'; }

http://labs.cs.utt.ro/labs/pc/html/node24.html (1 of 3) [22.07.2003 16:18:07]

Operatii cu caractere

int isdigit(int c); Efect: returneaza o valoare nenula daca c este cifra [''0''...''9'']; int isalnum(int c); Efect: returneaza o valoare nenula daca c este litera sau cifra; int isupper(int c); Efect: returneaza o valoare nenula daca c este litera mare; int islower(int c); Efect: returneaza o valoare nenula daca c este litera mica; int isspace(int c); Efect: returneaza o valoare nenula daca c este un caracter spatiu ('' '', f, $\backslash$ v); $\backslash$

r, $\backslash$ t, $\backsl $\backslash$ n,

int toupper(int c); Efect: returneaza litera majuscula ce corespunde lui c, daca c este litera mica; Exemplu de implementare:
int toupper(int c) { return islower(c) ? c-'a'+'A' : c; }

http://labs.cs.utt.ro/labs/pc/html/node24.html (2 of 3) [22.07.2003 16:18:07]

Operatii cu caractere

int tolower(int c); Efect: returneaza litera mica ce corespunde lui c, daca c este litera mare;
next up previous contents

Next: Tablouri unidimensionale Up: Caractere, siruri de caractere. Previous: Caractere, siruri de caractere. Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node24.html (3 of 3) [22.07.2003 16:18:07]

Tablouri unidimensionale

next

up

previous

contents

Next: Siruri de caractere Up: Caractere, siruri de caractere. Previous: Operatii cu caractere Cuprins

Tablouri unidimensionale
n C, tablourile unidimensionale sunt alcatuite dintr-un grup de elemente de acelasi tip (numit tip de baza) si referite printr-un nume comun. Variabilele de tip tablou se definesc n maniera: tip_de_baza nume_var[dimensiune]; Un element al tabloului este accesat folosind ca index pozitia elementului, astfel tabloul_meu[6] va referi al saptelea element al tabloului tabloul_meu. Atentie! n C, "numerotarea" elementelor tablourilor ncepe cu pozitia 0, astfel, daca avem definitia: int tabloul_meu[100]; primul element al tabloului va fi tabloul_meu[0], iar ultimul tabloul_meu[99]. Tablourile sunt stocate n memorie la locatii consecutive, un tablou ocupnd o zona contigua de memorie, cu primul element al tabloului aflat la adresa mai mica. Atentie! O problema legata de tablouri este ca n C nu se face nici o verificare legata de "marginile" tabloului, astfel ca se pot accesa gresit elemente din afara tabloului. De exemplu, pentru definitia: int tabloul_meu[100]; daca accesam tabloul_meu[105] nu se va semnala nici o eroare, returnndu-se valoarea de la o locatie de memorie aflata la o distanta de 5 locatii fata de sfrsitul tabloului, fapt ce va duce la comportari "bizare" ale programului. Aceeasi situatie, dar fata de nceputul tabloului, se ntmpla la accesarea tabloul_meu[-5].
http://labs.cs.utt.ro/labs/pc/html/node25.html (1 of 2) [22.07.2003 16:18:08]

Tablouri unidimensionale

next

up

previous

contents

Next: Siruri de caractere Up: Caractere, siruri de caractere. Previous: Operatii cu caractere Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node25.html (2 of 2) [22.07.2003 16:18:08]

Siruri de caractere

next

up

previous

contents

Next: Observatii asupra sirurilor de Up: Caractere, siruri de caractere. Previous: Tablouri unidimensionale Cuprins

Siruri de caractere
Cele mai des ntlnite utilizari ale tablorilor unidimensionale n limbajul C sunt sirurile de caractere, din cauza ca n C nu exista prevazut tipul de date sir de caractere. Pentru memorarea sirurilor se utilizeaza tablouri cu tipul de baza char, care au pe ultima pozitie, ca marca de sfrsit a sirului, caracterul '' $\backslash$ 0''. Pe lnga necesitatea de a defini un sir de caractere ca si tablou de caractere, n prelucrarea sirurilor se utilizeaza deseori tipul pointer la caracter. De exemplu:
char sir[30]; char *psir; /* tablou de 30 de caractere */ /* pointer la caracter */

Astfel, sir este o variabila de tipul tablou de caractere pentru care se rezerva un spatiu de memorie de 30 de octeti, n timp ce psir este un pointer la caracter care poate primi ca valoare adresa unui caracter (n particular, adresa primului element dintr-un sir de caractere). Trebuie retinut ca ori de cte ori se lucreaza cu variabile siruri de caractere ntr-un program, trebuie sa existe fie o definitie de forma celei prezentate pentru variabila sir, prin care se rezerva static (n timpul compilarii), spatiul de memorie necesar variabilei, fie sa se aloce dinamic memoria necesara. Neexistnd tipul sir de caractere, n C nu sunt prezenti nici operatorii pentru siruri. n schimb, biblioteca standard contine numeroase functii pentru prelucrarea sirurilor de caractere. O parte a functiilor pentru citirea/scrierea sirurilor, declarate n fisierul antet stdio.h, le-am prezentat n Capitolul 2. n continuare, trecem n revista functiile pentru compararea, copierea, concatenarea sirurilor, s.a.m.d. Acestea sunt declarate n fisierul string.h. Ele primesc adresele sirurilor prelucrate, prin intermediul parametrilor de tipul pointer la caracter.

http://labs.cs.utt.ro/labs/pc/html/node26.html (1 of 3) [22.07.2003 16:18:08]

Siruri de caractere

int strcmp(char *s1, char *s2); Efect: compara sirurile s1 si s2 si returneaza daca s1 egal s2, si
$>0$ $<0$ ,

daca sirul s1

$<$ sirul

s2, 0

daca s1

$>$ s2.

int strncmp(char *s1, char *s2, int n); Efect: identica cu strcmp, dar se compara sirurile s1 si s2 pentru cel mult n caractere.

char *strcpy(char *d, char *s); Efect: copiaza sirul sursa s n sirul destinatie d si returneaza adresa sirului destinatie.

char *strncpy(char *d, char *s, int n); Efect: copiaza maxim n caractere de la sursa s la destinatia d si returneaza adresa sirului destinatie.

int strlen(char *s); Efect: returneaza lungimea sirului fara a numara caracterul terminator ('' $\backslash$ 0'').

http://labs.cs.utt.ro/labs/pc/html/node26.html (2 of 3) [22.07.2003 16:18:08]

Siruri de caractere

char *strcat(char *d, char *s); Efect: concateneaza cele doua siruri si returneaza adresa sirului rezultat. n paragraful urmator vor fi prezentate particularitati ale operatiilor cu siruri de caractere, ct si dificultati si erori tipice rezultate din manipularea sirurilor de caractere.
Subsections q Observatii asupra sirurilor de caractere
next up previous contents

Next: Observatii asupra sirurilor de Up: Caractere, siruri de caractere. Previous: Tablouri unidimensionale Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node26.html (3 of 3) [22.07.2003 16:18:08]

Observatii asupra sirurilor de caractere

next

up

previous

contents

Next: Probleme rezolvate Up: Siruri de caractere Previous: Siruri de caractere Cuprins

Observatii asupra sirurilor de caractere


Se impun facute cteva precizari asupra unor operatii cu siruri. Prima precizare se refera la natura "duala" tablou-pointer (care va fi prezentata n capitolele urmatoare), motiv pentru care, n cazul citirii unui sir de caractere folosind functia scanf, nu este necesara folosirea operatorului de adresa & n fata variabilei sir (indiferent ca aceasta a fost declarata ca pointer la char sau ca tablou de caractere). O recomandare de ordin "practic", impusa de maniera n care unele functii de intrare/iesire folosesc buffer-ul de intrare: se va evita folosirea functiei scanf pentru citirea unui singur caracter, mai ales dupa un alt apel al functiei scanf; se recomanda folosirea functiilor getch sau getche (nu getchar). O alta problema n folosirea functiei scanf la citirea sirurilor de caractere apare la siruri care contin caractere de tip separator (spatii goale, tab-uri, etc.). Functia scanf va citi sirul doar pna la primul caracter de acest tip. Frecvent, programatorii obisnuiti cu limbajul Pascal si care "migreaza" la C fac o greseala importanta: compararea sirurilor folosind operatorii de comparatie aritmetici: $<$, $>$ si $==$ . Din punct de vedere sintactic, nu se semnaleaza nici o eroare n timpul compilarii, dar n timpul executiei vor aparea comportari anormale ale programului. Cauza acestui fapt este ca folosind comparatii ntre siruri cu operatori aritmetici, se realizeaza, de fapt, o comparatie ntre adresele de memorie la care sunt stocate sirurile, si nu o comparatie efectiva ntre siruri. Pentru a compara siruri, trebuie folosite doar functiile dedicate (strcmp, strncmp).

http://labs.cs.utt.ro/labs/pc/html/node27.html (1 of 2) [22.07.2003 16:18:09]

Observatii asupra sirurilor de caractere

O greseala asemanatoare este folosirea operatorului aritmetic de atribuire ntre siruri. n loc sa se efectueze copierea unui sir peste celalalt, dupa atribuirea aritmetica, cele doua variabile sir vor referi aceeasi zona de memorie (deoarece s-a realizat o atribuire de pointeri). Pentru atribuiri de siruri, se vor folosi functii specifice (strcpy, strncpy, bcopy, memcpy, memmove). Compilatorul nu va sesiza eroare dect daca cele doua siruri au fost declarate ca tablouri. Exemplul urmator ilustreaza aceasta greseala (operatia de alocare va fi explicata n capitolul dedicat pointerilor):
#include <stdio.h> #include <stdlib.h> #include <string.h> void main(void){ char * s1; char * s2; s1=(char *)malloc(20); s2=(char *)malloc(20); /* alocare dinamica, 20 caractere */ /* echivalent cu declaratia: */ /* char s1[20], s2[20]; */

strcpy(s1,"abcedfg"); strcpy(s2,"mnopqrs"); s1=s2; /* s1 si s2 vor referi acelasi sir de caractere */

s1[3]='\0'; /* scurteaza pe s1 la 3 caractere */ printf("%s\n%s\n",s1,s2); /* modificarea se va reflecta si */ /* asupra lui s2 */ }


next up previous contents

Next: Probleme rezolvate Up: Siruri de caractere Previous: Siruri de caractere Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node27.html (2 of 2) [22.07.2003 16:18:09]

Probleme rezolvate

next

up

previous

contents

Next: Probleme propuse Up: Caractere, siruri de caractere. Previous: Observatii asupra sirurilor de Cuprins

Probleme rezolvate
1. Sa se implementeze n doua moduri functia strcmp.

int strcmp(char *s1, char *s2) { int i; for (i=0; s1[i]||s2[i]; i++) if (s1[i]<s2[i]) return -1; else if (s1[i]>s2[i]) return 1; return 0; }

int strcmp(char *s1, char *s2) { int i; for (i=0; s1[i]||s2[i]; i++) if (s1[i]!=s2[i]) break; return s1[i]-s2[i]; } 2. Sa se implementeze functia strcpy. char *strcpy(char *d, char *s) { int i=0; while (s[i])
http://labs.cs.utt.ro/labs/pc/html/node28.html (1 of 3) [22.07.2003 16:18:09]

Probleme rezolvate

/* nu s-a ajuns la sfarsitul sirului s */ d[i]=s[i]; i++;

} d[i]='\0'; return d; } 3. Sa se scrie o functie care converteste un caracter reprezentnd o cifra hexazecimala n echivalentul ntreg zecimal. int hexa (char c) { if (isalpha(c)) return toupper(c)-'A'+10; return c-'0'; } 4. Sa se scrie o functie care verifica daca un sir de caractere este compus n ntregime din cifre. Folosind aceasta functie, sa se scrie un program care citeste de la intrare siruri de caractere (cte unul pe fiecare linie) pna la ntlnirea caracterului EOF si afiseaza inversat (de la dreapta la stnga) fiecare sir citit, exceptnd sirurile compuse doar din cifre, care se vor afisa nemodificate. #include <stdio.h> #include <string.h> #include <ctype.h> int numar(char * s) { int i=0; while(s[i]) if (!isdigit(s[i++])) return 0; /* s-a gasit un caracter non-cifra */ return 1; /* toate caraterele sunt cifre */ } void main(void) { char sir[80], c; short i, j; while (gets(sir)!=NULL) { if (!numar(sir)) /* se interschimba prin intermediul lui c elementele
http://labs.cs.utt.ro/labs/pc/html/node28.html (2 of 3) [22.07.2003 16:18:09]

Probleme rezolvate

aflate pe pozitii simetrice in raport cu mijlocul sirului */ for (i=0, j=strlen(sir)-1; i<j; ++i, --j) c=sir[i], sir[i]=sir[j], sir[j]=c; puts(sir); } }

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node28.html (3 of 3) [22.07.2003 16:18:09]

Probleme propuse

next

up

previous

contents

Next: Prelucrarea fisierelor Up: Caractere, siruri de caractere. Previous: Probleme rezolvate Cuprins

Probleme propuse
1. Se da o lista de cuvinte separate prin spatiu, lista care se ncheie prin doua rnduri goale succesive (doua enter-uri). Sa se tipareasca n ordine alfabetica toate palindroamele care apar n lista. Un palindrom este un cuvnt care este identic citit de la nceput spre sfrsit ca si de la sfrsit spre nceput (de exemplu: cazac, elevele, cojoc). 2. Un numar real are diagrama sintactica prezentata n Figura 4.1. Scrieti o functie care converteste un sir de caractere, ce respecta aceasta diagrama, n valoarea reala corespunzatoare. Functia primeste ca parametru pointerul la sirul de convertit si returneaza valoarea reala calculata. Functia elimina eventualele spatii ce preced numarul. Scrieti un program care citeste repetat de la intrare siruri de caractere si, folosind functia anterioara, afiseaza valoarea numerica a sirului citit. Programul se termina prin introducerea numarului 0. n caz ca un sir de caractere nu respecta diagrama sintactica, programul se termina cu un mesaj de eroare care specifica exact ce neconcordanta cu diagrama a avut loc.

\begin{figure}\begin{center} \epsfig{file=diagrama.eps, width=\textwidth} \end{center} \end{figure}

Figura 4.1: Diagrama sintactica a unui numar real


next up previous contents

Next: Prelucrarea fisierelor Up: Caractere, siruri de caractere. Previous: Probleme rezolvate Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node29.html [22.07.2003 16:18:09]

Prelucrarea fisierelor

next

up

previous

contents

Next: Tratarea fisierelor n C Up: carte Previous: Probleme propuse Cuprins

Prelucrarea fisierelor
Subsections q Tratarea fisierelor n C
q

Operatii asupra fisierelor


r r r r r

Deschiderea/nchiderea fisierelor Alte functii referitoare la fisiere Citirea si modificarea indicatorului de pozitie Transferul caracterelor si al sirurilor de caractere Citirea si scrierea cu format

q q

Probleme rezolvate Probleme propuse

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node30.html [22.07.2003 16:18:10]

Tratarea fisierelor n C

next

up

previous

contents

Next: Operatii asupra fisierelor Up: Prelucrarea fisierelor Previous: Prelucrarea fisierelor Cuprins

Tratarea fisierelor n C
n C, operatiile de intrare/iesire au la baza conceptul de stream. Un stream (flux) este o interfata logica ntre diverse dispozitive ale unui calculator. n mod uzual, un stream este o interfata logica pentru un fisier. Conceptul de fisier, n C este mai larg dect n alte limbaje de programare, el incluznd un fisier pe suport permanent (hard-disk, CD, etc.), ecranul, tastatura, diverse porturi, s.a.m.d. Tratarea unitara a tuturor operatiilor de intrare/iesire prin intermediul stream-urilor asigura o mai mare portabilitate limbajului C, ct si o transparenta pentru programator fata de arhitectura masinii pe care lucreaza. Un stream este asociat unui fisier printr-o operatie de deschidere (open), asocierea distrugndu-se prin operatia de nchidere a stream-ului (close). Exista doua tipuri de stream-uri: text si binare. Ceea ce diferenteaza cele doua tipuri este existenta unor translatii n cazul stream-urile text. De exemplu, caraterul newline (sfrsit de linie) cnd este ntlnit este convertit ntr-o secventa de doua caractere carriage-return/linefeed (ntoarcere/deplasare rnd). Din acest motiv, poate sa apara o diferenta ntre ceea ce este trimis la stream si ceea ce este scris fizic n fisier. n cazul stream-urilor binare, exista o perfecta concordanta ntre stream si fisierul fizic, astfel stream-urile binare pot fi folosite cu orice tip de date, pe cnd n cazul celor de tip text exista anumite limitari. Exista sisteme de operare (cum ar fi Unix-ul) n care nu exista stream-uri de tip text. La deschiderea unui stream, se asociaza acestuia un pointer la o structura de tip FILE (fisier). Aceasta structura, definita n stdio.h, retine diverse informatii legate de fisierul deschis (dimensiune, pozitia curenta a cursorului n fisier, moduri de acces). Prin operatia de deschidere, se rezerva automat si o zona tampon pentru transferul datelor.
http://labs.cs.utt.ro/labs/pc/html/node31.html (1 of 2) [22.07.2003 16:18:10]

Tratarea fisierelor n C

next

up

previous

contents

Next: Operatii asupra fisierelor Up: Prelucrarea fisierelor Previous: Prelucrarea fisierelor Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node31.html (2 of 2) [22.07.2003 16:18:10]

Operatii asupra fisierelor

next

up

previous

contents

Next: Deschiderea/nchiderea fisierelor Up: Prelucrarea fisierelor Previous: Tratarea fisierelor n C Cuprins

Operatii asupra fisierelor


Subsections q Deschiderea/nchiderea fisierelor
q q q q

Alte functii referitoare la fisiere Citirea si modificarea indicatorului de pozitie Transferul caracterelor si al sirurilor de caractere Citirea si scrierea cu format

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node32.html [22.07.2003 16:18:10]

Deschiderea/nchiderea fisierelor

next

up

previous

contents

Next: Alte functii referitoare la Up: Operatii asupra fisierelor Previous: Operatii asupra fisierelor Cuprins

Deschiderea/nchiderea fisierelor
La lansarea n executie a unui program se deschid trei fisiere cu canale de tip text:
stdin - pentru intrarea standard, asociat implicit tastaturii; stdout - pentru iesirea standard, asociat implicit ecranului monitorului; stderr - pentru iesirea standard pentru erori, asociat implicit ecranului monitorului.

Orice alte fisiere utilizate n program trebuie deschise n mod explicit cu functia fopen. FILE *fopen(const char *filename, const char *mode); Prin aceasta se deschide fisierul cu numele filename (care poate include si specificarea caii), i se asociaza un stream si se returneaza un pointer catre structura FILE creata sau NULL, daca fisierul nu a putut fi deschis. Acest pointer este folosit n operatiile ulterioare asupra fisierului. Parametrul mode este un sir de caractere care poate avea urmatoarele valori:
r deschide pentru citire; w deschide pentru scriere (daca fisierul exista anterior el va fi sters); a deschide pentru adaugare (scriere la sfrsitul fisierului); r+ deschide un fisier existent pentru actualizare (citire si scriere); w+ deschide un fisier nou pentru actualizare;

http://labs.cs.utt.ro/labs/pc/html/node33.html (1 of 2) [22.07.2003 16:18:10]

Deschiderea/nchiderea fisierelor

a+ deschide pentru actualizare la sfrsitul fisierului.

La sfrsitul sirului de caractere reprezentnd modul de acces se mai poate adauga optional sufixul:
t pentru prelucrare n mod text (implicit); b pentru prelucrare n mod binar.

nchiderea unui fisier deschis cu fopen se realizeaza cu functia fclose: int fclose(FILE *fp); unde fp este pointerul returnat de functia fopen. Prin nchiderea fisierului se elibereaza si zona tampon alocata acestuia. Functia returneaza valoarea 0 daca operatia de nchidere s-a efectuat cu succes, respectiv EOF (-1) n caz de eroare.
next up previous contents

Next: Alte functii referitoare la Up: Operatii asupra fisierelor Previous: Operatii asupra fisierelor Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node33.html (2 of 2) [22.07.2003 16:18:10]

Alte functii referitoare la fisiere

next

up

previous

contents

Next: Citirea si modificarea indicatorului Up: Operatii asupra fisierelor Previous: Deschiderea/nchiderea fisierelor Cuprins

Alte functii referitoare la fisiere


int feof(FILE *fp); returneaza o valoare nenula daca s-a ntlnit sfrsitul de fisier la ultima operatie de intrare si 0 n caz contrar.

int fflush(FILE *fp); determina golirea buffer-ului unui fisier.


Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node34.html [22.07.2003 16:18:11]

Citirea si modificarea indicatorului de pozitie

next

up

previous

contents

Next: Transferul caracterelor si al Up: Operatii asupra fisierelor Previous: Alte functii referitoare la Cuprins

Citirea si modificarea indicatorului de pozitie


int fgetpos(FILE *fp, long int *poz); nscrie valoarea indicatorului de pozitie n variabila adresata prin pointerul poz si returneaza 0 n caz de succes.

int fsetpos(FILE *fp, const long int *poz); atribuie indicatorului valoarea variabilei indicata prin pointerul poz si returneaza valoarea 0 n caz de succes.

int fseek(FILE *fp, long offset, int whence); repozitioneaza indicatorul fisierului la valoarea whence+offset; whence poate avea urmatoarele valori:
SEEK_SET = 0 - nceput de fisier SEEK_CUR = 1 - pozitie curenta SEEK_END = 2 - sfrsit de fisier

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node35.html [22.07.2003 16:18:11]

Transferul caracterelor si al sirurilor de caractere

next

up

previous

contents

Next: Citirea si scrierea cu Up: Operatii asupra fisierelor Previous: Citirea si modificarea indicatorului Cuprins

Transferul caracterelor si al sirurilor de caractere


int getc(FILE *fp); returneaza urmatorul caracter citit din fisierul fp sau EOF daca se ntlneste sfrsitul fisierului.

int ungetc(int c, FILE *fp); repune caracterul c n zona tampon corespunzatoare fisierului de intrare fp.

int putc(int c, FILE *fp); nscrie caracterul c n fisierul fp; n caz de eroare returneaza EOF.

char *fgets(char *s, int n, FILE *fp); citeste maxim n-1 caractere din fisierul fp sau pna la '' $\backslash$ n'' inclusiv, le depune n s, adauga la sfrsit '' $\backslash$ 0'' si returneaza adresa sirului s; n caz de eroare ntoarce valoarea NULL.

http://labs.cs.utt.ro/labs/pc/html/node36.html (1 of 2) [22.07.2003 16:18:11]

Transferul caracterelor si al sirurilor de caractere

int fputs(const char *s, FILE *fp); scrie sirul s n fisier, fara caracterul '' $\backslash$ de eroare ntoarce valoarea EOF. 0''; n caz

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node36.html (2 of 2) [22.07.2003 16:18:11]

Citirea si scrierea cu format

next

up

previous

contents

Next: Probleme rezolvate Up: Operatii asupra fisierelor Previous: Transferul caracterelor si al Cuprins

Citirea si scrierea cu format


int fscanf(FILE *fp, const char *format [, adresa, ...]); citeste date din fisierul fp, conform formatului specificat; returneaza numarul cmpurilor de intrare pentru care citirea, conversia si memorarea s-au efectuat corect sau EOF daca s-a ntlnit sfrsitul fisierului.

int fprintf(FILE *fp, const char *format [, argum...]); scrie date, conform formatului n fisierul fp; returneaza numarul de octeti transferati sau EOF n caz de eroare.
Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node37.html [22.07.2003 16:18:11]

Probleme rezolvate

next

up

previous

contents

Next: Probleme propuse Up: Prelucrarea fisierelor Previous: Citirea si scrierea cu Cuprins

Probleme rezolvate
1. Sa se scrie un program care afiseaza lungimea celei mai lungi linii din fisierul text TEST: /*------------------------------------------------*/ /* */ /* afiseaza lungimea lg_max a celei mai lungi */ /* linii a fisierului */ /* */ /*------------------------------------------------*/ #include <stdio.h> void main(void) { FILE *f; char c; int lg_max, lg_curenta; lg_max=lg_curenta=0; if (!(f=fopen("TEST", "r"))) { puts("Fisierul TEST nu poate fi deschis"); return; } while ((c=getc(f))!=EOF) if (c=='\n') { if (lg_max<lg_curenta) lg_max = lg_curenta; lg_curenta = 0; } else lg_curenta++;

http://labs.cs.utt.ro/labs/pc/html/node38.html (1 of 6) [22.07.2003 16:18:12]

Probleme rezolvate

fclose(f); printf ("\nLinia cea mai lunga are lungimea %d", lg_max); } 2. Sa se scrie un program care copiaza un fisier binar sursa n alt fisier binar destinatie. /*---------------------------------------*/ /* */ /* copiaza continutul unui fisier binar */ /* in alt fisier binar */ /* */ /----------------------------------------*/ #include <stdio.h> void main(void) { FILE *fs, *fd; char c; if ((fs=fopen("sursa", "rb"))==NULL) { fprintf(stderr, "Fisierul sursa nu poate fi deschis\n"); return; } if ((fd=fopen("dest", "wb"))==NULL) { fprintf(stderr, "Fisierul dest nu poate fi deschis\n"); return; } c=getc(fs); while (!feof(fs)) { putc(c, fd); c=getc(fs); } fclose(fs); fclose(fd); } 3. Sa se realizeze un program care pastreaza evidenta unei grupe de studenti. Datele despre studenti (numele, vrsta, media) se pastreaza sub forma unui fisier text. Programul trebuie sa permita urmatoarele optiuni: r a, A - adaugarea unui nou student n fisier;
http://labs.cs.utt.ro/labs/pc/html/node38.html (2 of 6) [22.07.2003 16:18:12]

Probleme rezolvate

r r r

l, L - listarea datelor tuturor studentilor; m, M - modificarea datelor unui student; x, X - terminarea programului;

/*----------------------------------------------*/ /* */ /* evidenta unei grupe de studenti */ /* */ /*----------------------------------------------*/ #include <stdio.h> #include <conio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> #define LNUME 20 /* lungimea maxima a numelor typedef struct { char nume[LNUME]; int varsta; float medie; } student; char fisier[13]; /* numele fisierului */

*/

/*---------------------------------------------------*/ /* */ /* adauga datele unui nou student in fisier */ /* */ /----------------------------------------------------*/ void AdaugStudent(void) { FILE *f; student s; if (!(f=fopen(fisier, "at"))) { puts("\nFisierul nu poate fi deschis."); return; } printf("\nNumele, varsta, media: "); scanf("%s %d %f", s.nume, &s.varsta, &s.medie);
http://labs.cs.utt.ro/labs/pc/html/node38.html (3 of 6) [22.07.2003 16:18:12]

Probleme rezolvate

fflush(stdin); /* se goleste buffer-ul tastaturii */ fprintf(f, "%20s %2d %6.2f\n", s.nume, s.varsta, s.medie); fclose(f); } /*-------------------------------------------*/ /* */ /* afiseaza datele tuturor studentilor */ /* */ /*--------------------------------------------*/ void ListezStudenti(void) { FILE *f; student s; if (!(f=fopen(fisier, "rt"))) { puts("\nFisierul nu poate fi deschis."); return; } while(fscanf(f,"%s %d %f",s.nume,&s.varsta,&s.medie)!=EOF) printf("\n%-20s %-2d %-6.2f\n",s.nume,s.varsta,s.medie); fclose(f); }

/*-----------------------------------------------*/ /* */ /* modifica datele studentului */ /* al carui nume se citeste in variabila n */ /* */ /*-----------------------------------------------*/ void ModificStudent(void) { int gasit=0; FILE *f; student s; char n[LNUME]; /* numele studentului ale */ /* carui date se vor modifica */ if (!(f=fopen(fisier, "r+t")))
http://labs.cs.utt.ro/labs/pc/html/node38.html (4 of 6) [22.07.2003 16:18:12]

Probleme rezolvate

{ puts("Fisierul nu poate fi deschis."); return; } printf("\nNume student: "); fgets(n, LNUME, stdin); while(fscanf(f,"%s %d %f",s.nume,&s.varsta,&s.medie)!=EOF) if (!strcmp(n,s.nume)) { /* studentul a fost gasit, se afiseaza datele sale */ printf("%-20s %-2d %-6.2f\n",s.nume,s.varsta,s.medie); gasit=1; break; } if (!gasit) printf("\nStudentul %s nu exista in fisier.", n); else { printf("\nNumele, varsta, media: "); scanf("%s %d %f", s.nume, &s.varsta, &s.medie); fflush(stdin); /* pozitionare la inceputul inregistrarii */ fseek(f, -30, SEEK_CUR); fprintf(f,"%20s %2d %6.2f\n", s.nume, s.varsta, s.medie); } fclose(f); } /*----------------------------------*/ /* */ /* afiseaza meniul programului */ /* */ /*----------------------------------*/ void AfisezMeniu(void) { puts("\na, A ---- adaugare student"); puts("m, M ---- modificare date student"); puts("l, L ---- listare studenti"); puts("x, X ---- parasire program"); }
http://labs.cs.utt.ro/labs/pc/html/node38.html (5 of 6) [22.07.2003 16:18:12]

Probleme rezolvate

void main(void) { char opt; puts("Nume fisier: "); fgets(fisier, 13, stdin); while (1) { AfisezMeniu(); opt=tolower(getche()); switch(opt) { case 'a': AdaugStudent(); break; case 'm': ModificStudent(); break; case 'l': ListezStudenti(); break; case 'x': exit(0); default: puts("Comanda eronata\n"); } } } Se observa ca cele trei operatii principale efectuate asupra fisierului: adaugare, listare si modificare sunt implementate n trei functii distincte. Functia adauga nscrie n fisier datele unui student sub forma unei nregistrari de 30 de octeti (20 pentru nume, 1 spatiu, 2 pentru vrsta, 1 spatiu, 6 pentru medie). Acest lucru este folosit n functia modifica cnd se repozitioneaza indicatorul de pozitie n fisier la nceputul nregistrarii care urmeaza a fi modificata.
next up previous contents

Next: Probleme propuse Up: Prelucrarea fisierelor Previous: Citirea si scrierea cu Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node38.html (6 of 6) [22.07.2003 16:18:12]

Probleme propuse

next

up

previous

contents

Next: Compilarea independenta a fisierelor Up: Prelucrarea fisierelor Previous: Probleme rezolvate Cuprins

Probleme propuse
1. Se considera doua fisiere care contin numere ntregi n ordine strict crescatoare, cte un numar pe o linie. Se cere sa se creeze un al treilea fisier, obtinut prin interclasarea primelor doua. Daca un numar apare n ambele fisiere de intrare, el va aparea o singura data n fisierul rezultat. De exemplu: fisier1: -1 0 4 5 67 123 678 2677 fisier2: 8 12 123 1234 1235 1236 7890 7892 fisier3 (rezultat): -1 0 4 5 8 12 67 123 678 1234 1235 1236 2677 7890 7892 2. Scrieti un program care concateneaza doua fisiere, FIS1 si FIS2 n fisierul FIS3. 3. Dintr-un fisier de intrare se citeste o propozitie terminata cu punct. Propozitia este formata din cuvinte ce contin doar litere mari. Cuvintele sunt separate prin unul sau mai multi separatori din t'','' $\backslash$ca propozitia are cel mult 30 de cuvinte, sa se afiseze grupurile de n''. Stiind multimea '' '','' $\backslash$ cuvinte n care fiecare membru reprezinta anagrama altui membru din grup. Un grup va contine numarul maxim de membri, iar membrii sunt distincti.
next up previous contents

Next: Compilarea independenta a fisierelor Up: Prelucrarea fisierelor Previous: Probleme rezolvate Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node39.html [22.07.2003 16:18:12]

Compilarea independenta a fisierelor

next

up

previous

contents

Next: Etapele compilarii unui program Up: carte Previous: Probleme propuse Cuprins

Compilarea independenta a fisierelor


Subsections q Etapele compilarii unui program C
r r r

Preprocesarea Compilarea Link-editare

Structurarea programelor C pe mai multe fisiere


r r r

De ce mai multe fisiere ? Reguli de structurare pe mai multe fisiere Lucrul n modul "project"

Tipuri de date abstracte


r r

Definirea tipului abstract stiva Evaluarea unei expresii n notatie poloneza

Probleme propuse

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node40.html [22.07.2003 16:18:12]

Etapele compilarii unui program C

next

up

previous

contents

Next: Preprocesarea Up: Compilarea independenta a fisierelor Previous: Compilarea independenta a fisierelor Cuprins

Etapele compilarii unui program C


Pentru a putea ntelege modul n care sunt compilate programele n C (indiferent de dimensiunea lor), vom trece n revista principalele etape care au loc pna la obtinerea codului final executabil. Aceste etape sunt transparente pentru programator n majoritatea compilatoarelor sau mediilor integrate, nefiind necesara activarea lor separata. n unele situatii nsa (de obicei, pentru programele structurate pe mai multe fisiere), anumite etape se pot desfasura independent.
Subsections q Preprocesarea
q q

Compilarea Link-editare

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node41.html [22.07.2003 16:18:13]

Preprocesarea

next

up

previous

contents

Next: Compilarea Up: Etapele compilarii unui program Previous: Etapele compilarii unui program Cuprins

Preprocesarea
Preprocesarea este prima faza n obtinerea codului executabil. n aceasta etapa au loc anumite transformari asupra codului sursa, rezultnd un fisier intermediar tot n limbajul C. Principalele operatii care au loc n aceasta faza sunt prelucrarea directivelor de preprocesare (liniile care ncep cu caracterul #): expandarea macrodefinitiilor si includerea fisierelor. Expandarea macrodefinitiilor presupune nlocuirea textuala a macro-ului cu valoarea asociata. De exemplu, pentru definitia #define MAX 10 se va nlocui n textul sursa fiecare aparitie a sirului MAX cu numarul 10. n faza de includere a fisierelor, toate fisierele specificate de directivele #include vor fi incluse textual n codul sursa al programului. n paragrafele urmatoare vor fi prezentate anumite reguli generale referitoare la continutul fisierelor incluse.
Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node42.html [22.07.2003 16:18:13]

Compilarea

next

up

previous

contents

Next: Link-editare Up: Etapele compilarii unui program Previous: Preprocesarea Cuprins

Compilarea
n faza de compilare, codul sursa al programului este transformat n cod obiect (un cod intermediar specific compilatorului de C). Dupa compilare, se creeaza un fisier cu acelasi nume, dar cu extensia .obj. n aceasta faza sunt semnalate posibilele erori sintactice din codul sursa.
Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node43.html [22.07.2003 16:18:13]

Link-editare

next

up

previous

contents

Next: Structurarea programelor C pe Up: Etapele compilarii unui program Previous: Compilarea Cuprins

Link-editare
Linkeditare (editarea legaturilor) "leaga" ntre ele mai multe fisiere obiect si creaza fisierul executabil. Aceasta faza este importanta pentru programe structurate pe mai multe fisiere, dar si pentru programe constnd dintr-un singur fisier (pentru legarea fisierelor obiect ale bibliotecilor de functii specificate prin #include).
Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node44.html [22.07.2003 16:18:13]

Structurarea programelor C pe mai multe fisiere

next

up

previous

contents

Next: De ce mai multe Up: Compilarea independenta a fisierelor Previous: Link-editare Cuprins

Structurarea programelor C pe mai multe fisiere


Subsections q De ce mai multe fisiere ?
q q

Reguli de structurare pe mai multe fisiere Lucrul n modul "project"

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node45.html [22.07.2003 16:18:13]

De ce mai multe fisiere ?

next

up

previous

contents

Next: Reguli de structurare pe Up: Structurarea programelor C pe Previous: Structurarea programelor C pe Cuprins

De ce mai multe fisiere ?


Utilitatea structurarii programelor C mari pe mai multe fisiere este explicata de urmatoarele avantaje:
q

n cazul programelor mari, daca tot programul ar fi scris ntr-un singur fisier, programul ar fi foarte greu de urmarit si timpul de compilare ar fi foarte mare, nefiind folosita facilitatea de compilare independenta. Acest aspect este foarte util n faza de corectare a erorilor sintactice si semantice, cnd doar fisierul eronat trebuie recompilat, pentru restul fisierelor trebuind doar linkeditate fisierele obiect. Daca ntregul program este plasat ntr-un singur fisier atunci orice modificare sau corectie impune recompilarea ntregului program. Structurarea programelor pe mai multe fisiere permite simularea mecanismului de ncapsulare a datelor. Variabilele si functiile avnd clasa de memorare static pot fi accesate doar n cadrul fisierului n care ele au fost definite. Variabilele si functiile declarate cu clasa de memorare extern sunt definite ntr-un alt fisier dect cel curent, dar ele pot fi accesate n fisierul curent. Astfel fisierele apar n C ca un mecanism de control al vizibilitatii obiectelor.
up previous contents

next

Next: Reguli de structurare pe Up: Structurarea programelor C pe Previous: Structurarea programelor C pe Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node46.html [22.07.2003 16:18:14]

Reguli de structurare pe mai multe fisiere

next

up

previous

contents

Next: Lucrul n modul "project" Up: Structurarea programelor C pe Previous: De ce mai multe Cuprins

Reguli de structurare pe mai multe fisiere


Vom prezenta n continuare anumite reguli general acceptate pentru structurarea unui program pe mai multe fisiere. n general, se alege un fisier care va fi fisierul principal, n acest fisier fiind implementata functia main(); n celelalte fisiere nu va mai fi implementata aceasta functie. n fisierul antet se vor trece definitia tipurilor de date folosite si declaratiile (prototipurile) functiilor. Nu se vor trece n fisierul antet declaratii de variabile si implementari de functii (este perfect "legal" sa apara declaratii de variabile si implementari de functii, fisierul antet fiind tratat ca orice fisier C, dar aceasta maniera de programare distruge conceptul de modularizare a programelor si de ncapsulare a datelor). n fisierul auxiliar antetului (cu acelasi nume si extensia .c) se va trece implementarea functiilor definite n fisierul antet. n acest fisier nu se va implementa functia main(). Att fisierul principal ct si cel auxiliar vor include fisirul antet. Astfel se realizeaza ncapsularea tipurilor de date si a functiilor n fisiere separate. Aceasta maniera de structurare a programelor este folosita n scrierea unor biblioteci de functii. Programatorul care doreste sa furnizeze o biblioteca de functii va scrie fisierul antet si fisierul auxiliar antetului, care va include fisierul antet. n fisierul antet vor fi trecute functiile si tipurile de date oferite de biblioteca, iar n fisierul auxiliar vor fi implementate aceste functii. Aceste fisiere se compileaza mpreuna, rezultnd un fisier obiect (nu executabil), iar biblioteca va oferi acces la aceste functii prin includerea n orice program a fisierului antet si prin linkeditarea cu fisierul obiect. Programatorul acestei biblioteci nu va oferi spre utilizare dect fisierul antet si fisierul obiect, astfel maniera de implementare a functiilor oferite de biblioteca ramne invizibila pentru utilizatorul bibliotecii.

http://labs.cs.utt.ro/labs/pc/html/node47.html (1 of 4) [22.07.2003 16:18:14]

Reguli de structurare pe mai multe fisiere

Pentru a exemplifica aceste reguli, consideram un program pentru calculul sumei a doua numere complexe. Pentru aceasta, se va defini o functie suma. De asemenea, vor fi definite si doua functii pentru citirea, respectiv afisarea numerelor complexe. Programul va fi structurat pe trei fisiere: calcule.c - care contine functia main, operatii.h - fisierul antet unde sunt declarate principalele tipuri de date si functii si operatii.c - implementarea functiilor. Fisierele sursa sunt prezentate n continuare.

Fisierul calcule.c
#include <stdio.h> #include "operatii.h" void main(void) { complex x,y; printf("introduceti primul numar\n"); x=citire(); printf("introduceti al 2-lea numar\n"); y=citire(); printf("\nsuma: "); afisare(suma(x,y)); printf("\n"); }

Fisierul operatii.h
/* definire tip de date complex */ typedef struct nr_complex { double p_real; double p_imag; } complex; /* prototipuri functii exportate */
http://labs.cs.utt.ro/labs/pc/html/node47.html (2 of 4) [22.07.2003 16:18:14]

Reguli de structurare pe mai multe fisiere

complex citire(void); void afisare(complex); complex suma(complex,complex);

Fisierul operatii.c
#include <stdio.h> #include "operatii.h" /* implementare functii exportate */ complex citire(void) { complex nr; printf("Partea reala: "); scanf("%lf",&nr.p_real); printf("Partea imaginara: "); scanf("%lf",&nr.p_imag); return nr; }

void afisare(complex nr) { if (nr.p_imag<0) printf("%lf%lfi\n",nr.p_real,nr.p_imag); else printf("%lf+%lfi\n",nr.p_real,nr.p_imag); } complex suma(complex nr1, complex nr2) { complex rezult; rezult.p_real=nr1.p_real + nr2.p_real; rezult.p_imag=nr1.p_imag + nr2.p_imag; return rezult; }
next up previous contents

Next: Lucrul n modul "project" Up: Structurarea programelor C pe Previous: De ce mai multe

http://labs.cs.utt.ro/labs/pc/html/node47.html (3 of 4) [22.07.2003 16:18:14]

Reguli de structurare pe mai multe fisiere

Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node47.html (4 of 4) [22.07.2003 16:18:14]

Lucrul n modul "project"

next

up

previous

contents

Next: Tipuri de date abstracte Up: Structurarea programelor C pe Previous: Reguli de structurare pe Cuprins

Lucrul n modul "project"


Pentru a compila fisierele si a le "linkedita" mpreuna folosim modul project. n mediul Borland C acest lucru presupune urmatorii pasi:
q q q

Selectam optiunea Project si apoi Open project. Fixam numele fisierului project (care are extensia .prj). Cu ajutorul butonul Ins precizam fisierele care trebuie compilate si apoi linkeditate mpreuna. Fisierele antet nu se includ n project. Cu butonul Del fisierul selectat este eliminat din grupul celor care sunt compilate si linkeditate mpreuna. Selectam optiunea pentru construirea programului executabil (din meniul Compile, optiunea Build all. Mediul Borland C compileaza automat toate fisierele enumerate si le linkediteaza mpreuna. Prin selectarea optiunii Project si apoi a celei Close project, se ncheie lucrul n modul Project.

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node48.html [22.07.2003 16:18:14]

Tipuri de date abstracte

next

up

previous

contents

Next: Definirea tipului abstract stiva Up: Compilarea independenta a fisierelor Previous: Lucrul n modul "project" Cuprins

Tipuri de date abstracte


Tipul de date abstract este o entitate manipulata doar prin operatiile ce definesc acel tip. Avantajele utilizarii tipurilor de date abstracte sunt:
1. Programele devin independente de modul de reprezentare a datelor. Modul de reprezentare poate fi modificat, fara nsa a afecta restul programului (de exemplu, o multime poate fi implementata printr-un tablou sau printr-o lista ordonata, dar partea de program ce foloseste operatorii tipului abstract ramne neschimbata). 2. Se previne violarea accidentala a datelor. Utilizatorul tipului abstract este fortat sa manipuleze datele doar prin intermediul operatorilor ce compun tipul abstract, astfel reducndu-se riscul unei distrugeri a datelor.

Dupa cum este exemplificat n continuare, n C tipurile abstracte sunt realizate folosind fisiere. Acest mod are desigur propriile sale limitari. Mentionam doar doua din ele: nu se pot defini tablouri de tipuri abstracte si nu se pot transmite parametri avnd ca si tip un tip abstract.
Subsections q Definirea tipului abstract stiva
q

Evaluarea unei expresii n notatie poloneza


up previous contents

next

Next: Definirea tipului abstract stiva Up: Compilarea independenta a fisierelor Previous: Lucrul n modul "project" Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node49.html [22.07.2003 16:18:15]

Definirea tipului abstract stiva

next

up

previous

contents

Next: Evaluarea unei expresii n Up: Tipuri de date abstracte Previous: Tipuri de date abstracte Cuprins

Definirea tipului abstract stiva


Stiva este un tip special de lista n care toate insertiile si suprimarile de noduri au loc la un singur capat. Acest capat se numeste vrful stivei. Tipul abstract stiva pe care l definim contine urmatorii operatori:
1. 2. 3. 4. 5. 6. Initializarea stivei. Verificarea faptului ca stiva e plina. Verificarea faptului ca stiva e goala. Introducerea unui element n vrful stivei. Eliminarea elementului din vrful stivei. Furnizarea elementului din vrful stivei fara a-l elimina.

n exemplul nostru, stiva este materializata printr-un tablou de numere reale, numit stiva, iar vrful stivei este indicat de variabila ind_top. Dimensiunea stivei este egala cu MAX, valoare care este lungimea tabloului. Toate declaratiile si definitiile care urmeaza mai jos trebuie sa fie continute ntr-un singur fisier. Pentru a "ascunde" de utilizator detaliile de implementare a stivei, att stiva ct si ind_top sunt definite cu clasa de memorare static. Astfel domeniul lor de vizibilitate se restrnge la fisierul curent si aceste variabile nu pot fi accesate dintr-un alt fisier. Functiile au implicit clasa de memorare extern. Prin urmare, ele pot fi apelate din alte fisiere, iar toate operatiile asupra stivei sunt realizate doar prin intermediul lor.
static double stiva[MAX]; /* stiva */ static int ind_top; /* varful stivei */

http://labs.cs.utt.ro/labs/pc/html/node50.html (1 of 4) [22.07.2003 16:18:15]

Definirea tipului abstract stiva

Operatorii sunt implementati astfel:

Initializarea stivei:
void init(void) { int i; for (i=0; i<MAX; i++) stiva[i]=0; /* toate elementele devin 0 */ ind_top=-1; /* varful stivei indica primul element ocupat*/ } /* init */

Verificarea faptului ca stiva este plina:


int plin(void) { return ind_top==MAX-1; } /* plin */

Stiva este plina atunci cnd vrful stivei indica spre ultimul element din stiva (cel de indice MAX-1).

Verificarea faptului ca stiva este goala:


int gol(void) { return ind_top==-1; } /* gol */

http://labs.cs.utt.ro/labs/pc/html/node50.html (2 of 4) [22.07.2003 16:18:15]

Definirea tipului abstract stiva

Functia gol verifica daca stiva este goala. Cnd indicele stivei este egal cu -1, stiva nu contine nici o valoare si gol returneaza 1. Daca ind_top $>$-1 atunci stiva contine cel putin o valoare, astfel ca gol returneaza 0.

Introducerea unui element n vrful stivei:


void push(double nr) { if (plin()) /* daca stiva este plina */ { printf("Eroare: stiva este plina\n"); exit(1); } stiva[++ind_top] = nr; /* noul element este introdus in varful stivei */ } /* push */

Rutina push introduce n vrful stivei numarul transmis prin parametrul double nr. Daca stiva este plina atunci se afiseaza un mesaj de eroare si executia programului este terminata. n caz contrar, se incrementeaza vrful stivei ind_top, dupa care noul element este memorat n vrful stivei.

Eliminarea elementului din vrful stivei:


void pop(void) { if (gol() ) /* daca stiva este goala */ { printf("Eroare: stiva este goala\n"); exit(1); } ind_top--; /* decrementeaza varful stivei */ } /* pop */

http://labs.cs.utt.ro/labs/pc/html/node50.html (3 of 4) [22.07.2003 16:18:15]

Definirea tipului abstract stiva

Rutina pop extrage elementul din vrful stivei fara a-l returna. Daca stiva este goala atunci pop afiseaza un mesaj de eroare si executia programului este ncheiata. n caz contrar, vrful stivei este decrementat.

Furnizarea elementului din vrful stivei (fara a-l elimina):


double top(void) { if (gol()) /* daca stiva este goala */ { printf("Eroare: stiva este goala\n"); exit(1); } return stiva[ind_top]; /* returneaza elementul din varful stivei */ } /* top */

Functia top returneaza valoarea elementului din vrful stivei, nsa fara a-l extrage. Daca stiva este goala atunci se afiseaza un mesaj de eroare si executia programului este ncheiata. n caz contrar, top returneaza valoarea din vrful stivei.
next up previous contents

Next: Evaluarea unei expresii n Up: Tipuri de date abstracte Previous: Tipuri de date abstracte Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node50.html (4 of 4) [22.07.2003 16:18:15]

Evaluarea unei expresii n notatie poloneza

next

up

previous

contents

Next: Probleme propuse Up: Tipuri de date abstracte Previous: Definirea tipului abstract stiva Cuprins

Evaluarea unei expresii n notatie poloneza


Notatia poloneza (sau postfix) este un mod de scriere a expresiilor, n care ordinea operatorilor si a operanzilor este schimbata fata de cea dintr-o expresie uzuala. n notatia uzuala (numita si infix) o expresie are forma: operand operator operand n notatia postfix (poloneza) expresia este scrisa sub forma: operand operand operator De exemplu: a + b devine n notatie poloneza a b + (a - b) * c devine a b - c * a - b * (c + d) devine a b c d + * Avantajul notatiei poloneze este acela ca indica ordinea corecta a evaluarii operatiilor fara a utiliza paranteze. Astfel, o expresie poloneza poate fi evaluata printr-o singura parcurgere a sa. Pentru evaluarea unei expresii n notatie poloneza se poate folosi o stiva de valori reale. Ori de cte ori ntlnim n expresie un operand, valoarea lui este introdusa n stiva. Daca ntlnim un operator atunci se extrag doua valori din vrful stivei, care sunt, de fapt, cei doi operanzi, aplicam operatorul asupra valorilor extrase si rezultatul l depunem n stiva. n momentul n care s-a terminat parcurgerea expresiei, rezultatul final al expresiei este n vrful stivei (si stiva contine doar aceasta valoare).
next up previous contents

http://labs.cs.utt.ro/labs/pc/html/node51.html (1 of 2) [22.07.2003 16:18:15]

Evaluarea unei expresii n notatie poloneza

Next: Probleme propuse Up: Tipuri de date abstracte Previous: Definirea tipului abstract stiva Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node51.html (2 of 2) [22.07.2003 16:18:15]

Probleme propuse

next

up

previous

contents

Next: Pointeri Up: Compilarea independenta a fisierelor Previous: Evaluarea unei expresii n Cuprins

Probleme propuse
1. Se citeste o expresie n notatie poloneza, care contine ca operanzi constante reale, iar ca operatori +, -, * si /. Fiecare expresie apare pe o linie separata. Dupa ce s-a citit expresia, ea este evaluata si rezultatul ei este tiparit. Programul citeste expresii si le evalueaza pna la citirea unui 0 singular pe o linie. Observatii: r Ca stiva se foloseste tipul abstract stiva cu valori reale, definit anterior. r Se va defini functia getop (char *s), care citeste ncepnd cu pozitia curenta a liniei de intrare si detecteaza urmatorul operand sau operator. getop sare peste spatii si caracterele tab. Pentru un operand, functia returneaza constanta NUMAR si, n parametrul s, adresa de nceput a sirului format din cifrele numarului. Pentru un operator, getop returneaza caracterul citit, iar n parametrul s adresa de nceput a sirului format din acel caracter. r Programul va fi mpartit n trei fisiere: stiva.h - contine definitiile constantelor si a tipurilor de date folosite n program, precum si declaratiile functiilor ce prelucreaza tipul abstract stiva. stiva.c - contine implementarea tipului abstract stiva. main.c - contine programul principal precum si functia getop. 2. Sa se realizeze un program C ce tine evidenta personalului unei companii de dimensiuni mici (aproximativ 50 de angajati). Informatia referitoare la angajati este pastrata ntr-un fisier si este folosita pentru initializarea bazei de date. Fisierul contine linii de forma: nume varsta adresa numar_matricol functie Cmpurile sunt separate printr-un spatiu si sunt siruri de caractere cu urmatoarele lungimi: nume 19, vrsta - 2, adresa - 11, numar_matricol - 5 si functie - 5. Functiile care trebuie implementate sunt: r IncarcBD(fis_bd) - ncarca baza de date din fisierul fis_bd. r SalvezBD(fis_bd) - salveaza baza de date din memorie n fisierul fis_bd. r AfisezBD() - afiseaza baza de date din memorie. r IntroducPersoana(n, v, a, nm, f) - introduce n baza de date o persoana si datele aferente ei. r CautPersoana(n) - verifica prezenta unei persoane n baza de date. r StergPersoana(n) - sterge din baza de date persoana cu numele n. r ModificPersoana(n) - permite modificarea informatiilor legate de persoana cu numele n. r RetVarsta(n) - returneaza vrsta persoanei cu numele n.
http://labs.cs.utt.ro/labs/pc/html/node52.html (1 of 2) [22.07.2003 16:18:16]

Probleme propuse

r r r

RetAdresa(n) - returneaza adresa persoanei cu numele n. RetNrMatricol(n) - returneaza numarul matricol al persoanei cu numele n. RetFunctia(n) - returneaza functia persoanei cu numele n.
previous contents

next

up

Next: Pointeri Up: Compilarea independenta a fisierelor Previous: Evaluarea unei expresii n Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node52.html (2 of 2) [22.07.2003 16:18:16]

Pointeri

next

up

previous

contents

Next: Introducere Up: carte Previous: Probleme propuse Cuprins

Pointeri
Subsections q Introducere
q q q q q q q

Operatii cu pointeri Pointeri ca argumente ale functiilor Pointeri si tablouri Pointeri la functii Folosirea neadecvata a operatiilor cu pointeri Problema rezolvata Problema propusa

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node53.html [22.07.2003 16:18:16]

Introducere

next

up

previous

contents

Next: Operatii cu pointeri Up: Pointeri Previous: Pointeri Cuprins

Introducere
Pointerii sunt variabile care contin adresa de memorie a unei alte variabile. Din aceste considerente, pointerii se numesc si variabile de adresa. Presupunem ca avem o variabila de tip ntreg numita entitate localizata la adresa de memorie 0x1000 (adresele sunt automat asigante variabilelor de catre compilator). Daca dorim sa referim aceasta variabila prin intermediul unui pointer entitate_ptr, atunci valoarea pointerului va fi 0x1000 (entitate_ptr = 0x1000), astfel spunem ca entitate_ptr "arata" spre variabila entitate (Pentru a se evita confuziile, se recomanda ca numele pointerilor sa aiba sufixul _ptr). Pentru a ntelege mai bine mecanismul de functionare a pointerilor, introducem o analogie pointeri - adrese postale, n care adresa de memorie este adresa postala, numele variabilei pointer este numele cladirii, iar entitatea referita este cladirea propriu-zisa. Aceasta analogie este prezentata n tabelul 7.1. Se observa ca doi pointeri diferiti (Fac_AC si Fac_ETC) au aceeasi valoare, indicnd spre aceeasi locatie, astfel referind aceeasi entitate.
Tabela 7.1: Analogie pointeri - adrese postale Variabila (nume pointer) Valoare adresa Fac_AC Fac_ETC Fac_Mate Entitate

Bd. V. Prvan 2 Cladire Electro Bd. V. Prvan 2 Cladire Electro Bd. V. Prvan 4 Cladire "U"

next

up

previous

contents

Next: Operatii cu pointeri Up: Pointeri Previous: Pointeri Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node54.html [22.07.2003 16:18:16]

Operatii cu pointeri

next

up

previous

contents

Next: Pointeri ca argumente ale Up: Pointeri Previous: Introducere Cuprins

Operatii cu pointeri
Pointerii se declara punnd un asterisc (*) n fata numelui variabilei:
int variabila; /*definire variabila intreg*/ int *variabila_ptr; /*definire pointer la un intreg */

Operatorii specifici pointerilor sunt: operatorul de dereferentiere * (pentru un pointer, returneaza entitatea referita de pointer) si operatorul de adresa & (pentru o entitate, returneaza adresa entitatii). Exemplul urmator explica folosirea acestor operatori. Variabila pointer obiect_ptr primeste adresa variabilei obiect, astfel obiect_ptr va indica spre zona de memorie unde este memorata variabila obiect. n ultima linie, se stocheaza valoarea 5 la zona de memorie spre care arata obiect_ptr, adica n variabila obiect.
int obiect; /* variabila de tip intreg */ int * obiect_ptr; /* pointer la un intreg */ obiect=4; obiect_ptr=&obiect; /* obiect_ptr va indica spre obiect */ printf("%d\n", *obiect_ptr); /* afiseaza valoarea spre care indica obiect_ptr */ *obiect_ptr=5; /* atribuie lui obiect valoarea 5 */

Folosirea gresita a operatorilor poate duce la functionari incorecte a programului sau, n cazul fericit, la erori semnalate de compilator:
*variabila este ilegal, prin aceasta se solicita entitatea referita de o variabila care nu este un pointer; &variabila_ptr este legal, dar "neobisnuit", se solicita adresa lui variabila_ptr, adica un pointer la un pointer.

http://labs.cs.utt.ro/labs/pc/html/node55.html (1 of 3) [22.07.2003 16:18:16]

Operatii cu pointeri

Mai multi pointeri pot indica spre aceeasi zona de memorie:


int obiect; int *obiect_ptr1; int *obiect_ptr2; obiect = 1; /* se atribuie valoarea 1 lui obiect */ obiect_ptr1 = &obiect; obiect_ptr2 = obiect_ptr1; /* obiect_ptr1 si obiect_ptr2 vor indica spre aceasi locatie de memorie */ printf("%d %d\n", *obiect_ptr1, *obiect_ptr2);

Un pointer special definit n limbajul C este pointerul NULL, care nu indica spre nimic (adresa spre care arata acest pointer este 0). Acest pointer este definit n stdio.h si n stdlib.h ca fiind (void *) 0, adica un pointer spre o locatie de tip void si care arata spre locatia de memorie 0. O situatie n care pointerii sunt utili este declararea structurilor recursive. n C nu se permite ca o structura sa contina cmpuri de tipul aceleiasi structuri. Aceasta restrictie poate fi evitata folosind pointeri la structuri, dupa cum se arata n exemplul urmator:
typedef struct pers { char nume[20]; int varsta; struct pers * urmator; } persoana; persoana *p;

Pentru a referi un cmp folosind un pointer spre o structura, se foloseste operatorul de dereferentiere: (*p).nume. Echivalent cu acest operator exista n C un alt operator pentru accesarea cmpurilor din structurile indicate de pointeri: p- $>$nume.
next up previous contents

Next: Pointeri ca argumente ale Up: Pointeri Previous: Introducere Cuprins Cristian Gavrila
http://labs.cs.utt.ro/labs/pc/html/node55.html (2 of 3) [22.07.2003 16:18:16]

Operatii cu pointeri

2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node55.html (3 of 3) [22.07.2003 16:18:16]

Pointeri ca argumente ale functiilor

next

up

previous

contents

Next: Pointeri si tablouri Up: Pointeri Previous: Operatii cu pointeri Cuprins

Pointeri ca argumente ale functiilor


n C, transmiterea parametrilor la functii se face "prin valoare", singurul rezultat vizibil n exterior fiind valoarea pe care o returneaza functia. Pentru ca o functie sa poata returna mai multe valori sau pentru ca modificarile asupra parametrilor sa se propage n exteriorul functiei, se folosesc pointeri. Acest concept este ilustrat de urmatoarea analogie: Presupunem ca se ntlnesc doua persoane A si B, A poate doar sa vorbeasca, iar B poate doar sa asculte. Cum poate B sa i transmita informatii lui A ? Simplu: A i spune: "Lasa raspunsul tau n cutia postala numarul x". Astfel, n momentul cnd se transmite un pointer catre o functie, functiei i se "comunica" adresa variabilei transmise ca parametru, putnd astfel face modificari asupra acelei variabile. n exemplul urmator se arata cum functia inc_contor va modifica valoarea variabilei contor.
#include <stdio.h> void inc_contor(int *contor_ptr) { (*contor_ptr)++; } void main(void) { int contor = 0; while (contor<10) inc_contor(&contor); printf("contor: %d\n",contor); }

http://labs.cs.utt.ro/labs/pc/html/node56.html (1 of 2) [22.07.2003 16:18:17]

Pointeri ca argumente ale functiilor

Din functia main se transmite spre functia inc_contor nu variabila care trebuie incrementata, ci adresa sa. Functia inc_contor primeste ca parametru nu un ntreg, ci un pointer la un ntreg. Astfel, cunoscnd adresa variabilei contor, functia poate modifica valoarea acelei variabile, referind-o indirect prin intermediul pointerului.
next up previous contents

Next: Pointeri si tablouri Up: Pointeri Previous: Operatii cu pointeri Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node56.html (2 of 2) [22.07.2003 16:18:17]

Pointeri si tablouri

next

up

previous

contents

Next: Pointeri la functii Up: Pointeri Previous: Pointeri ca argumente ale Cuprins

Pointeri si tablouri
n C, exista o strnsa legatura ntre pointeri si tablouri. Cnd se foloseste numele unui tablou (fara index), se genereaza un pointer catre primul element al tabloului. Astfel, n C se pot transmite tablouri ca parametri n functii (de fapt, se transmite adresa de nceput a tabloului). Alt avantaj al tratarii unitare pointer-tablou este aplicarea aritmeticii pointerilor pentru accesarea elementelor unui tablou. Identitate pointer-tablou se reflecta cel mai bine n operatiile cu siruri de caractere, unde sirul de caractere este un tablou de caractere sau un pointer la caracter. Prezentam n cele ce urmeaza unele aspecte ale relatiei dintre pointeri si tablouri.
int tablou[5]; int *tablou_ptr; tablou_ptr=&tablou[0];

Dupa secventa de mai sus, pointerul tablou_ptr va indica spre primul element al tabloului, deci spre nceputul zonei de memorie unde este stocat tabloul. Deoarece variabila tablou este vazuta n C ca un pointer, acelasi efect s-ar fi obtinut prin atribuirea: tablou_ptr=tablou;. Pentru a accesa elementele tabloului, se incrementeaza valoarea pointerului, astfel daca tablou_ptr=tablou; atunci *(tablou_ptr++) va returna valoarea lui tablou[0], dupa care tablou_ptr va arata spre tablou[1]. Atentie! *(tablou_ptr++) va returna valoarea lui tablou[0], dupa care se va incrementa valoarea lui tablou_ptr, aratnd spre tablou[1]. n schimb, (*tablou_ptr)++ va incrementa valoarea spre care arata tablou_ptr, returnnd astfel tablou[0]++.

http://labs.cs.utt.ro/labs/pc/html/node57.html (1 of 2) [22.07.2003 16:18:17]

Pointeri si tablouri

n acelasi context, propunem ca exercitiu rularea urmatorului exemplu:


#include <stdio.h> void main(void) { int t[4]={0, 1, 2, 3}; int *p=&t[1]; printf("%d\n", *p++); /* afiseaza valoarea lui t[1] */ printf("%d\n", *++p); /* afiseaza valoarea lui t[3] */ printf("%d\n", ++*p); /* afiseaza valoarea incrementata a lui t[3] */ }
next up previous contents

Next: Pointeri la functii Up: Pointeri Previous: Pointeri ca argumente ale Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node57.html (2 of 2) [22.07.2003 16:18:17]

Pointeri la functii

next

up

previous

contents

Next: Folosirea neadecvata a operatiilor Up: Pointeri Previous: Pointeri si tablouri Cuprins

Pointeri la functii
Limbajul C permite nu doar referirea unor date, ci si referirea functiilor (pointeri la functii). Aceasta nu difera mult de referirea datelor, un pointer la o functie retinnd adresa de memorie unde ncepe rutina care implementeaza functia. Un pointer la o functie se declara n maniera: tip_returnat (*nume_pointer)(... declaratii parametri ...); Astfel, daca avem implementata o functie f1 si un pointer spre functie f1_ptr, secventa urmatoare va arata cum se poate realiza prin intermediul unui pointer apelul unei functii:
#include <stdio.h> void f1(int a) { printf("%d\n",a); } void main(void) { void (*f1_ptr)(int); f1_ptr=f1; /* pointerul f1_ptr va indica spre functia f1 */ (*f1_ptr)(4); /* prin intermediul lui f1_ptr se apeleaza functia f1 */ }

La fel ca n cazul tablourilor, putem atribui direct unui pointer adresa functiei, fara a folosi operatorul & (f1_ptr=f1; este identic cu f1_ptr=&f1;).
Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node58.html [22.07.2003 16:18:17]

Folosirea neadecvata a operatiilor cu pointeri

next

up

previous

contents

Next: Problema rezolvata Up: Pointeri Previous: Pointeri la functii Cuprins

Folosirea neadecvata a operatiilor cu pointeri


n C, deoarece limbajul ofera o mare libertate de exprimare, este foarte usor pentru un programator neatent sa faca erori care nu sunt semnalate la compilare, dar care duc la comportari neasteptate ale programului. O eroare tipica este atribuirea de valori pointerilor neinitializati:
int *un_pointer; *un_pointer=5;

n aceasta situatie, deoarece un_pointer este neinitializat, valoarea 5 este scrisa n memorie la o locatie aleatoare, poate chiar rezervata altei variabile. n cazul n care un pointer nu arata spre o zona de memorie rezervata, trebuie alocata o zona de memorie n mod explicit, folosind functia malloc: un_pointer=(int *)malloc(sizeof(int)); Functia malloc rezerva spatiu de memorie si returneaza adresa spatiului rezervat; zona de memorie referita de un pointer poate fi eliberata folosind functia free. Ambele functii sunt definite n stdlib.h. n C nu exista un mecanism de garbage collection, astfel ca programatorul trebuie sa aiba grija ca zonele de memorie alocate dinamic si care nu mai sunt utile sa fie dealocate (folosind functia free). Faptul ca unui pointer i se atribuie o noua valoare nu nseamna ca zona de memorie spre care arata s-a eliberat si n acest mod programul poate ajunge sa tina alocata toata memoria disponibila. O alta greseala des ntlnita este referirea pointerilor spre alte locatii de memorie:
int obiect=5; int *obiect_ptr;

http://labs.cs.utt.ro/labs/pc/html/node59.html (1 of 2) [22.07.2003 16:18:18]

Folosirea neadecvata a operatiilor cu pointeri

obiect_ptr = obiect;

Lipsa operatorului de adresa & face ca obiect_ptr sa indice spre locatia de memorie aflata la adresa 5. Urmatorul exemplu ilustreaza un stil de programare "daunator", care strica lizibilitatea codului. Limbajul C este foarte flexibil, fapt ce poate duce, n special n cazul pointerilor, la rezultate imprevizibile:
void copy_string(char * p, char *q) { /* copiaza sirul q in p */ while (*p++ = *q++); }

Chiar daca aceasta implementare este mult mai compacta, urmarirea codului este foarte dificila, iar folosirea combinata a operatorilor de incrementare si pointerilor poate duce la efecte necontrolate. Urmatoarea varianta de implementare a aceleiasi functii copy_string prezinta un stil adecvat programarii cu pointeri:
void copy_string(char * dest, char * sursa) { *dest = *sursa; while (*dest!='\0') { ++dest; ++sursa; *dest = *sursa; } }
next up previous contents

Next: Problema rezolvata Up: Pointeri Previous: Pointeri la functii Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node59.html (2 of 2) [22.07.2003 16:18:18]

Problema rezolvata

next

up

previous

contents

Next: Problema propusa Up: Pointeri Previous: Folosirea neadecvata a operatiilor Cuprins

Problema rezolvata
Sa se scrie un program care gestioneaza date despre un grup de studenti. Pentru fiecare student se memoreaza numele si numarul sau matricol. Programul trebuie sa implementeze urmatoarele operatii:
q q q q q

citirea numarului de studenti si a datelor acestora; afisarea datelor tuturor studentilor; sortarea listei de studenti n ordinea alfabetica a numelor; sortarea listei de studenti n ordinea crescatoare a numerelor matricole; cautarea unui student pentru care se precizeaza numele si afisarea pozitiei pe care o ocupa acesta n lista ordonata alfabetic dupa numele studentilor; cautarea unui student pentru care se precizeaza numarul matricol si afisarea pozitiei pe care o ocupa acesta n lista ordonata crescator dupa numarul matricol al studentilor. <stdio.h> <string.h> <stdlib.h> <ctype.h> <conio.h>

#include #include #include #include #include

typedef struct { char *nume; int nr; } student; #define SIZE sizeof(student) typedef int (*comp)(void *, void *); /* tip pointer la functia de comparare */ typedef student *pstud; /*--------------------------------------------------------*/ /* */ /* functia eroare afiseaza un mesaj de eroare,in */
http://labs.cs.utt.ro/labs/pc/html/node60.html (1 of 7) [22.07.2003 16:18:18]

Problema rezolvata

/* cazul in care nu poate fi alocata dinamic o zona */ /* de memorie; apoi se opreste executia programului */ /* */ /*--------------------------------------------------------*/ void eroare(void) { puts(" \n **** eroare alocare dinamica de memorie ****"); exit(1); } /*--------------------------------------------------------*/ /* */ /* citeste numarul de studenti si datele acestora, */ /* aloca dinamic spatiu pentru tabloul de studenti, */ /* memoreaza numele si nr. matricol ale studentilor */ /* */ /*--------------------------------------------------------*/ void citeste(int *n, pstud *tab) { pstud t; char sir[40]; int i; /* citeste numarul de studenti */ printf("\n dati numarul de studenti:"); scanf("%d", n); /* aloca spatiu pentru toate inregistrarile de tip student */ if (!(t=(pstud)malloc((*n)*SIZE))) /* citeste1 */ eroare(); *tab=t; /* citeste datele tuturor studentilor */ for (i=0; i<*n; i++, t++) { printf("\n nume: "); scanf("%s", sir); /* aloca dinamic spatiu pentru numele studentului */ if (!(t->nume=(char *)malloc(strlen(sir)+1))) /* citeste2 */ eroare(); strcpy(t->nume, sir); printf("\n numar matricol:"); scanf("%d", &t->nr); }
http://labs.cs.utt.ro/labs/pc/html/node60.html (2 of 7) [22.07.2003 16:18:18]

Problema rezolvata

} /*--------------------------------------------------------*/ /* */ /* afiseaza numele si numarul matricol ale celor */ /* n studenti din tabelul a carui adresa este data */ /* in parametrul tab */ /* */ /*--------------------------------------------------------*/ void afiseaza (int n, pstud tab) { int i; puts("\n tabelul cu studenti "); for (i=0; i<n; i++, tab++) printf("\n%-30s %4d", tab->nume, tab->nr); } /*--------------------------------------------------------*/ /* */ /* functia comp1 compara numele a doi studenti ale caror */ /* adrese sunt date de pointerii p si r */ /* */ /*--------------------------------------------------------*/ int comp1(void *p, void *r) { return strcmp(((pstud)p)->nume, ((pstud)r)->nume); } /*--------------------------------------------------------*/ /* */ /* functia comp2 compara nr. matricol a doi studenti ale */ /* caror adrese sunt date de pointerii p si r */ /* */ /*--------------------------------------------------------*/ int comp2(void *p, void *r) { return ((pstud)p)->nr - ((pstud)r)->nr; }

/*--------------------------------------------------------*/ /* */ /* functia cauta studentul cu adresa data de parametrul s */


http://labs.cs.utt.ro/labs/pc/html/node60.html (3 of 7) [22.07.2003 16:18:18]

Problema rezolvata

/* in tabelul cu adresa indicata de parametrul tab; */ /* tabelul este ordonat dupa criteriul specificat prin */ /* parametrul f */ /* */ /*--------------------------------------------------------*/ void cauta(pstud s, pstud tab, int n, comp f) { pstud t=NULL; int i; t=bsearch(s, tab, n, SIZE, f); if (t) { /* exista studentul cautat */ i=t-tab; printf("\n studentul %s cu numarul matricol %d e al %d -lea in evidenta", t->nume, t->nr, i+1); } else printf("\n studentul nu se afla in evidenta"); }

/*--------------------------------------------------------*/ /* */ /* elibereaza spatiul de memorie detinut de campurile nume*/ /* ale celor n studenti din tabel si apoi zona detinuta */ /* de tabel */ /* */ /*--------------------------------------------------------*/ void elibereaza(pstud tabel, int n) { int i; for (i=0; i<n; i++) free(tabel[i].nume); free(tabel); } /*--------------------------------------------------------*/ /* */ /* functia meniu afiseaza meniul programului */ /* */ /*--------------------------------------------------------*/

http://labs.cs.utt.ro/labs/pc/html/node60.html (4 of 7) [22.07.2003 16:18:18]

Problema rezolvata

void meniu(void) { puts("\n c, C --- citeste tabel studenti"); puts(" a, A --- afiseaza tabel studenti"); puts(" n, N --- ordoneaza dupa nume"); puts(" r, R --- ordoneaza dupa numar matricol"); puts(" f, F --- cauta dupa nume"); puts(" l, L --- cauta dupa numar matricol"); puts(" x, X --- iesire din program"); }

void main(void) { char opt; int n; /* numarul de studenti */ char nume[30]; student s; pstud tabel=NULL; /* adresa tabloului cu studenti */ while (1) { meniu(); opt=tolower(getche()); switch (opt) { case 'c': if(tabel) /* daca a existat anterior un alt tablou in memorie */ elibereaza(tabel,n); citeste(&n, &tabel); break; case 'a': afiseaza(n,tabel); break; case 'n': qsort(tabel, n, SIZE, comp1); break; case 'r': qsort(tabel, n, SIZE, comp2); break; case 'f': printf("\n dati numele:"); scanf("%s", nume); if (!(s.nume=(char *)malloc(strlen(nume)+1))) eroare();
http://labs.cs.utt.ro/labs/pc/html/node60.html (5 of 7) [22.07.2003 16:18:18]

Problema rezolvata

strcpy(s.nume,nume); cauta(&s, tabel, n, comp1); free(s.nume); /* elibereaza spatiul alocat pentru nume */ break; case 'l': printf("\n dati numarul matricol:"); scanf("%d", &s.nr); cauta(&s, tabel, n, comp2); break; case 'x': exit(0); default: puts("comanda gresita"); } } }

Observatii: Din considerente de economie de memorie, implementarea tabloului cu studenti s-a facut dinamic; dupa ce s-a citit numarul de studenti, s-a alocat spatiul corespunzator (vezi linia /* citeste1 */). n plus, n tablou, n cmpul nume se pastreaza nu sirul de caractere pentru numele studentilor, ci un pointer la sirul de caractere. Astfel, n loc de a rezerva, pentru toate numele, acelasi numar de caractere, n momentul n care se cunoaste exact numele unui student, se aloca dinamic un spatiu de memorie de dimensiune egala cu lungimea acestuia (vezi linia /* citeste2 */). Adresa acestui spatiu se pastreza n cmpul nume. Reamintim ca n limbajul C, mecanismul de transmitere a parametrilor este prin valoare. Prin urmare, o functie nu poate modifica valoarea unui parametru actual, chiar daca modifica parametrul formal corespondent. Pentru situatiile n care se doreste sa se transmita informatie de la functia apelata la cea apelanta prin intermediul parametrilor se procedeaza in felul urmator: la apelul functiei se transmite adresa obiectului care urmeaza sa se modifice, iar, n cadrul functiei, parametrul corespondent se declara de tipul pointer. Astfel, functia apelata cunoaste adresa obiectului respectiv si l poate modifica, opernd indirect asupra lui, prin intermediul pointerului. Din aceste considerente, deoarece citirea numarului de studenti si alocarea spatiului pentru tablou se face n functia citeste, parametrii formali corespunzatori int *n si pstud *tab vor fi de tipul pointer. La apelul functiei citeste se vor transmite nu valorile lui n si tabel, ci
http://labs.cs.utt.ro/labs/pc/html/node60.html (6 of 7) [22.07.2003 16:18:18]

Problema rezolvata

adresele acestora: &n, &tabel. La accesarea elementelor tabloului de studenti s-a folosit att lucrul cu pointeri n functiile citeste si afiseaza, ct si varianta cu indici n functia elibereaza. Pentru compararea, dupa nume, a doi studenti s-a implementat functia comp1. Similar, functia comp2 realizeaza compararea dupa numarul matricol. Pentru sortarea tabloului se apeleaza functia de biblioteca qsort. Aceasta are urmatorul prototip: void qsort(void *tab, int nr_elem, int nr_oct_elem, int (*fcmp)(void *, void *)); Parametrii indica adresa tabloului de sortat, numarul elementelor tabloului, marimea n octeti a fiecarui element si adresa functiei de comparare. Dupa sortarea tabloului, cautarea unui student se face cu functia de cautare binara bsearch: void *bsearch(void *cheie, void *tab, int nr_elem, int nr_octeti_elem, int (*fcmp)(void *,void *)); Parametrii indica cheia cautata, adresa tabloului, numarul elementelor tabloului, marimea n octeti a fiecarui element si adresa functiei de comparare. Functia returneaza adresa primului element care corespunde cheii, respectiv valoarea NULL daca nu exista un astfel de element. n functia cauta, pentru a afla numarul de ordine al unui student n tabela, se scade din adresa elementului de tablou corespunzator acestuia (t) adresa de nceput a tabelei (tab). Pentru ca programul sa functioneze corect, comenzile f si l trebuie date dupa ce n prealabil s-au dat comenzile n si respectiv r. (Se utilizeaza pentru cautarea unui student o functie de cautare binara, deci tabela trebuie sa fie anterior sortata!)
next up previous contents

Next: Problema propusa Up: Pointeri Previous: Folosirea neadecvata a operatiilor Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node60.html (7 of 7) [22.07.2003 16:18:18]

Problema propusa

next

up

previous

contents

Next: Liste liniare simplu nlantuite Up: Pointeri Previous: Problema rezolvata Cuprins

Problema propusa
Sa se realizeze un program pentru evidenta abonatilor telefonici dintr-o localitate. Pentru fiecare abonat se memoreaza numele, adresa, numarul de telefon. Programul trebuie sa permita:
q q q q q

adaugarea unui nou abonat; stergerea unui abonat; modificarea datelor unui abonat; afisare numarului de telefon al unui abonat; stergerea ntregii evidente.

Implementarea listei de abonati sa se faca folosind ct mai putina memorie.


Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node61.html [22.07.2003 16:18:18]

Liste liniare simplu nlantuite

next

up

previous

contents

Next: Aspecte ale implementarii listelor Up: carte Previous: Problema propusa Cuprins

Liste liniare simplu nlantuite


Subsections q Aspecte ale implementarii listelor liniare
q

Problema rezolvata
r r

Codul sursa Comentarea programului

Problema propusa

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node62.html [22.07.2003 16:18:19]

Aspecte ale implementarii listelor liniare

next

up

previous

contents

Next: Problema rezolvata Up: Liste liniare simplu nlantuite Previous: Liste liniare simplu nlantuite Cuprins

Aspecte ale implementarii listelor liniare


O solutie de implementare a listelor liniare este sub forma unei nlantuiri de elemente cu aceeasi structura, aflate n memorie la diverse adrese si legate ntre ele prin intermediul pointerilor. Scopul utilizarii listelor este de a economisi spatiu de memorie, motiv pentru care se foloseste alocarea dinamica n locul celei statice (utilizata n cazul tablourilor). Accesul la un element al listei se poate face doar secvential, parcurgnd elementele aflate naintea sa n nlantuire. Pentru a exploata avantajul listelor n ceea ce priveste economia de spatiu de memorie, trebuie acordata o atentie deosebita operatiilor asupra listei. n general, asupra unei liste se pot face operatii de insertie/adaugare de noduri, stergere de noduri si parcurgerea nodurilor. Pentru a putea folosi o lista, este necesar sa fie retinuta adresa de nceput a listei (adresa primului nod). Ne vom referi n continuare la aceasta adresa prin pointerul prim. n cazul parcurgerii listei, operatia este relativ simpla. Cu ajutorul unui pointer auxiliar se pleaca de la prim si se urmareste legatura spre nodul urmator, pointerul auxiliar primind pe rnd adresa nodului urmator. O operatie mai complicata este introducerea unui nod nou n lista. Se disting trei situatii: introducere la nceputul listei, introducere la sfrsit si introducere ntre doua noduri. Dupa alocarea spatiului de memorie necesar noului nod, presupunem ca acesta este referit prin pointerul temp. n figurile 8.1, 8.2 si 8.3 se prezinta cele trei cazuri de adaugare a noului nod. Ordinea operatiilor a fost marcata prin 1, 2, 3.

http://labs.cs.utt.ro/labs/pc/html/node63.html (1 of 4) [22.07.2003 16:18:20]

Aspecte ale implementarii listelor liniare

\begin{figure}\begin{center} \epsfig{file=adaugare_inc.eps, height=5cm} \end{center}\end{figure}

Figura 8.1: Adaugarea unui nod la nceputul listei

\begin{figure}\begin{center} \epsfig{file=adaugare_sf.eps, height=5cm} \end{center}\end{figure}

Figura 8.2: Adaugarea unui nod la sfrsitul listei

http://labs.cs.utt.ro/labs/pc/html/node63.html (2 of 4) [22.07.2003 16:18:20]

Aspecte ale implementarii listelor liniare

\begin{figure}\begin{center} \epsfig{file=adaugare_mijl.eps, height=5cm} \end{center}\end{figure}

Figura 8.3: Adaugarea unui nod la mijlocul listei

n situatia stergerii unui nod din lista apar de asemenea cele trei situatii anterior descrise (nod de la nceputul, de la sfrsitul sau din mijlocul listei). Principala grija a programatorului n cazul stergerii unui nod trebuie sa fie eliberarea spatiului de memorie alocat nodului care a fost sters si mentinerea integritatii listei (prin stergerea nodului, sa nu se "rupa" lista). n figurile 8.4, 8.5 si 8.6 se prezinta cele trei situatii de stergere.

\begin{figure}\begin{center} \epsfig{file=stergere_inc.eps, height=3.5cm} \end{center}\end{figure}

Figura 8.4: Stergerea unui nod de la nceputul listei

http://labs.cs.utt.ro/labs/pc/html/node63.html (3 of 4) [22.07.2003 16:18:20]

Aspecte ale implementarii listelor liniare

\begin{figure}\begin{center} \epsfig{file=stergere_sf.eps, height=4cm} \end{center}\end{figure}

Figura 8.5: Stergerea unui nod de la sfrsitul listei

\begin{figure}\begin{center} \epsfig{file=stergere_mijl.eps, height=3.5cm} \end{center}\end{figure}

Figura 8.6: Stergerea unui nod de la mijlocul listei


next up previous contents

Next: Problema rezolvata Up: Liste liniare simplu nlantuite Previous: Liste liniare simplu nlantuite Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node63.html (4 of 4) [22.07.2003 16:18:20]

Problema rezolvata

next

up

previous

contents

Next: Codul sursa Up: Liste liniare simplu nlantuite Previous: Aspecte ale implementarii listelor Cuprins

Problema rezolvata
Sa se realizeze un program care raspunde la urmatoarele comenzi:
q

a - Se citeste o linie de forma: identificator numar unde numar este un numar ntreg. Ca rezultat, se retine n evidenta identificatorul mpreuna cu numarul asociat lui. t - Se citeste o linie ce contine un identificator. Daca acesta apare n evidenta, se tipareste valoarea asociata lui; n caz contrar se tipareste un mesaj de eroare. s - Se citeste o linie ce contine un identificator si l sterge din evidenta. l - Se tiparesc identificatorii din evidenta n ordine alfabetica mpreuna cu valorile asociate lor.
$+$ - Se citesc doua linii, fiecare continnd un identificator. n cazul n care ambii se afla n

q q q

evidenta se tipareste suma lor. n caz ca unul sau ambii identificatori lipsesc din evidenta, se afiseaza un mesaj de eroare.
q

$-$ - Se citesc doua linii, fiecare continnd un identificator. n cazul n care ambii se afla n

evidenta se tipareste diferenta lor. n caz ca unul sau ambii identificatori lipsesc din evidenta, se afiseaza un mesaj de eroare.
q

- Se citesc doua linii, fiecare continnd un identificator. n cazul n care ambii se afla n evidenta se tipareste produsul lor. n caz ca unul sau ambii identificatori lipsesc din evidenta se afiseaza un mesaj de eroare.
$/$ - Se citesc doua linii, fiecare continnd un identificator. n cazul n care ambii se afla n

$*$

evidenta se tipareste rezultatul mpartirii lor. n caz ca unul sau ambii identificatori lipsesc din evidenta se afiseaza un mesaj de eroare. f - Se termina programul.

http://labs.cs.utt.ro/labs/pc/html/node64.html (1 of 2) [22.07.2003 16:18:20]

Problema rezolvata

Observatie: Identificatorii sunt pastrati n tabela n mod ordonat.


Subsections q Codul sursa
q

Comentarea programului
up previous contents

next

Next: Codul sursa Up: Liste liniare simplu nlantuite Previous: Aspecte ale implementarii listelor Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node64.html (2 of 2) [22.07.2003 16:18:20]

Codul sursa

next

up

previous

contents

Next: Comentarea programului Up: Problema rezolvata Previous: Problema rezolvata Cuprins

Codul sursa
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <conio.h> #include <ctype.h> #define Max 100 /* lungimea maxima a unei linii */ /* tipul pentru nodul listei */ typedef struct elem { char *id; int valoare; struct elem *urm; } nod; nod *radacina=NULL; /* pastreaza inceputul listei */

/*---------------------------------------------------------*/ /* */ /* Functia caut cauta sirul s in lista al carei inceput */ /* e indicat de parametrul lista. Daca sirul apare in lista*/ /* atunci functia returneaza pointerul la nodul respectiv, */ /* in caz contrar returneaza NULL */ /* */ /*---------------------------------------------------------*/ nod *caut(nod *lista, char *s) { nod *q1; for (q1=lista; q1!=NULL && strcmp(q1->id, s)<0; q1=q1->urm); /* caut 1 */ if (q1!=NULL && strcmp(q1->id, s)==0) /* caut 2 */ return q1; /* daca sirul s a fost gasit in lista */

http://labs.cs.utt.ro/labs/pc/html/node65.html (1 of 9) [22.07.2003 16:18:21]

Codul sursa

return NULL; } /*---------------------------------------------------------*/ /* */ /* Functia listez parcurge lista si pentru fiecare nod */ /*afiseaza identificatorul memorat si valoarea atasata lui.*/ /*Deoarece lista este ordonata, afisarea identificatorilor*/ /* este in ordine alfabetica */ /* */ /*---------------------------------------------------------*/ void listez(void) { nod *q; for (q=radacina; q!=NULL; q=q->urm) printf("Identificator: %s Valoare: %d\n",q->id,q->valoare); } /*---------------------------------------------------------*/ /* Functia sterg elimina din lista indicata de pointerul */ /* lista, nodul ce are campul id egal cu argumentul s */ /* */ /*---------------------------------------------------------*/ nod *sterg(nod *lista, char *s) { nod *q1, *q2; for (q1=q2=lista; q1!=NULL && strcmp(q1->id, s)<0; q2=q1,q1=q1->urm); /* sterg 1 */ /* se parcurge lista cautandu-se nodul avand */ /* campul id egal cu sirul s */ if (q1!=NULL && strcmp(q1->id, s)==0) /* sterg 2 */ { /* daca s-a gasit un astfel de nod */ if (q1!=q2) /* daca nodul nu este la inceputul listei */ /* sterg 3 */ q2->urm = q1->urm; /* elimina nodul din lista */ else /* nodul apare la inceputul listei */ lista = lista->urm; /* sterg 4 */ free(q1->id); /* se elibereaza memoria ocupata de nodul eliminat */ free(q1);

http://labs.cs.utt.ro/labs/pc/html/node65.html (2 of 9) [22.07.2003 16:18:21]

Codul sursa

return lista; /*returneaza pointerul catre inceputul listei modificate*/ } else { printf("Eroare: identificatorul %s nu apare in lista\n", s); return lista; } }

/*---------------------------------------------------------*/ /* */ /* Functia introduc insereaza un nod in lista ordonata, */ /* indicata de parametrul lista. Lista ramine ordonata si */ /* dupa inserare. Nodul nou are campul id egal cu sirul */ /* indicat de parametrul s, iar campul valoare egal cu */ /* parametrul v. Functia returneaza pointerul catre */ /* inceputul listei modificate */ /* */ /*---------------------------------------------------------*/ nod *introduc(nod *lista, char *s, int v) { nod *q1, *q2, *aux; if ((aux=(nod *)malloc(sizeof(nod)))==NULL || (aux->id=(char *)malloc(strlen(s)+1))==NULL) /* introduc 1 */ { /* daca nu e memorie suficienta pentru a crea un nod nou, respectiv pentru a memora sirul s, se da un mesaj de eroare dupa care executia e incheiata */ printf("Eroare: memorie insuficienta\n"); exit(1); } strcpy(aux->id, s); /* se salveaza s in nodul nou */ aux->valoare=v; /* se salveaza v in nodul nou */ /* nodul nou este inserat in lista ordonata astfel incat ea ramane ordonata si dupa inserare. Lista este parcursa cautandu-se primul nod avand campul id mai mare sau egal cu s */ for (q2=q1=lista; q1!=NULL && strcmp(q1->id, s)<0; q2=q1, q1=q1->urm); /* introduc 2 */
http://labs.cs.utt.ro/labs/pc/html/node65.html (3 of 9) [22.07.2003 16:18:21]

Codul sursa

if (q1!=NULL && strcmp(q1->id, s)==0) /* introduc 3 */ /* daca in lista apare un nod avand campul id egal cu s, atunci se afiseaza un mesaj de eroare si se pastreaza lista nemodificata*/ { printf("Eroare: %s apare in tabela\n", s); return lista; } if (q1!=q2) /* daca inserarea nu se face la inceputul listei*/ /* introduc 4 */ { q2->urm=aux; aux->urm=q1; return lista ; } /* daca inserarea se face la inceputul listei */ /* introduc 5 */ aux->urm=lista; return aux; } /*-------------------------------------------------------------*/ /* */ /*Functia citesc_linie citeste urmatoarea linie de la tastatura */ /*si recunoaste identificatorul si valoarea asociata lui. */ /*Identificatorul este returnat in parametrul s, */ /*iar valoarea in parametrul val */ /* */ /*-------------------------------------------------------------*/ void citesc_linie(char *s, int *val) { int i, j; char temp[Max]; /* citeste urmatoarea linie de la tastatura */ gets(temp); /* citesc_linie 1 */ s[0]='\0'; /* initializeaza valorile argumentelor */ for (i=0; temp[i]!='\0'; ) /* atata timp cat nu a fost atins sfarsitul sirului */ /* citesc_linie 2 */ { if (isalpha(temp[i])) /* daca incepe un identificator */
http://labs.cs.utt.ro/labs/pc/html/node65.html (4 of 9) [22.07.2003 16:18:21]

Codul sursa

/* citesc_linie 3 */ { j=0; /* memoreaza identificatorul in s */ while (isalnum(temp[i])) s[j++]=temp[i++]; /* citesc_linie 4 */ /* memoreaza sfarsitul de sir */ s[j]='\0'; /* citesc_linie 5 */ continue; } if (isdigit(temp[i])) /* daca incepe un numar */ /* citesc_linie 6 */ { *val=0; while (isdigit(temp[i])) /* citesc_linie 7 */ { /* calculeaza valoarea numarului */ *val=*val*10+temp[i]-'0' ; /* citesc_linie 8 */ i++; } continue; } /* altfel se trece peste caracterul curent */ i++; /* citesc_linie 9 */ } /* while */ } /*----------------------------------------------------------*/ /* */ /* Functia comanda_a realizeaza functionalitatea comenzii a */ /* */ /*----------------------------------------------------------*/ void comanda_a(void) { int val; char s[Max]; citesc_linie(s, &val); /* citeste o linie de la tastatura */ if (strlen(s)!=0) /* daca linia e corecta */ radacina=introduc(radacina, s, val); else
http://labs.cs.utt.ro/labs/pc/html/node65.html (5 of 9) [22.07.2003 16:18:21]

Codul sursa

printf("Eroare : linie incorecta\n"); } /*---------------------------------------------------------*/ /* */ /* Functia comanda_t realizeaza functionalitatea comenzii t */ /* */ /*---------------------------------------------------------*/ void comanda_t(void) { int val; char s[Max]; nod *p; citesc_linie(s, &val); /* citeste o linie de la tastatura */ if (strlen(s)==0) /* daca linia e incorecta */ {printf("Eroare: linie incorecta\n"); return;} if ((p=caut(radacina, s))!=NULL) /* cauta nodul in lista */ printf("Identificator:%s Valoare:%d\n", p->id, p->valoare); else printf("Eroare: Identificator nedefinit\n"); } /*---------------------------------------------------------*/ /* */ /* Functia comanda_s realizeaza comanda s */ /* */ /*---------------------------------------------------------*/ void comanda_s(void) { char s[Max]; int val; citesc_linie(s, &val); /* citeste o linie de la tastatura */ if (strlen(s)==0) /* daca linia citita e incorecta */ {printf("Eroare: linie incorecta\n"); return;} radacina=sterg(radacina, s); /* sterge nodul din lista */ } /*---------------------------------------------------------*/ /* */ /* Functia comanda_oper executa operatiile legate de */ /* comenzile +, -, *, / */
http://labs.cs.utt.ro/labs/pc/html/node65.html (6 of 9) [22.07.2003 16:18:21]

Codul sursa

/* Se citesc cei doi operatori si se executa operatia */ /* dorita. Rezultatul este afisat. */ /* */ /*---------------------------------------------------------*/ void comanda_oper(char c) { char s1[Max], s2[Max]; int val; nod *p1, *p2; /* se citeste primul operand */ citesc_linie(s1, &val); /* comanda_oper 1 */ /* se citeste al doilea operand */ citesc_linie(s2, &val); /* comanda_oper 2 */ if (strlen(s1)!=0 && strlen(s2)!=0) if(((p1=caut(radacina, s1))!=NULL) && ((p2=caut(radacina, s2))!=NULL)) /* comanda_oper 3 */ /* se verifica daca operanzii apar in lista */ { switch(c) /* functie de tipul comenzii */ { case '+': val=p1->valoare+p2->valoare; break; case '-': val=p1->valoare-p2->valoare; break; case '*': val=p1->valoare*p2->valoare; break; case '/': if (p2->valoare!=0) val=p1->valoare/p2->valoare; else printf("Eroare: Impartire la 0\n"); break; } printf("Rezultatul operatiei e %d\n", val); } else printf("Operand nedefinit\n"); else printf("Eroare: linie eronata\n"); }
http://labs.cs.utt.ro/labs/pc/html/node65.html (7 of 9) [22.07.2003 16:18:21]

Codul sursa

/*-----------------------------------------------------------*/ /* */ /* Functia meniu afiseaza meniul programului,citeste comanda */ /* si apeleaza subrutina corespunzatoare */ /* */ /*-----------------------------------------------------------*/ void meniu(void) { char o; while(1) /* meniu 1 */ { clrscr(); /* se afiseaza meniul programului */ puts("a : adauga un identificator si valoarea asociata"); puts("t : tipareste valoarea asociata unui identificator"); puts("s : sterge un identificator"); puts("l : listeaza identificatorii si valorile asociate"); puts("+ : calculeaza suma pentru 2 identificatori"); puts("- : calculeaza diferenta pentru 2 identificatori"); puts("* : calculeaza produsul pentru 2 identificatori"); puts("/ : calculeaza impartirea pentru 2 identificatori"); puts("f : termina programul"); printf("\nOptiunea: "); o=getche(); /* meniu 2 */ printf("\n\n"); switch (tolower(o)) /* meniu 3 */ { case 'a': comanda_a(); break; case 't': comanda_t(); break; case 's': comanda_s(); break; case 'l': listez(); break; case '+': case '-': case '*': case '/': comanda_oper(o); break; case 'f': return; default: printf("Eroare : Comanda inexistenta\n"); }
http://labs.cs.utt.ro/labs/pc/html/node65.html (8 of 9) [22.07.2003 16:18:21]

Codul sursa

printf("\nApasa orice tasta..."); getch(); } } /*----------------------------------------------------*/ /* */ /* Functia main apeleaza functia meniu */ /* */ /*----------------------------------------------------*/ void main(void) { meniu(); }

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node65.html (9 of 9) [22.07.2003 16:18:21]

Comentarea programului

next

up

previous

contents

Next: Problema propusa Up: Problema rezolvata Previous: Codul sursa Cuprins

Comentarea programului
Programul memoreaza identificatorii si valorile asociate lor ntr-o evidenta, pe care o foloseste conform functionalitatii cerute. Evidenta este realizata printr-o lista simplu nlantuita ordonata. Fiecare nod al listei contine un cmp pentru pastrarea identificatorului, care este indicat de char *id, un cmp pentru memorarea valorii asociate identificatorului, cmpul int valoare, si un cmp pentru a crea nlantuirea cu nodul urmator din lista, cmpul struct elem *urm. Lista este ordonata crescator functie de cmpurile id ale nodurilor. Functia main apeleaza functia meniu. Aceasta afiseaza n mod repetat, datorita instructiunii while(1) de pe linia /* meniu 1 */, optiunile pe care le ofera programul. n continuare, meniu citeste de la tastatura optiunea dorita (linia /* meniu 2 */) si caracterul $<$Return $>$. n functie de optiunea aleasa (linia /* meniu 3 */) se selecteaza rutina ce implementeaza functionalitatea dorita. Rutina comanda_a citeste un identificator si valoarea asociata lui, dupa care l introduce n evidenta. Citirea se face apelnd functia citesc_linie. n cazul n care lungimea identificatorului citit este 0, se afiseaza un mesaj de eroare. n caz contrar, identificatorul si valoarea asociata lui sunt introduse n lista ordonata prin apelarea rutinei introducere. comanda_t citeste un identificator folosind citesc_linie. Daca lungimea identificatorului este 0, atunci se afiseaza mesajul ca linia este incorecta. Daca nsa lungimea este diferita de 0, atunci identificatorul este cautat n lista (apelnd functia caut). Daca identificatorul apare n lista, atunci se afiseaza valoarea asociata lui, n caz contrar se tipareste un mesaj de eroare adecvat.

http://labs.cs.utt.ro/labs/pc/html/node66.html (1 of 4) [22.07.2003 16:18:21]

Comentarea programului

Functia comanda_s citeste o linie ce contine un identificator (folosind citesc_linie). Daca linia citita este corecta (adica lungimea identificatorului este nenula), atunci identificatorul este eliminat din evidenta prin apelarea lui sterg. comanda_oper citeste doi identificatori (liniile /* comanda_oper 1 */ si /* comanda_oper 2 */) si efectueaza o operatie aritmetica cu acesti operanzi. Felul operatiei dorite este transmis prin parametrul char c al rutinei comanda_oper. Daca identificatorii sunt corecti (au lungimile diferite de 0), atunci ei sunt cautati n evidenta (linia /* comanda_oper 3*/). Daca ambii apar, atunci, functie de c, se efectueaza operatia dorita, iar rezultatul este afisat. Citirea unei linii de la tastatura se face prin rutina citesc_linie. Linia /* citesc_linie 1 */ citeste n variabila locala temp o linie de la tastatura. Ciclul while de pe linia /* citesc_linie 2 */ parcurge tabloul temp. Daca gaseste o litera (linia /* citesc_linie 3 */), atunci nseamna ca a descoperit nceputul unui identificator. Ciclul while de pe linia /* citesc_linie 4 */ preia ntregul identificator si l memoreaza n tabloul al carui nceput este indicat de parametrul char *s. Linia /*citesc_linie 5 0'' ce indica sfrsitul identificatorului. Daca la */ memoreaza caracterul '' $\backslash$ parcurgerea lui temp este ntlnita o cifra (linia /* citesc_linie 6 */), atunci a fost descoperit nceputul numarului care apare n linia de text. Acest numar este preluat prin ciclul while de pe linia /* citesc_linie 7 */, calculndu-se simultan si valoarea numerica asociata lui. Linia /* citesc_linie 8 */ face conversia, din sirul de caractere asociat numarului ntreg, n valoarea lui. Calcularea valorii numerice se face folosind variabila ntreaga a carei adresa este transmisa prin parametrul int *val. Linia /* citesc_linie 9 */ "sare" peste acele caractere care nu fac parte din identificator sau numar. caut parcurge lista al carei nceput este transmis prin parametrul nod *lista, cautnd nodul al carui identificator este egal cu sirul indicat de parametrul char *s. Daca un astfel de nod este gasit, atunci caut returneaza pointerul catre el. n caz contrar, returneaza NULL. Parcurgerea listei se face prin ciclul for de pe linia /* caut 1 */. Variabila q1 este initializata astfel nct sa indice nceputul listei. La sfrsitul fiecarei iteratii, q1 este mutat catre urmatorul nod. Conditia de reluare a ciclului este ca lista sa nu fi fost parcursa n ntregime (conditia q1 !=
http://labs.cs.utt.ro/labs/pc/html/node66.html (2 of 4) [22.07.2003 16:18:21]

Comentarea programului

NULL de pe linia /* caut 1 */) si identificatorul sa nu fi fost gasit. Deoarece lista este ordonata crescator este suficient sa testam ca strcmp(q1- $>$id,s)
$<$

0 (linia /* caut 1 */). Linia /* caut 2 */ verifica daca

identificatorul a fost gasit. Pentru aceasta este necesar ca q1 != NULL (altfel s-ar fi parcurs toata lista) si sirul memorat n nodul curent sa fie egal cu cel indicat de s. Rutina listez parcurge toate nodurile din lista si, pentru fiecare, afiseaza identificatorul retinut si valoarea atasata lui. Rutina sterg elimina, din lista referita prin parametrul nod *lista, nodul al carui identificator este egal cu sirul indicat de parametrul char *s. sterg returneaza pointerul catre nceputul listei modificate. Dupa eliminare, lista ramne ordonata. Pentru eliminarea unui nod sunt folositi doi pointeri care parcurg lista. q1 indica nodul curent, n timp ce q2 pe cel anterior lui. Acest lucru este necesar deoarece la eliminarea nodului indicat de q1, nlantuirea urm a nodului anterior (care este indicat de q2) se modifica spre nodul urmator lui q1. Ciclul for de pe linia /* sterg 1 */ parcurge lista. Pointerii q1 si q2 sunt initializati sa indice spre nceputul listei din care se face stergerea. La fiecare reluare a ciclului, q2 ia vechea valoare a lui q1, n timp ce q1 se muta spre nodul urmator. Conditia de reluare a ciclului for este ca lista sa nu fi fost parcursa n ntregime (q1 != NULL) si nodul sa nu fi fost gasit (strcmp(q1- $>$id, s)
$<$

0). Daca nodul a fost gasit (linia /* sterg 2 */), atunci se verifica daca

el este sau nu primul nod al listei. Daca nodul nu este chiar nceputul listei (linia /* sterg 3 */), atunci nlantuirea urm a nodului anterior celui indicat de q1 se modifica spre nodul urmator celui indicat de q1. Daca nsa nodul indicat de q1 este primul din lista, atunci variabila lista este schimbata spre al doilea nod. Memoria ocupata de nodul eliminat este eliberata. Daca nsa nu exista un nod care sa aiba identificatorul egal cu sirul indicat de s, atunci sterg tipareste un mesaj de eroare.

http://labs.cs.utt.ro/labs/pc/html/node66.html (3 of 4) [22.07.2003 16:18:21]

Comentarea programului

introduc creeaza un nod nou care contine sirul indicat de parametrul char *s, iar cmpul lui de valoare este egal cu parametrul int v. Nodul este inserat n lista indicata de parametrul nod *lista, astfel nct dupa introducere, lista ramne ordonata. introduc returneaza nceputul listei modificate. Linia /* introduc 1 */ aloca memorie pentru noul nod. Daca alocarea nu este posibila, se afiseaza un mesaj de eroare si executia programului este ncheiata. n caz contrar, cmpurile id si valoare sunt initializate corespunzator. Linia /* introduc 2 */ parcurge lista cautnd pozitia n care noul nod trebuie introdus. Pentru introducerea unui nod ntr-o lista ordonata sunt necesari doi pointeri; unul indica nodul n fata caruia se face inserarea, iar al doilea pe cel anterior lui. Daca noul nod nu este inserat ca primul nod n lista (linia /* introduc 4 */), atunci nlantuirea de la nodul anterior (indicat de q2) se schimba catre nodul nou, iar nlantuirea noului nod se schimba spre nodul indicat de q1. Daca nodul devine primul n lista (linia /* introduc 5 */) atunci nlantuirea lui urm este modificata spre nodul indicat de q1. n acest caz valoarea returnata de introduc (care este nceputul listei modificate) este tocmai pointerul spre nodul recent introdus. Daca n lista apare deja un nod al carui identificator este egal cu cel care se doreste a fi introdus (linia /* introduc 3 */), atunci se afiseaza un mesaj de eroare si se pastreaza lista nemodificata.
next up previous contents

Next: Problema propusa Up: Problema rezolvata Previous: Codul sursa Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node66.html (4 of 4) [22.07.2003 16:18:21]

Problema propusa

next

up

previous

contents

Next: Liste liniare multiplu nlantuite Up: Liste liniare simplu nlantuite Previous: Comentarea programului Cuprins

Problema propusa
Sa se implementeze un set de functii care sa realizeze urmatoarele operatii:
q q

q q q q q

adaug (t,id) - introduce identificatorul id n tabela de simboluri t; prezent (t,id) - returneaza 1 sau 0 dupa cum identificatorul id este sau nu prezent n tabela t; sterg (t,id) - elimina id din tabela t; reuniune (t1,t2,t) - t va contine identificatorii prezenti n t1 sau t2; intersectie (t1,t2,t) - t va contine identificatorii prezenti att n t1 ct si in t2; diferenta (t1,t2,t) - t va contine identificatorii prezenti n t1 si absenti n t2; scriu(t) - tipareste n ordine alfabetica identificatorii din t.

Folosind functiile de mai sus sa se realizeze un program care citeste doua secvente consecutive de text, care se termina fiecare cu caracterul `.`. Dupa citirea textelor se cere sa se tipareasca, n ordine alfabetica, identificatorii prezenti doar n primul text, apoi cei doar n al doilea text. n continuare se vor tipari n ordine alfabetica identificatorii care sunt prezenti att n primul ct si n al doilea text. n final se afiseaza identificatorii care apar n cel putin unul din cele doua texte.
next up previous contents

Next: Liste liniare multiplu nlantuite Up: Liste liniare simplu nlantuite Previous: Comentarea programului Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node67.html [22.07.2003 16:18:22]

Liste liniare multiplu nlantuite

next

up

previous

contents

Next: Implementarea listelor multiplu nlantuite Up: carte Previous: Problema propusa Cuprins

Liste liniare multiplu nlantuite


Subsections q Implementarea listelor multiplu nlantuite
q

Problema rezolvata
r r

Sursa programului Comentarea programului

Problema propusa

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node68.html [22.07.2003 16:18:22]

Implementarea listelor multiplu nlantuite

next

up

previous

contents

Next: Problema rezolvata Up: Liste liniare multiplu nlantuite Previous: Liste liniare multiplu nlantuite Cuprins

Implementarea listelor multiplu nlantuite


Listele multiplu nlantuite sunt similare cu cele simplu nlantuite, diferenta constnd n prezenta n structura unui nod a mai multor legaturi logice, n locul uneia singure. Astfel, o asemenea lista poate fi privita ca mai multe liste simplu nlantuite "suprapuse", dupa cum se arata n Figura 9.1. Problemele de la liste simplu nlantuite referitoare la inserare/stergere sunt aceleasi, doar ca operatia trebuie efectuata pentru fiecare nlantuire logica a listei. Parcurgerea se face ca la liste simplu nlantuite, urmarind legaturile logice, cu deosebirea ca exista mai multe "nceputuri" ale listei, egale cu numarul de liste logice existente.

\begin{figure}\begin{center} \epsfig{file=lista.eps, width=\textwidth} \end{center}\end{figure}

Figura 9.1: Liste multiplu nlantuite

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node69.html [22.07.2003 16:18:22]

Problema rezolvata

next

up

previous

contents

Next: Sursa programului Up: Liste liniare multiplu nlantuite Previous: Implementarea listelor multiplu nlantuite Cuprins

Problema rezolvata
Sa se realizeze un program care raspunde la urmatoarele comenzi:
q

q q q

''a'' - Se citesc trei linii ce contin datele asociate unei persoane. Prima linie contine numele, a doua locul de munca, iar a treia vrsta. Persoana si datele asociate ei sunt retinute ntr-o evidenta. Daca persoana este deja prezenta atunci se actualizeaza datele asociate ei. ''t'' - Se citeste o linie ce contine un nume. n cazul n care acesta este prezent n evidenta, se tiparesc datele asociate lui. n caz contrar, se afiseaza un mesaj de atentionare. ''l'' - Se citeste o linie ce contine un loc de munca si se tiparesc n ordine alfabetica numele tuturor persoanelor ce au locul de munca respectiv. ''p'' - Se citeste o valoare ntreaga si se tiparesc, n ordinea crescatoare a vrstei, numele si datele asociate tuturor persoanelor care au vrsta mai mare sau egala cu valoarea citita. ''s'' - Se citeste o linie ce contine un nume. Persoana cu numele respectiv este eliminata din evidenta. ''d'' - Se citeste o linie ce contine un loc de munca si se elimina din evidenta toate persoanele care au locul de munca respectiv. ''n'' - Se tiparesc n ordine alfabetica toate persoanele din evidenta si datele asociate lor. ''v'' - Se tiparesc n ordine descrescatoare a vrstei, persoanele din evidenta. ''f'' - Se termina programului.

Subsections q Sursa programului


q

Comentarea programului
up previous contents

next

Next: Sursa programului Up: Liste liniare multiplu nlantuite Previous: Implementarea listelor multiplu nlantuite Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node70.html [22.07.2003 16:18:23]

Sursa programului

next

up

previous

contents

Next: Comentarea programului Up: Problema rezolvata Previous: Problema rezolvata Cuprins

Sursa programului
Fisierul tip.h
/* tipul unui nod al listei ce implementeaza evidenta */ typedef struct nod_lista { char *nume; /* nume */ char *loc_munca; /* locul de munca */ int varsta; /* varsta */ struct nod_lista *alf; /* inlantuirea in ordine alfabetica */ struct nod_lista *varcr; /* inlantuirea in ordinea crescatoarea a varstei */ struct nod_lista *vardes; /* inlantuirea in ordinea descrescatoarea a varstei */ } nod;

/* operatiile asupra listei */ nod *cauta(char *); void introdu(char *, char *, int); void afis_alf(void); void afis_des(void); void afis_loc_munca(char *); void afis_varsta(int); void elimin(char *); void elimin_loc_munca(char *);

Fisierul lista.c
#include #include #include #include <stdio.h> <string.h> <stdlib.h> "tip.h"

static nod *inc1=NULL, *inc2=NULL, *inc3=NULL ; /* nodurile listei sunt inlantuite dupa cele trei

http://labs.cs.utt.ro/labs/pc/html/node71.html (1 of 12) [22.07.2003 16:18:24]

Sursa programului

/* /* /* /*

criterii de ordonare */ cele trei liste sunt indicate inc1 indica lista ordonata in inc2 indica lista ordonata in inc3 indica lista ordonata in

de inc1, inc2 si inc3 */ ordine alfabetica */ ordinea crescatoare a varstei */ ordinea descrecatoare a varstei*/

static nod *auxp; /* variabila auxiliara folosita la eliminarea unui nod */ /*---------------------------------------------------------*/ /* */ /* cauta in lista ordonata alfabetic nodul care are */ /* numele egal cu parametrul n; */ /* returneaza pointerul la nod sau NULL */ /* */ /*---------------------------------------------------------*/ nod *cauta(char *n) { nod *l;

for(l=inc1; l!=NULL && strcmp(l->nume, n) < 0; l=l->alf); /* parcurge lista cautand nodul cu nume egal cu n */ if (l!=NULL && strcmp(l->nume, n)==0) /* daca nodul a fost gasit */ return l; return NULL; } /* cauta */ /*---------------------------------------------------------*/ /* */ /* scot1 elimina din lista ordonata alfabetic nodul */ /* care are numele egal cu parametrul l */ /* */ /*---------------------------------------------------------*/ nod *scot1(nod *p, char *l) /* p este inceputul listei din care se face eliminarea */ { nod *l1, *l2; for(l1=l2=p; l1!=NULL && strcmp(l1->nume, l) < 0; l2=l1, l1=l1->alf); /* se parcurge lista ordonata alfabetic cautand nodul cu numele egal cu l */ if (l1!=NULL && strcmp(l1->nume, l) == 0)
http://labs.cs.utt.ro/labs/pc/html/node71.html (2 of 12) [22.07.2003 16:18:24]

Sursa programului

/*daca s-a gasit nodul*/ if(l1 == l2 ) /* daca este primul nod in lista */ return p->alf; else { l2->alf=l1->alf; return p; } else /* nodul nu a fost gasit in lista */ { printf("Eroare: %s nu apare in evidenta\n", l); return p; } } /* scot1 */ /*---------------------------------------------------------*/ /* */ /* scot2 elimina din lista ordonata crescator dupa */ /* varsta, nodul care are numele egal cu parametrul l */ /* */ /*---------------------------------------------------------*/ nod *scot2(nod *p, char *l) /* p este inceputul listei din care se face eliminarea */ { nod *l1, *l2; for (l1=l2=p; l1!=NULL && strcmp(l1->nume, l)!=0; l2=l1, l1=l1->varcr); /* se parcurge lista ordonata crescator functie de varsta cautand nodul cu numele egal cu l */ if (l1!=NULL && strcmp(l1->nume, l)==0) /* daca s-a gasit nodul */ if(l1 == l2 ) /* daca este primul nod in lista */ return p->varcr; else { l2->varcr=l1->varcr; return p; } else { printf("Eroare: %s nu apare in evidenta\n",l); return p; } } /* scot2 */
http://labs.cs.utt.ro/labs/pc/html/node71.html (3 of 12) [22.07.2003 16:18:24]

Sursa programului

/*---------------------------------------------------------*/ /* */ /* scot3 elimina din lista ordonata descrescator dupa */ /* varsta nodul care are numele egal cu parametrul l */ /* */ /*---------------------------------------------------------*/ nod *scot3(nod *p, char *l) /* p este inceputul listei din care se face eliminarea */ { nod *l1, *l2; for (l1=l2=p; l1!=NULL && strcmp(l1->nume, l)!=0; l2=l1, l1=l1->vardes); /* se parcurge lista ordonata descrescator functie de varsta cautand nodul cu numele egal cu l*/ if (l1!=NULL && strcmp (l1->nume, l)==0) /* daca s-a gasit nodul */ { auxp=l1; /* auxp indica spre nodul care se elimina */ if (l1==l2) /* daca este primul nod in lista */ return p->vardes; else { l2->vardes=l1->vardes; return p; } } else { printf("Eroare: %s nu apare in evidenta\n", l); return p; } } /* scot3 */ /*---------------------------------------------------------*/ /* */ /* intr1 introduce nodul indicat de l in lista */ /* ordonata alfabetic, cu adresa de inceput in p */ /* */ /*---------------------------------------------------------*/ nod *intr1(nod *p, nod *l) /* p este inceputul listei in care se face introducerea */ /* l este nodul care este inserat */ {
http://labs.cs.utt.ro/labs/pc/html/node71.html (4 of 12) [22.07.2003 16:18:24]

Sursa programului

nod *l1, *l2; for(l1=l2=p; l1!=NULL && strcmp(l1->nume, l->nume)<0; l2=l1, l1=l1->alf); l->alf=l1; if (l1==l2) /* daca nodul este inserat la inceputul listei */ return l; else { l2->alf=l; return p; } } /* intr1 */ /*----------------------------------------------------------*/ /* */ /* intr2 introduce nodul indicat de l in lista ordonata */ /* crescator functie de varsta, cu adresa de inceput in p */ /* */ /*----------------------------------------------------------*/ nod *intr2( nod *p, nod *l) /* p este inceputul listei in care se face introducerea */ /* l este nodul care este inserat */ { nod *l1, *l2; for (l1=l2=p; l1!=NULL && l1->varsta<l->varsta; l2=l1, l1=l1->varcr); l->varcr=l1; if (l1==l2) /* daca nodul este inserat la inceputul listei */ return l; else { l2->varcr=l; return p; } } /* intr2 */ /*---------------------------------------------------------*/ /* */ /* intr3 introduce nodul indicat de l in lista ordonata */ /* descrescator functie de varsta, */ /* cu adresa de inceput in p */
http://labs.cs.utt.ro/labs/pc/html/node71.html (5 of 12) [22.07.2003 16:18:24]

Sursa programului

/* */ /*---------------------------------------------------------*/ nod *intr3(nod *p, nod *l) /* p este inceputul listei in care se face introducerea */ /* l este nodul care este inserat */ { nod *l1, *l2; for (l1=l2=p; l1!=NULL && l1->varsta>l->varsta; l2=l1, l1=l1->vardes); l->vardes=l1; if (l1==l2) /* daca nodul este inserat la inceputul listei */ return l; else { l2->vardes=l; return p; } } /* intr3 */ /*---------------------------------------------------------*/ /* */ /* introdu creeaza un nod nou pentru o persoana noua si il */ /* inlantuie in cele trei evidente */ /* */ /*---------------------------------------------------------*/ void introdu(char *n, char *lm, int v) /* n reprezinta numele persoanei */ /* lm reprezinta locul de munca */ /* v reprezinta varsta */ { nod *t; if ((t=cauta(n))!=NULL) /* daca exista deja o persoana cu numele n */ { /* actualizeaza locul de munca */ free(t->loc_munca); if ((t->loc_munca=(char*)malloc(strlen(lm)+1))==NULL) { printf("Eroare: memorie insuficienta\n"); exit(1); } else {
http://labs.cs.utt.ro/labs/pc/html/node71.html (6 of 12) [22.07.2003 16:18:24]

Sursa programului

strcpy(t->loc_munca, lm); /* noul loc de munca */ t->varsta=v; /* noua varsta */ inc2=scot2(inc2, t->nume); /* elimina nodul din lista ordonata crescator dupa varsta */ inc2=intr2(inc2, t); /* introdu nodul in lista ordonata crescator dupa varsta */ inc3=scot3(inc3, t->nume); /*elimina nodul din lista ordonata descrescator dupa varsta*/ inc3=intr3(inc3, t); /* introdu nodul in lista ordonata crescator dupa varsta */ } } else /* daca nodul nu apare in evidenta */ /* aloca memorie pentru nod */ if ((t=(nod*)malloc(sizeof(nod)))==NULL || (t->nume=(char*)malloc(strlen(n)+1))==NULL || (t->loc_munca=(char*)malloc(strlen(lm)+1))==NULL) { printf("Eroare: memorie insuficienta\n"); exit(1); } else { /* initializeaza campurile nodului nou */ strcpy(t->nume, n); strcpy(t->loc_munca, lm); t->varsta=v; inc1=intr1(inc1, t); /* nodul este introdus in lista 1 */ inc2=intr2(inc2, t); /* nodul este introdus in lista 2 */ inc3=intr3(inc3, t); /* nodul este introdus in lista 3 */ } } /* introdu */ /*---------------------------------------------------------*/ /* */ /* parcurge lista ordonata alfabetic si afiseaza evidenta */ /* */ /*---------------------------------------------------------*/ void afis_alf(void) { nod *p; for (p=inc1; p!=NULL ; p=p->alf) /* parcurge lista ordonata alfabetic */ { printf("Nume: %s\n", p->nume);
http://labs.cs.utt.ro/labs/pc/html/node71.html (7 of 12) [22.07.2003 16:18:24]

Sursa programului

printf("Loc de munca: %s\n", p->loc_munca); printf("varsta: %d\n\n", p->varsta); } } /* afis_alf */ /*---------------------------------------------------------*/ /* */ /* afiseaza evidenta in ordinea descrescatoare a varstei */ /* */ /*---------------------------------------------------------*/ void afis_des(void) { nod *p; for (p=inc3; p!=NULL; p=p->vardes) /*parcurge lista ordonata descrescator in functie de varsta*/ printf("Nume: %s\n", p->nume); } /* afis_des */ /*---------------------------------------------------------*/ /* */ /* afiseaza ordonat alfabetic persoanele cu locul */ /* de munca lm */ /* */ /*---------------------------------------------------------*/ void afis_loc_munca(char *lm) { nod *l; for (l=inc1; l!=NULL; l=l->alf) /* parcurge lista ordonata alfabetic */ if (strcmp(l->loc_munca, lm)==0) /* daca are locul de munca egal cu lm */ printf(" Nume: %s\n", l->nume); } /* afis_loc_munca */ /*---------------------------------------------------------*/ /* */ /* afis_varsta parcurge lista ordonata crescator functie */ /* de varsta si afiseaza toate persoanele care au */ /* varsta >= ca si v */ /* */ /*---------------------------------------------------------*/ void afis_varsta(int v) { nod *l;
http://labs.cs.utt.ro/labs/pc/html/node71.html (8 of 12) [22.07.2003 16:18:24]

Sursa programului

for (l=inc2; l!=NULL; l=l->varcr) /* se parcurge lista ordonata functie de varsta */ if (l->varsta>=v) /* daca varsta este >= ca si limita v */ printf("Nume: %s\n", l->nume); } /* afis_varsta */ /*---------------------------------------------------------*/ /* elimin scoate persoana cu numele egal cu s din evidenta */ /* */ /*---------------------------------------------------------*/ void elimin(char *s) { if (cauta(s)) /* daca s apare in evidenta */ { inc1=scot1(inc1, s); /* scoate nodul din lista 1 */ inc2=scot2(inc2, s); /* scoate nodul din lista 2 */ inc3=scot3(inc3, s); /* scoate nodul din lista 3 */ /* elibereaza memoria ocupata de nodul eliminat */ free (auxp->nume); free (auxp->loc_munca); free (auxp); } else printf("Persoana %s nu apare in evidenta\n"); } /* elimin */ /*---------------------------------------------------------*/ /* */ /* elimin_loc_munca elimina persoanele avind locul */ /* de munca egal cu s */ /* */ /*---------------------------------------------------------*/ void elimin_loc_munca(char *s) { nod *l, *aux; for (l=inc1; l!=NULL; ) if (strcmp(l->loc_munca, s)==0) /* s-a gasit o persoana cu locul de munca cautat */ { aux=l->alf; elimin(l->nume); /* elimina persoana gasita */ l=aux;
http://labs.cs.utt.ro/labs/pc/html/node71.html (9 of 12) [22.07.2003 16:18:24]

Sursa programului

} else l=l->alf; } /* elimin_loc_munca */

Fisierul main.c
#include <stdio.h> #include <conio.h> #include "tip.h" /*---------------------------------------------------------*/ /* */ /* Functia meniu afiseaza meniul programului, citeste */ /* comanda si apeleaza rutina care implementeaza */ /* functionalitatea comenzii respective */ /* */ /*---------------------------------------------------------*/ void meniu(void) { char c, s[30], lm[30]; int v; nod *t; while (1) { clrscr(); printf("aprintf("tprintf("lprintf("p-

Introducerea unei persoane noi in evidenta\n"); Cautarea unui nume in evidenta\n"); Tipareste persoanele cu un anumit loc de munca\n"); Afiseaza persoanele de varsta mai mare sau egala cu o valoare citita\n"); printf("s- Elimina o persoana din evidenta\n"); printf("d- Elimina persoanele cu un anumit loc de munca\n"); printf("n- Afiseaza alfabetic persoanele din evidenta\n"); printf("v- Afiseaza persoanele in ordinea descrescatoare a varstei\n"); printf("f- Termina programul\n\n\n"); printf(" Introduceti optiunea: "); c=getchar(); getchar(); /* citeste optiunea */ switch( c ) { case 'a': printf("Numele persoanei: "); gets(s); /* citeste numele */ printf(" Locul de munca: "); gets(lm);

http://labs.cs.utt.ro/labs/pc/html/node71.html (10 of 12) [22.07.2003 16:18:24]

Sursa programului

/* citeste locul de munca */ printf(" Varsta: "); scanf("%d", &v); getchar(); /* citeste varsta */ introdu(s, lm, v); /* persoana si datele aferente sunt introduse in evidenta */ break; case 'v': afis_des(); /* tipareste evidenta in ordinea descrescatoare a varstei */ break; case 't': printf("Numele persoanei: "); gets(s); /* citeste numele */ if ((t=cauta(s))!=NULL) /*daca persoana apare in evidenta*/ { printf("Nume: %s\n", t->nume); printf("Loc de munca: %s\n", t->loc_munca); printf("varsta: %d\n", t->varsta); } else printf("%s nu apare in evidenta\n",s); break; case 'l': printf(" Locul de munca: "); gets(lm); /* citeste numele */ afis_loc_munca(lm); /* afiseaza persoanele cu locul de munca citit */ break; case 'p': printf(" varsta limita: "); scanf("%d", &v); /* citeste varsta */ getchar(); afis_varsta(v); /* afiseaza persoanele cu varsta >= ca limita */ break; case 's': printf(" Numele persoanei: "); gets(s); /* citeste numele */ elimin(s); /* elimina persoana cu numele s din evidenta */ break; case 'd': printf(" Locul de munca: "); gets(lm); /* citeste numele */ elimin_loc_munca(lm); /* elimina persoanele cu un anumit loc de munca */ break; case 'n': afis_alf();
http://labs.cs.utt.ro/labs/pc/html/node71.html (11 of 12) [22.07.2003 16:18:24]

Sursa programului

/* afiseaza evidenta in ordine alfabetica */ break; case 'f': return; /* incheie meniu */ } getchar(); } } /* meniu */

/*---------------------------------------------------------*/ /* */ /* Functia main apeleaza functia meniu */ /* */ /*---------------------------------------------------------*/ void main() { meniu(); } /* main */

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node71.html (12 of 12) [22.07.2003 16:18:24]

Comentarea programului

next

up

previous

contents

Next: Problema propusa Up: Problema rezolvata Previous: Sursa programului Cuprins

Comentarea programului
Problema cere tiparirea persoanelor din evidenta, ordonate dupa trei criterii: ordonate dupa nume (comanda n), ordonate descrescator dupa vrsta (comanda v) si ordonate crescator dupa vrsta (comanda p). Din acest motiv, implementam evidenta printr-o lista multiplu nlantuita (fiecare nod fiind atasat unei persoane), iar criteriile de nlantuire a nodurilor corespunznd celor trei moduri de afisare cerute. Programul este mpartit pe trei fisiere. tip.h defineste tipul nodurilor din lista si declara operatorii pentru prelucrarea tipului abstract, lista.c defineste tipul abstract lista multiplu nlantuita, iar main.c defineste rutina pentru interfata cu utilizatorul si functia main. Nodurile listei cuprind urmatoarele cmpuri:
q q q q q q

nume - pentru numele angajatului loc_munca - pentru locul de munca varsta - pentru vrsta angajatului alf - pentru nlantuirea n ordine alfabetica varcr - pentru nlantuirea n ordine crescatoare dupa vrsta vardes - pentru nlantuirea n ordine descrescatoare dupa vrsta.

Datorita nlantuirilor multiple, fiecare nod apare nlantuit n listele atasate celor trei criterii de ordonare. Variabilele inc1, inc2 si inc3 (din fisierul lista.c) indica spre nceputurile listelor ordonate alfabetic, crescator dupa vrsta si, respectiv, descrescator dupa vrsta. Functia cauta parcurge lista ordonata alfabetic (folosind cmpul alf) si cauta persoana cu numele egal cu parametrul n. Daca un astfel de nod exista, atunci cauta returneaza pointerul la el, altfel NULL.

http://labs.cs.utt.ro/labs/pc/html/node72.html (1 of 3) [22.07.2003 16:18:24]

Comentarea programului

Cnd introducem un nod nou, el trebuie nlantuit dupa fiecare din cele trei criterii. Functia intr1 introduce nodul referit prin parametrul l n lista indicata de parametrul p, astfel nct lista sa ramna ordonata alfabetic. Functia returneaza pointerul catre nceputul listei rezultate. n mod asemanator, intr2 si intr3 nlantuie nodul indicat de l dupa criteriile ordonat crescator si descrescator dupa vrsta. Operatorul pentru introducerea unui nod nou n lista multiplu nlantuita este introdu. El are trei parametri, char *n pentru numele, char *lm pentru locul de munca si int v pentru vrsta nodului nou. introdu ncepe prin a verifica daca n evidenta apare deja o persoana cu numele n. n caz afirmativ se actualizeaza cmpurile loc_munca si varsta cu noile valori. n urma acestor modificari, pozitiile nodului n listele ordonate crescator si descrescator dupa vrsta se schimba. De aceea, scoatem nodul din pozitiile anterioare si l reintroducem conform noilor cmpuri. Daca persoana nu apare n evidenta, atunci se creeaza un nod nou, se initializeaza cmpurile lui, apoi nodul este nlantuit dupa cele trei criterii de ordonare. n mod asemanator, daca un nod trebuie eliminat din evidenta, el este scos din toate cele trei nlantuiri. scot1 elimina nodul din nlantuirea alf (cea ordonata alfabetic dupa nume), scot2 scoate nodul din nlantuirea dupa varcr (ordonata crescator dupa vrsta) si scot3 elimina nodul din nlantuirea dupa vardes (ordonata descrescator dupa vrsta). Operatorul (elimin) pentru stergerea persoanei cu numele dat de parametrul char *s apeleaza scot1, scot2 si scot3, dupa care elibereaza memoria ocupata de nodul sters. Pentru aceasta, foloseste variabila globala auxp pe care o pozitioneaza functia scot3. afis_alf este operatorul pentru afisarea persoanelor ordonate dupa nume. afis_des tipareste persoanele ordonate descrescator dupa vrsta. afis_varsta parcurge lista ordonata crescator dupa vrsta si afiseaza persoanele care au cmpul varsta mai mare ca si parametrul int v. afis_loc_munca tipareste ordonat alfabetic persoanele cu locul de munca dat de parametrul char *lm. elimin_loc_munca scoate din evidenta toate persoanele cu locul de munca egal cu parametrul char *s. Rutina parcurge lista ordonata alfabetic si elimina persoanele apelnd elimin.

http://labs.cs.utt.ro/labs/pc/html/node72.html (2 of 3) [22.07.2003 16:18:24]

Comentarea programului

Rutina meniu afiseaza meniul programului si functie de comanda selectata se apeleaza operatorul tipului abstract ce implementeaza functionalitatea dorita.
next up previous contents

Next: Problema propusa Up: Problema rezolvata Previous: Sursa programului Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node72.html (3 of 3) [22.07.2003 16:18:24]

Problema propusa

next

up

previous

contents

Next: Tipul abstract arbore binar Up: Liste liniare multiplu nlantuite Previous: Comentarea programului Cuprins

Problema propusa
Clasamentul jucatorilor de tenis este alcatuit pe baza rezultatelor din turnee. Dupa fiecare turneu disputat, jucatorii sunt rasplatiti cu un numar de puncte, functie de clasificarea lor. De exemplu, locul I ia 10 puncte, locul II 8 puncte, etc. n orice moment clasamentul ia n evidenta doar primii k jucatori (k este mai mic ca numarul tuturor jucatorilor). Daca un jucator iese din clasament, el pierde numarul de puncte adunate. Sa se realizeze un program care efectueaza urmatoarele operatii: citeste rezultatele din turneele disputate, actualizeaza clasamentul dupa fiecare turneu, elimina dupa fiecare turneu jucatorii care sunt situati mai jos de locul k si afiseaza situatia actualizata. De asemenea, programul va afisa toti jucatorii participanti n ordine alfabetica. Pentru implementarea clasamentului, se va retine o lista dublu nlantuita dupa doua criterii: ordonata alfabetic dupa numele jucatorilor si ordonata dupa punctaj (doar pentru primii k jucatori).
Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node73.html [22.07.2003 16:18:24]

Tipul abstract arbore binar ordonat

next

up

previous

contents

Next: Arbori binari Up: carte Previous: Problema propusa Cuprins

Tipul abstract arbore binar ordonat


Subsections q Arbori binari
r r r r

Cautarea n arbori binari ordonati Inserarea n arbori binari ordonati Stergerea n arbori binari ordonati Parcurgerea arborilor binari

Problema rezolvata
r r

Sursa programului Comentarea programului

Problema propusa

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node74.html [22.07.2003 16:18:24]

Arbori binari

next

up

previous

contents

Next: Cautarea n arbori binari Up: Tipul abstract arbore binar Previous: Tipul abstract arbore binar Cuprins

Arbori binari
Un arbore este o multime de elemente numite noduri sau vrfuri pentru care:
1. exista un nod cu destinatie speciala (radacina arborelui); 2. celelalte noduri sunt repartizate n n $>=$ 0 seturi disjuncte A1, A2, ..., An fiecare set constituind la rndul sau un arbore.

n structura ierarhica a arborelui, fiecare nod (mai putin radacina) este subordonat unui alt nod (relatie fiu-parinte). Daca un nod nu are fii, el se numeste terminal (sau frunza) Un arbore binar este un arbore n care un nod are maxim doi fii. Arborii binari ordonati reprezinta un caz particular al arborilor binari, n care fiecare nod contine o informatie distincta numita cheie, cu proprietatea ca, pentru fiecare nod , toate nodurile din subarborele stng au cheia mai mica dect cheia lui $t_{i}$ si $t_{i}$ toate nodurile din subarborele drept au cheia mai mare dect cheia lui binar ordonati se numesc si arbori de cautare. Principalele operatii asupra arborilor binar ordonati, prezentate n continuare, sunt: cautarea unui nod n arbore, inserarea unui nod n arbore, stergerea unui nod din arbore si parcurgerea arborelui. Se vor prezenta algoritmii recursivi pentru realizarea acestor operatii.
Subsections q Cautarea n arbori binari ordonati
q q

. Arborii $t_{i}$

Inserarea n arbori binari ordonati Stergerea n arbori binari ordonati

http://labs.cs.utt.ro/labs/pc/html/node75.html (1 of 2) [22.07.2003 16:18:25]

Arbori binari

Parcurgerea arborilor binari


up previous contents

next

Next: Cautarea n arbori binari Up: Tipul abstract arbore binar Previous: Tipul abstract arbore binar Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node75.html (2 of 2) [22.07.2003 16:18:25]

Cautarea n arbori binari ordonati

next

up

previous

contents

Next: Inserarea n arbori binari Up: Arbori binari Previous: Arbori binari Cuprins

Cautarea n arbori binari ordonati


Algoritmul de cautare a unui nod dupa o cheie x:
1. daca arborele este vid, cautarea se ncheie fara succes; 2. se compara cheia x cu cheia c a radacinii, daca x=c cautarea se ncheie cu succes; 3. daca x $<$c, se reia algoritmul n subarborele stng; 4. daca x $>$c, se reia algoritmul n subarborele drept.

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node76.html [22.07.2003 16:18:25]

Inserarea n arbori binari ordonati

next

up

previous

contents

Next: Stergerea n arbori binari Up: Arbori binari Previous: Cautarea n arbori binari Cuprins

Inserarea n arbori binari ordonati


Algoritmul de inserare a unui nod cu cheia x:
1. daca arborele este vid, se creeaza un nod nou cu cheia x, care va fi radacina arborelui; 2. daca cheia c a radacinii este egala cu x, inserarea se opreste fara a modifica arborele; 3. daca x $<$c, se reia algoritmul pentru subarborele stng; 4. daca x $>$c, se reia algoritmul pentru subarborele drept;

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node77.html [22.07.2003 16:18:25]

Stergerea n arbori binari ordonati

next

up

previous

contents

Next: Parcurgerea arborilor binari Up: Arbori binari Previous: Inserarea n arbori binari Cuprins

Stergerea n arbori binari ordonati


n cazul stergerii unui nod, se disting trei situatii:
1. daca cheia x nu se gaseste n arbore, atunci nu se modifica arborele; 2. daca nodul cu cheia x are cel mult un descendent, atunci nodul cu cheia x se sterge, locul sau fiind luat de unicul sau descendent; 3. daca nodul cu cheia x are doi descendenti, atunci nodul cu cheia x se sterge, fiind nlocuit de nodul cu cheia cea mai mare din subarborele stng (cel mai din dreapta nod al subarborelui stng) sau nlocuit de nodul cu cheia cea mai mica din subarborele drept (cel mai din stnga nod al subarborelui drept).

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node78.html [22.07.2003 16:18:25]

Parcurgerea arborilor binari

next

up

previous

contents

Next: Problema rezolvata Up: Arbori binari Previous: Stergerea n arbori binari Cuprins

Parcurgerea arborilor binari


Exista trei metode de parcurgere a arborilor binari: preordine inordine si postordine.
1. Preordine: se viziteaza radacina, dupa care se parcurge subarborele stng si apoi cel drept; 2. Inordine: se parcurge subarborele stng, dupa care se viziteaza radacina, apoi se parcurge si subarborele drept; 3. Postordine: se parcurge subarborele stng, dupa care se parcurge subarborele drept, apoi se viziteaza radacina.

Dintre cele trei parcurgeri, pentru un arbore binar ordonat, parcurgerea n inordine va genera o lista a nodurilor ordonata crescator dupa cheile nodurilor.
Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node79.html [22.07.2003 16:18:26]

Problema rezolvata

next

up

previous

contents

Next: Sursa programului Up: Tipul abstract arbore binar Previous: Parcurgerea arborilor binari Cuprins

Problema rezolvata
Sa se realizeze un program care raspunde la urmatoarele comenzi: ''a'' - Se citeste o linie de forma: identificator numar

unde numar este un numar ntreg. Ca rezultat, se retine n evidenta identificatorul mpreuna cu numarul asociat lui. ''t'' - Se citeste o linie ce contine un identificator. Daca acesta apare n evidenta, se tipareste valoarea asociata lui; n caz contrar se tipareste un mesaj de eroare. ''s'' - Se citeste o linie ce contine un identificator si l sterge din evidenta. ''l'' - Se tiparesc identificatorii din evidenta n ordine alfabetica mpreuna cu valorile asociate lor. ''+'' - Se citesc doua linii, fiecare continnd un identificator. n cazul n care ambii se afla n evidenta se tipareste suma lor. n caz ca unul sau ambii identificatori lipsesc din evidenta, se afiseaza un mesaj de eroare. ''-'' - Se citesc doua linii, fiecare continnd un identificator. n cazul n care ambii se afla n evidenta se tipareste diferenta lor. n caz ca unul sau ambii identificatori lipsesc din evidenta, se afiseaza un mesaj de eroare. ''*'' - Se citesc doua linii, fiecare continnd un identificator. n cazul n care ambii se afla n evidenta se tipareste produsul lor. n caz ca unul sau ambii identificatori lipsesc din evidenta se afiseaza un mesaj de eroare.

http://labs.cs.utt.ro/labs/pc/html/node80.html (1 of 2) [22.07.2003 16:18:26]

Problema rezolvata

''/'' - Se citesc doua linii, fiecare continnd un identificator. n cazul n care ambii se afla n evidenta se tipareste rezultatul mpartirii lor. n caz ca unul sau ambii identificatori lipsesc din evidenta se afiseaza un mesaj de eroare. ''f'' - Se termina programul.

Observatii:
q q q

Identificatorii sunt pastrati n tabela n mod ordonat. Se vor prezenta si comenta structurile de date folosite. Se va prezenta si comenta structura de ansamblu a programului, fisierele componente, functiile ce compun programul si efectul lor.

Subsections q Sursa programului


q

Comentarea programului
up previous contents

next

Next: Sursa programului Up: Tipul abstract arbore binar Previous: Parcurgerea arborilor binari Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node80.html (2 of 2) [22.07.2003 16:18:26]

Sursa programului

next

up

previous

contents

Next: Comentarea programului Up: Problema rezolvata Previous: Problema rezolvata Cuprins

Sursa programului
Fisierul arbore.h
#define Max 20 /* lungimea maxima a unui identificator */

typedef struct pn { char *id; /* campul pemtru identificator */ int valoare; /* campul pentru valoare */ struct pn *stang, *drept; /* fiul stang si drept al nodului */ } nod; /* tipul unui nod din arborele binar ordonat */ /* functiile prin care tipul abstract arbore este prelucrat*/ void sterge(char*); void listare(void); nod *cauta(char*); void introdu(char*, int);

Fisierul arbore.c
#include #include #include #include #include #include <stdio.h> <string.h> <stdlib.h> <ctype.h> <conio.h> "arbore.h"

static nod *root = NULL; /* radacina arborelui */ /*---------------------------------------------------------*/ /* */ /* prezent verifica daca in arborele cu radacina indicata */ /* de t exista un nod avand campul id egal cu parametrul */ /* id */

http://labs.cs.utt.ro/labs/pc/html/node81.html (1 of 11) [22.07.2003 16:18:27]

Sursa programului

/* */ /*---------------------------------------------------------*/ nod *prezent (nod *t, char *id) { if (t==NULL) return NULL; /* nodul nu a fost gasit */ if (strcmp (t->id, id)<0) /* incearca pentru subarborele drept */ return prezent(t->drept, id); if (strcmp (t->id, id)>0) /* incearca pentru subarborele stang */ return prezent (t->stang, id); return t; /* nodul a fost gasit */ } /* prezent */ /*---------------------------------------------------------*/ /* */ /* adauga introduce in arborele indicat de t un nod nou */ /* avand campul id si valoarea v */ /* */ /*---------------------------------------------------------*/ nod *adauga(nod *t, char *id, int v) { if (t==NULL) /* nodul nu exista si este creat */ { if ((t=(nod*)malloc(sizeof(nod)))==NULL || (t->id=(char*)malloc(strlen(id)+1))==NULL) { printf("Eroare: memorie insuficienta\n"); exit(1); } /* s-a putut crea nodul */ strcpy(t->id, id); t->valoare=v; t->stang=t->drept=NULL; } else if (strcmp(t->id, id)<0) /* inserarea e in subarborele drept */ t->drept=adauga(t->drept, id, v); else if (strcmp(t->id, id)>0)
http://labs.cs.utt.ro/labs/pc/html/node81.html (2 of 11) [22.07.2003 16:18:27]

Sursa programului

/* inserarea e in subarborele stang */ t->stang=adauga(t->stang, id, v); else printf("Identificatorul %s apare in evidenta\n",id); return t; } /* adauga */ /*---------------------------------------------------------*/ /* */ /* supred rutina auxiliara pentru eliminarea nodurilor */ /* cu doi fii */ /* */ /*---------------------------------------------------------*/ nod *supred (nod *t, nod *p) { nod *q, *q_aux; q=t; if (q->drept!=NULL) /* gaseste nodul cel mai mare din subarborele indicat de t */ q->drept=supred(q->drept, p); else /* pentru nodul cel mai mare din subarborele indicat de t */ { free(p->id); /* muta campurile nodului indicat de q in nodul indicat de p */ p->id=q->id; p->valoare=q->valoare; q_aux=q; q=q->stang; /* fiul stang este returnat */ free(q_aux); /* elibereaza memoria ocupata de nod */ } return q; } /* supred */

/*---------------------------------------------------------*/ /* */ /* elimina scoate nodul avand campul id egal cu parametrul */ /* id din arborele indicat de parametrul p */ /* */ /*---------------------------------------------------------*/ nod *elimina(nod *p, char *id) { nod *q, *q1; char *s;
http://labs.cs.utt.ro/labs/pc/html/node81.html (3 of 11) [22.07.2003 16:18:27]

Sursa programului

if (p==NULL) { printf("Eroare: %s nu apare in evidenta\n", id); return NULL; } if (strcmp(p->id, id)<0) /* nodul e in subarborele drept */ { p->drept=elimina(p->drept, id); return p; } if (strcmp(p->id, id)>0) /* nodul e in subarborele stang */ { p->stang=elimina(p->stang, id); return p; } /* s-a gasit nodul ce trebuie sters */ if (p->stang==NULL) /* daca nu are fiu stang */ { q=p->drept; free(p->id); free(p); return q; } if (p->drept==NULL) /* nu are fiu drept */ { q=p->stang; free(p->id); free(p); return q; } /* are ambii fii */ p->stang=supred(p->stang, p); return p; } /* elimina */

/*---------------------------------------------------------*/ /* */ /* parcurge in inordine arborele cu radacina indicata de t */


http://labs.cs.utt.ro/labs/pc/html/node81.html (4 of 11) [22.07.2003 16:18:27]

Sursa programului

/* si afiseaza nodurile */ /* */ /*---------------------------------------------------------*/ void tipareste (nod *t) { if (t!=NULL) { tipareste(t->stang); /* tipareste subarborele stang */ printf("%s : %d\n", t->id, t->valoare); tipareste(t->drept); /* tipareste subarborele drept */ } } /* tipareste */

/*---------------------------------------------------------*/ /* */ /* Operatorul de listare al tipului abstract */ /* */ /*---------------------------------------------------------*/ void listare(void) { tipareste(root); } /* listare */

/*---------------------------------------------------------*/ /* */ /* Operatorul de cautare al tipului abstract */ /* */ /*---------------------------------------------------------*/ nod *cauta(char *s) { return prezent(root, s); } /* cauta */

/*---------------------------------------------------------*/ /* */ /* Operatorul de stergere al tipului abstract */ /* */ /*---------------------------------------------------------*/ void sterge(char *s)


http://labs.cs.utt.ro/labs/pc/html/node81.html (5 of 11) [22.07.2003 16:18:27]

Sursa programului

{ root=elimina(root, s); } /* sterge */ /*---------------------------------------------------------*/ /* */ /* Operatorul de introducere al tipului abstract */ /* */ /*---------------------------------------------------------*/ void introdu(char *s, int v) { root=adauga(root, s, v); } /* introdu */

Fisierul main.c
#include #include #include #include #include <stdio.h> <ctype.h> <string.h> <conio.h> "arbore.h"

/*---------------------------------------------------------*/ /* */ /* Functia getlin citeste urmatoarea linie de la tastatura*/ /* si recunoaste identificatorul si valoarea asociata lui.*/ /* Identificatorul este returnat in parametrul s, iar */ /* valoarea in parametrul val */ /* */ /*---------------------------------------------------------*/ void getlin(char *s ,int *val) { int i=0, j; char temp[Max]; gets(temp);/* citeste urmatoarea linie de la tastatura */ /* getlin 1 */ s[i]='\0'; *val=0; /* initializeaza valorile argumentelor */ while (temp[i]!='\0') /* atata timp cat nu a fost atins sfarsitul sirului */ /* getlin 2 */ if(isalpha(temp[i]))/* daca incepe un identificator */ /* getlin 3 */

http://labs.cs.utt.ro/labs/pc/html/node81.html (6 of 11) [22.07.2003 16:18:27]

Sursa programului

{ j=0; while (isalnum(temp[i])) s[j++]=temp[i++]; /*getlin 4*/ /* memoreaza identificatorul in s */ s[j]='\0'; /* memoreaza sfarsitul de sir */ /* getlin 5 */ } else if (isdigit(temp[i])) /* daca incepe un numar */ /* getlin 6 */ while (isdigit(temp[i])) /* getlin 7 */ { *val=*val*10+temp[i]-'0'; /* calculeaza valoarea numarului */ /* getlin 8 */ i++; } else /* altfel se trece peste caracterul curent */ i++; /* getlin 9 */ } /* getlin */

/*---------------------------------------------------------*/ /* */ /*Functia comanda_a realizeaza functionalitatea comenzii a */ /* */ /*---------------------------------------------------------*/ void comanda_a(void) { int val; char s[Max]; getlin(s, &val); /* citeste o linie de la tastatura */ if (strlen(s)!=0) /* daca linia e corecta */ introdu(s, val); else printf(" Eroare : linie incorecta \n"); } /* comanda_a */ /*---------------------------------------------------------*/ /* */ /*Functia comanda_t realizeaza functionalitatea comenzii t */ /* */
http://labs.cs.utt.ro/labs/pc/html/node81.html (7 of 11) [22.07.2003 16:18:27]

Sursa programului

/*---------------------------------------------------------*/ void comanda_t(void) { char s[Max]; nod *p; int val; getlin(s, &val); /* citeste o linie de la tastatura */ if (strlen(s)!=0) /* daca linia e corecta */ { if ((p=cauta(s))!=NULL) /* cauta nodul in lista */ printf("Identificator: %s Valoare: %d \n", p->id, p->valoare); else printf("Eroare: Identificator nedefinit \n"); } else printf(" Eroare: linie incorecta \n"); } /* comanda_t */ /*---------------------------------------------------------*/ /* */ /*Functia comanda_s realizeaza functionalitatea comenzii s */ /* */ /*---------------------------------------------------------*/ void comanda_s(void) { char s[Max]; int val; getlin(s, &val); /* citeste o linie de la tastatura */ if (strlen(s)!=0) /* daca linia citita e corecta */ sterge(s); /* sterge nodul din lista */ else printf(" Eroare: linie incorecta \n"); } /* comanda_s */

/*---------------------------------------------------------*/ /* */ /* Functia comanda_oper executa operatiile legate de */ /* comenzile +, -, * si /. Se citesc cei doi operatori si */ /* se executa operatia dorita.Rezultatul este afisat */ /* */
http://labs.cs.utt.ro/labs/pc/html/node81.html (8 of 11) [22.07.2003 16:18:27]

Sursa programului

/*---------------------------------------------------------*/ void comanda_oper(char c) { char s1[Max], s2[Max]; int val; nod *p1, *p2; getlin(s1, &val); /* se citeste primul operand */ getlin(s2, &val); /* se citeste al doilea operand */ if ((strlen(s1)!=0) && (strlen(s2)!=0)) if (((p1=cauta(s1))!=NULL) && ((p2=cauta(s2))!=NULL)) /* se verifica daca operanzii apar in lista */ { switch(c) /* in functie de tipul comenzii */ { case '+': val=p1->valoare+p2->valoare; break; case '-': val=p1->valoare-p2->valoare; break; case '*': val=p1->valoare*p2->valoare; break; case '/': if (p2->valoare!=0) val=p1->valoare/p2->valoare; else printf("Eroare:Impartire la 0\n"); break; } printf(" Rezultatul operatiei e %d \n", val); } else printf("Operand nedefinit \n"); else printf(" Eroare: linie eronata \n"); } /* comanda_oper */

/*---------------------------------------------------------*/ /* */ /* Functia meniu afiseaza meniul programului, citeste */ /* comanda si apeleaza subrutina care implementeaza */
http://labs.cs.utt.ro/labs/pc/html/node81.html (9 of 11) [22.07.2003 16:18:27]

Sursa programului

/* functionalitatea comenzii */ /* */ /*---------------------------------------------------------*/ void meniu(void) { char o; while (1) /* meniu 1 */ { clrscr(); /* se afiseaza meniul programului */ printf("a adauga in evidenta un id si val asociata\n"); printf("t tipareste valoarea asociata unui id \n"); printf("s sterge un id \n"); printf("l listeaza id-rii si valorile asociate lor\n"); printf("+ calculeaza suma pentru 2 id \n"); printf("- calculeaza diferenta pentru 2 id \n"); printf("* calculeaza produsul pentru 2 id \n"); printf("/ calculeaza impartirea pentru 2 id \n"); printf("f termina programul \n"); printf("\n Introduceti optiunea :"); o=getchar(); getchar(); /* meniu 2 */ switch (tolower(o)) /* meniu 3 */ { case 'a': comanda_a(); break; case 't': comanda_t(); break; case 's': comanda_s(); break; case 'l': listare(); break; case '+': case '-': case '*': case '/': comanda_oper(o); break; case 'f': return; default: printf(" Eroare : Comanda inexistenta \n"); } getchar();
http://labs.cs.utt.ro/labs/pc/html/node81.html (10 of 11) [22.07.2003 16:18:27]

Sursa programului

} }

/*---------------------------------------------------------*/ /* */ /* Functia main apeleaza functia meniu */ /* */ /*---------------------------------------------------------*/ void main(void) { meniu(); }

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node81.html (11 of 11) [22.07.2003 16:18:27]

Comentarea programului

next

up

previous

contents

Next: Problema propusa Up: Problema rezolvata Previous: Sursa programului Cuprins

Comentarea programului
Programul este compus din trei fisiere: Primul fisier, arbore.h contine definitia de tip pentru un nod al arborelui, precum si declaratiile functiilor ce apartin tipului abstract arbore binar ordonat. Al doilea fisier, arbore.c contine definitia tipului abstract arbore binar ordonat. Functia prezent cauta nodul din arborele indicat de parametrul t, care are cmpul id egal cu sirul indicat de parametrul id. prezent returneaza pointerul catre nodul n care s-a gasit identificatorul sau NULL daca acest nod nu exista. tipareste parcurge arborele n inordine si afiseaza continutul lui. tipareste afiseaza nti subarborele stng (apelndu-se recursiv pentru fiul stng al nodului curent), apoi nodul curent si n final subarborele drept (apelndu-se recursiv pentru fiul drept al nodului curent). elimina sterge din arborele cu radacina p nodul al carui cmp id este egal cu parametrul id. elimina returneaza radacina arborelui modificat. Daca p este NULL nseamna ca nu exista nodul cautat n arbore si se afiseaza un mesaj de eroare. Daca nodul curent are cmpul id mai mic dect parametrul id, atunci cautarea nodului continua n subarborele drept. Din acest motiv, elimina este apelata recursiv pentru fiul drept al nodului curent. n mod asemanator, daca cmpul id al nodului curent este mai mare ca si parametrul id, atunci elimina este apelata pentru fiul stng. Cnd nodul ce trebuie eliminat a fost gasit, distingem trei situatii. n prima, nodul nu are fiu stng. Se elibereaza memoria ocupata de nod si returnam fiul sau drept. Situatia a doua este cnd nodul nu are fiu drept si atunci returnam fiul sau stng. Al treilea caz este cnd nodul are ambii fii si atunci cautam pe cel mai mare nod care este mai mic ca cel care trebuie sters. El va fi mutat n locul celui care trebuie eliminat si apoi l stergem din vechea pozitie. ntotdeauna, acest nod nu are fiu drept (daca ar avea, acesta ar fi mai mare ca el),
http://labs.cs.utt.ro/labs/pc/html/node82.html (1 of 2) [22.07.2003 16:18:27]

Comentarea programului

iar eliminarea lui se face ca pentru un nod doar cu fiu stng. Pentru a gasi nodul precizat, vom parcurge n subarborele stng nlantuirile pentru fiul drept. Rutina supred realizeaza acest lucru. adauga introduce un nod nou n arborele indicat de parametrul t. Nodul are cmpul id egal cu parametrul id si cmpul valoare egal cu v. Rutina returneaza radacina arborelui modificat. Toate aceste functii au ca si parametru formal radacina arborelui prelucrat, radacina care nu este vizibila n exteriorul fisierului n care a fost definita (din cauza clasei de memorare static). Folosind aceste functii se definesc cauta, sterge, listare si introdu, operatorii prin care tipul abstract arbore ordonat este prelucrat. Al treilea fisier, main.c contine functia main, functia pentru citirea comenzilor, rutina de afisare si prelucrare a meniului si rutinele auxiliare pentru implementarea comenzilor.
next up previous contents

Next: Problema propusa Up: Problema rezolvata Previous: Sursa programului Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node82.html (2 of 2) [22.07.2003 16:18:27]

Problema propusa

next

up

previous

contents

Next: Probleme propuse spre rezolvare Up: Tipul abstract arbore binar Previous: Comentarea programului Cuprins

Problema propusa
O baza de date pastreaza informatii despre marfurile dintr-un magazin. Baza de date e realizata folosind un arbore binar ordonat. Sa se scrie un program care realizeaza urmatoarele: - introduce o noua marfa n baza de date; - tipareste baza de date ordonata dupa numele marfii si separat dupa pret; - sterge toate marfurile cu termenul de garantie expirat; - creeaza un arbore binar ordonat dupa pret, arbore care va contine doar marfurile cu un pret mai mic ca o valoare data p. Valoarea p se citeste.
Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node83.html [22.07.2003 16:18:27]

Probleme propuse spre rezolvare

next

up

previous

contents

Next: Setul 1 Up: carte Previous: Problema propusa Cuprins

Probleme propuse spre rezolvare


Subsections q Setul 1
q

Setul 2

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node84.html [22.07.2003 16:18:28]

Setul 1

next

up

previous

contents

Next: Setul 2 Up: Probleme propuse spre rezolvare Previous: Probleme propuse spre rezolvare Cuprins

Setul 1
1. Sa se realizeze un editor de texte. Textul initial este ncarcat dintr-un fisier, iar textul modificat este salvat ntr-un fisier nou. Editarea se face prin urmatoarele comenzi: I, m - insereaza o linie dupa linia m; D, m, n - sterge liniile ntre liniile m si n; R, m, n - nlocuieste liniile ntre m si n cu linii noi; E - termina procesul de editare.

2. Sa se genereze toate posibilitatile de planificare a unui turneu la care participa n concurenti, stiind ca doi concurenti se ntlnesc o singura data si un concurent disputa un singur joc pe zi.

3. Pentru elaborarea unui test de aptitudini se dispune de un set de n ntrebari. Fiecare ntrebare este cotata cu un numar de puncte. Sa se elaboreze toate chestionarele posibile care au un numar de ntrebari cuprins ntre a si b (a si b se citesc de la tastatura), astfel nct numarul total de puncte pe chestionar sa fie cuprins ntre p si q (p si q se citesc de la tastatura).

http://labs.cs.utt.ro/labs/pc/html/node85.html (1 of 8) [22.07.2003 16:18:29]

Setul 1

4. ntr-un grup de persoane, fiecare persoana cunoaste eventual alte persoane din grup. Sa se formeze toate echipele posibile, astfel nct pentru o echipa, fiecare persoana este cunoscuta de cel putin un membru al acelei echipe.

5. Se da un grup de orase si conexiunile ntre ele. Sa se gaseasca toate drumurile care trec prin toate orasele parcurgndu-le o singura data.

6. Pozitiile oraselor unei tari sunt date prin coordonatele lor carteziene. Sa se gaseasca configuratia retelei telefonice care ndeplineste conditiile: - orice oras este conectat la reteaua telefonica; - costul retelei (proportional cu lungimea liniilor telefonice) este minim.

7. O harta cuprinde n tari. Sa se gaseasca numarul minim de culori cu care pot fi colorate tarile, astfel nct doua tari vecine sa nu fie colorate cu aceeasi culoare.

8. Se considera o cale ferata de forma celei din Figura 11.1. Pe linia de intrare se afla n vagoane numerotate de la 1 la n. Notam cu I operatia de introducere a vagoanelor de pe prima pozitie pe linia de intrare n stiva, si cu S cea de extragere din vrful stivei catre iesire. Alte operatii nu sunt permise.

http://labs.cs.utt.ro/labs/pc/html/node85.html (2 of 8) [22.07.2003 16:18:29]

Setul 1

\begin{figure}\begin{center} \epsfig{file=stiva.eps, height=6cm}\end{center}\end{figure}

Figura 11.1:

Pentru un anumit numar de vagoane dat, programul va realiza urmatoarele: a) Dndu-se la intrare o secventa de forma : ISSI... sa se raspunda daca secventa respectiva de operatii poate fi executata. b) Dndu-se o permutare oarecare a numerelor 1...n, sa se spuna daca ea poate fi obtinuta pe linia de iesire, pornind de la n vagoane aflate n ordine pe linia de intrare. n caz afirmativ, sa se dea succesiunea de operatii I si S care duce la configuratia respectiva. c) Sa se tipareasca toate secventele de vagoane, care pot fi obtinute pe linia de iesire, pentru n dat initial.

9. Problema "Descendentilor dupa parinte": Petre stie ca este fiul lui Ion si mai stie ca este frate cu Virgil si Matei. Copiii lui Petre sunt Ilie si Marcu, iar ai lui Virgil sunt: Ionel si Petrica. Filip stie ca este fiul lui Matei si frate cu Ioana. Sabin este fiul lui Ionel.

http://labs.cs.utt.ro/labs/pc/html/node85.html (3 of 8) [22.07.2003 16:18:29]

Setul 1

Ion doreste sa stie numele tuturor nepotilor sai. Filip vrea sa stie daca pe bunicul lui l cheama Ilie. Ionel vrea sa stie daca este var cu Alexandru. Sa se scrie programul, care pe baza unor informatii de acest tip, este n masura sa raspunda la urmatoarele genuri de ntrebari: 1) Care sunt nepotii bunicului "nume"? 2) "nume1" este bunicul lui "nume2"? 3) "nume1" este var primar cu "nume2"? Se va verifica daca datele de intrare sunt consistente. Se considera ca doua persoane sunt diferite daca au nume diferite. Datele de intrare se citesc dintr-un fisier cu numele REGULI.DAT, avnd cte o regula pe fiecare linie. Regulile sunt de forma: "nume1"=FIU("nume2") sau "nume1"=FRATE("nume2") unde "nume1" si "nume2" sunt siruri de maxim 20 de litere (literele mici si cele mari se considera identice). Este permisa folosirea unor separatori de forma spatiu si tab. Detectarea caracterului $ la nceputul unei linii reprezinta sfrsitul sirului de reguli. Dupa ce s-au citit toate regulile, de pe liniile urmatoare se citesc tipul ntrebarii (1, 2 sau 3) si informatiile aferente acestuia, separate prin virgula. Fiecare ntrebare se citeste de pe o linie. Datele de iesire se vor scrie sub forma: "nume1"=BUNIC("nume2",...,"numep") pentru primul tip de ntrebare, sau ESTE, NU ESTE sau EROARE pentru celalalte doua tipuri de ntrebari. Raspunsurile sunt scrise pe linii distincte.

10. Un dictionar este scris ntr-un alfabet pentru care nu se stie daca exista sau nu o ordine ntre litere. Sa se stabileasca pe baza ordinii n care apar cuvintele n dictionar, daca exista sau nu ordine ntre literele alfabetului.

http://labs.cs.utt.ro/labs/pc/html/node85.html (4 of 8) [22.07.2003 16:18:29]

Setul 1

11. Un dreptunghi D, cu laturile paralele cu axele de coordonate este precizat prin coordonatele (ntregi) a doua vrfuri opuse. Sa se scrie un program care calculeaza si afiseaza aria si perimetrul conturului reuniunii D1 U D2 U ...de dreptunghiuri. Datele de test se citesc dintr-un fisier text, ce contine pe linii coordonatele vrfurilor unui dreptunghi n ordinea x1, y1, x2, y2.

12. Un numar de 2n + 1 persoane participa la discutii ce dureaza K zile. Sa se gaseasca toate variantele de asezare a persoanelor la masa de discutii, astfel nct o persoana sa nu aiba n 2 zile diferite aceiasi vecini.

13. Sa se scrie un program care citeste de la tastatura n mod repetat expresii cu doi operanzi ntregi si un operator (+, -, *, /). Operanzii sunt exprimati n cifre romane, iar numerele negative sunt precedate de caracterul minus. Programul afiseaza rezultatele exprimate tot n cifre romane.

14. Se da o expresie n notatie poloneza, care contine operatorii , AND si OR. Sa se verifice daca expresia $+, -, *, /, <, <=, >, >=, =, <>$ furnizata este corecta: a) Fiecarui operator sa-i corespunda doi operanzi. b) Sa nu existe operanzi carora sa nu le corespunda operatori. c) Sa fie respectate urmatoarele restrictii legate de tip: Pentru numar.
$+, -, *, /$

ambii operanzi trebuie sa fie numere. Rezultatul este tot un

http://labs.cs.utt.ro/labs/pc/html/node85.html (5 of 8) [22.07.2003 16:18:29]

Setul 1

Pentru boolean.

$<, <=, >, >=, =, <>$

operanzii sunt numere, iar rezultatul este

Pentru AND si OR operanzii sunt de tipul boolean, iar rezultatul este tot boolean.

15. Se da n plan un poligon oarecare P cu vrfurile P1, P2, P3, P4, ...Pn ale caror coordonate (numere ntregi) sunt citite dintr-un fisier. Sa se determine daca un punct dat A(p,q) este n interiorul, pe laturile, sau n exteriorul poligonului P.

16. Se da o succesiune de mase, fiecare sub forma a doua numere ntregi, ce reprezinta numarul de kilograme, respectiv de grame. Sa se tipareasca masele n cifre si cuvinte ca n exemplul de mai jos: 871 25 opt sute saptezeci si unu kilograme si douazeci si cinci grame 0 0 nimic 0 35 treizeci si cinci grame 113 0 o suta treisprezece kilograme

17. Studentii unui an pot alege 10 cursuri facultative: muzica, literatura, pictura, sanscrita, arheologie, canto, poetica, gastronomie, albaneza si puericultura. Optiunile fiecarui student se citesc de pe o linie cu urmatoarea structura: numele studentului (ca o succesiune de caractere care se ncheie cu un punct) si n continuare, pe zece pozitii, sunt spatii sau X. Fiecare pozitie se asociaza unui curs, n ordinea enumerarii de mai sus, iar X pe pozitia respectiva nseamna ca studentul a ales cursul respectiv. Un student poate alege oricte cursuri. De exemplu: Dumitrescu Dumitru. X XX

http://labs.cs.utt.ro/labs/pc/html/node85.html (6 of 8) [22.07.2003 16:18:29]

Setul 1

Studentul Dumitrescu Dumitru a ales pictura, canto si poetica. La nceputul dialogului se afla numarul studentilor, care nu depaseste 100. Sa se tiparesca, pentru fiecare curs, lista studentilor nscrisi. Cursurile vor aparea n ordinea descrescatoare a numarului de studenti nscrisi, iar listele de studenti sunt afisate n ordine alfabetica.

18. Dintr-o bara de lungime L se taie m repere de lungime l1, l2, ..., lm. Sa se gaseasca toate variantele de debitare a barei astfel nct pierderile de material sa fie minime. Se impune ca printr-o debitare sa se obtina cel putin cte un exemplar din fiecare reper. Valorile lui L si l1, l2, ..., lm sunt ntregi si sunt citite de la tastatura.

19. Un nume de fisier poate contine si caracterele ? si *. Sa se scrie un program care citeste o descriere pentru numele de fisiere si listeaza toate fisierele care corespund descrierii. Daca astfel de fisiere nu exista atunci se afiseaza numele cele mai apropiate de descrierea citita. Apropierea (distanta) ntre doua nume de fisiere este stabilita de numarul minim de operatii de stergere/ inserare/ nlocuire de caractere, necesare pentru a transforma primul cuvnt n al doilea. Exemplu: Pentru numele de fisiere: DIST.BAK DIST.EXE DIST.PAS RANDUL.1 RANDUL.2 RANDUL.3 C FLORINLL PAS PLANIFIC si descrierea *L*I*.*?* se va afisa (ntre paranteze este specificata distanta): DIST.BAK (1) DIST.EXE (1)
http://labs.cs.utt.ro/labs/pc/html/node85.html (7 of 8) [22.07.2003 16:18:29]

Setul 1

DIST.PAS RANDUL.1 RANDUL.2 RANDUL.3 FLORINLL PLANIFIC

(1) (1) (1) (1) (1) (1)

20. Un automat finit consta dintr-o multime de stari (care sunt numere ntregi n intervalul 1...n) si o matrice de tranzitie. Matricea de tranzitie precizeaza, pentru fiecare stare si fiecare caracter de intrare, starea urmatoare. Presupunem ca intrarile pot lua doua valori 0 sau 1. Anumite stari sunt stari finale. Presupunem ca n cazul nostru, starile finale sunt cele al caror numar este divizibil cu 7. Doua stari x si y sunt echivalente daca ele sunt identice sau daca ndeplinesc simultan conditiile: (1) Ambele sunt finale sau nefinale. (2) Pentru o intrare 0, ambele trec n stari echivalente. (3) Pentru o intrare 1, ambele trec n stari echivalente. Programul calculeaza multimea starilor echivalente, pentru un automat finit dat.
next up previous contents

Next: Setul 2 Up: Probleme propuse spre rezolvare Previous: Probleme propuse spre rezolvare Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node85.html (8 of 8) [22.07.2003 16:18:29]

Setul 2

next

up

previous

contents

Next: Bibliografie Up: Probleme propuse spre rezolvare Previous: Setul 1 Cuprins

Setul 2
1. Sa se realizeze un program pentru rezervarea locurilor la o companie de zbor. Programul are urmatoarele comenzi: ZBOR
$<$numar

zbor $> <$ numar total locuri $>$


$<$numar

adauga n evidenta cursa ANULARE


$<$numar

zbor $>$ n cazul n care aceasta nu exista deja.

zbor $>$

anuleaza cursa. Pasagerii (daca vor) si rezerva locuri la o alta cursa. LOC
$<$numar

zbor $>$

$<$nume

pasager $>$

Pasagerul cursa

$<$nume

pasager $>$ si rezerva (daca mai exista loc) un loc pentru

$<$numar

zbor $>$. Se permit pasageri cu acelasi nume. zbor $>$


$<$nume

RENUNT Pasagerul
$>$.

$<$numar $<$nume

pasager $>$
$<$numar

pasager $>$ renunta la locul sau din cursa

zbor

PRINT

$<$numar

zbor $>$
$<$numar

Afiseaza n ordine alfabetica lista pasagerilor cursei

zbor $>$.

http://labs.cs.utt.ro/labs/pc/html/node86.html (1 of 13) [22.07.2003 16:18:30]

Setul 2

Daca s-a introdus o comanda eronata se afiseaza "eroare" si se asteapta o noua comanda.

2. Se considera o structura de date abstracta de tip arbore binar ordonat asupra careia sunt executate urmatoarele operatii: adaugare, cautare si suprimare. Nodurile sunt ordonate functie de valoarea unui cmp cheie. Fiecarui nod i este atasat un contor de acces la nodul respectiv. La anumite intervale de timp, structura se reorganizeaza ntr-o noua structura de arbore binar ordonat, n care ordinea de creare a nodurilor este corespunzatoare valorilor descrescatoare ale contoarelor de acces. Se cere: a. Sa se precizeze structurile de date aferente structurii de arbore. b. Sa se defineasca rutinele care gestioneaza structura de date arbore (adauga, cauta, suprima ). c. Sa se defineasca rutina pentru reorganizarea arborelui.

3. Sa se realizeze un program pentru corectarea erorilor de ortografie dintr-un text. Cuvintele textului sunt introduse de la tastatura. Fiecare cuvnt este prelucrat astfel: a. Daca figureaza n dictionar el este copiat n fisierul de iesire. b. Daca nu figureaza n dictionar, atunci cuvntul este afisat la terminal si se cere utilizatorului una din urmatoarele optiuni: - Daca cuvntul este corect, atunci el trebuie adaugat n dictionar si n fisierul de iesire. - Daca cuvntul este incorect, atunci se introduce o noua forma corecta a cuvntului care se adauga la fisierul de iesire. - Daca cuvntul este incorect, atunci se introduce o noua forma corecta a cuvntului care se adauga la fisierul de iesire si n plus forma incorecta este retinuta, urmnd ori de cte ori este ntlnita, sa fie nlocuita automat cu forma corecta.

4. Un polinom P(x) se reprezinta ca o succesiune de tupleti (coeficient, putere), ambii ntregi. Sa se realizeze un program care executa nmultiri si adunari ntre
http://labs.cs.utt.ro/labs/pc/html/node86.html (2 of 13) [22.07.2003 16:18:30]

Setul 2

polinoame. Polinoamele se introduc sub forma unei succesiuni de numere ntregi. Primul indica numarul termenilor, iar urmatoarele N perechi de numere reprezinta fiecare cte un tuplet. Un polinom este urmat de + sau * , functie de operatia dorita. Dupa calcularea si afisarea rezultatului se citeste o valoare reala x, pentru care se evalueaza derivata polinomului. Observatie: La intrare, polinoamele se dau cu termenii n ordinea oarecare a puterii si pot aparea mai multi termeni pentru aceeasi putere a lui x.

5. Sa se realizeze un program care raspunde la urmatoarele comenzi: i - Citeste o linie cu urmatoarea structura: identificator numar numar este de forma: secventa_de_cifre sau secventa_de_cifre.secventa_de_cifre Ca raspuns la comanda, identificatorul este introdus n evidenta mpreuna cu valoarea asociata lui. Daca identificatorul apare n evidenta, se tipareste un mesaj de eroare si comanda este ncheiata. t - Tipareste n ordine alfabetica identificatorii din evidenta. s - Preia din intrare un identificator. Daca el exista n evidenta el este sters, n caz contrar se tipareste un mesaj de eroare. m - Preia din intrare o linie de forma: identificator numar Daca identificatorul apare n evidenta, valoarea lui este actualizata la noua valoare, n caz contrar, el este luat n evidenta. v - Tipareste identificatorii n ordinea inversa a valorii asociate lor. e - Citeste din intrare o expresie n notatie postfix. Operanzii pot fi identificatori sau numere avnd forma precizata, iar operatorii sunt $+ - * /$ . Valoarea asociata identificatorilor este extrasa din evidenta. Daca n expresie apare un identificator
http://labs.cs.utt.ro/labs/pc/html/node86.html (3 of 13) [22.07.2003 16:18:30]

Setul 2

neluat n evidenta, se tipareste un mesaj de eroare si se abandoneaza evaluarea expresiei. Se va calcula expresia, iar valoarea obtinuta se afiseaza. f - Termina programul.

6. Sa se realizeze un program pentru o tabela de referinte ncrucisate dupa cum urmeaza: citeste un text oarecare, ce se ncheie cu EOF. Dupa receptionarea sfrsitului de text se tipareste, n ordine alfabetica, lista identificatorilor ntlniti si, pentru fiecare identificator, numerele liniilor n care apare. Observatie: Tabela identificatorilor este organizata sub forma unei liste. Dupa fiecare 5 operatii n lista, aceasta se va reorganiza n ordinea descrescatoare a numarului de referiri ale nodurilor.

7. Sa se realizeze urmatorul program: Se citeste un text oarecare, care se ncheie cu caracterul `.`. n continuare, programul raspunde la un numar de comenzi dupa cum urmeaza: t - Tipareste n ordine alfabetica identificatorii din evidenta si pentru fiecare numarul de aparitii. l - Tipareste, n ordinea lungimii identificatorilor, identificatorii din evidenta si pentru fiecare numarul de aparitii. s - Citeste o valoare n ntreaga. Elimina din evidenta toti identificatorii care contin n vocale. a - Tipareste identificatorii din evidenta n ordinea descrescatoare a numarului de vocale continut. v - Se citeste o vocala c si un numar ntreg n. Se cere sa se tipareasca, n ordinea lungimii identificatorilor, acei identificatori care contin vocala c cel putin de n ori.

8. Sa se scrie un program care realizeaza urmatoarele: citeste un prim text care se ncheie cu caracterul `.` si memoreaza identificatorii prezenti n acel text. n cazul n
http://labs.cs.utt.ro/labs/pc/html/node86.html (4 of 13) [22.07.2003 16:18:30]

Setul 2

care un identificator apare de mai multe ori n acest prim text, el se retine o singura data. n continuare, se citeste un al doilea text care se ncheie cu EOF. Se cere sa se tipareasca lista identificatorilor prezenti n primul text si pentru fiecare identificator sa se mentioneze liniile din cel de-al doilea text n care este prezent. Lista este tiparita n ordine alfabetica.

9. Se citeste un text format din linii de forma: nume; loc_de_munca; adresa; Textul se ncheie cu EOF. Dupa citirea textului se cere sa se tipareasca n ordine alfabetica: a. Lista nominala de forma: nume adresa loc_de_munca b. Lista locurilor de munca n forma: loc_de_munca numar_angajati

10. Se citeste o succesiune de linii care se ncheie cu caracterul `.`. Aceste linii au ca prim caracter fie #, fie * si n rest contin un text oarecare. Se vor construi trei evidente separate continnd: identificatorii prezenti exclusiv n linii care ncep cu #, cei prezenti exclusiv n linii care ncep cu *, si cei prezenti n linii ce ncep cu #, ct si n linii ce ncep cu *. Fiecare identificator apare o singura data n evidenta. n continuare se citeste un text oarecare, format din mai multe linii, care se ncheie de asemenea cu caracterul `.`. Se cere sa se tipareasca separat, n ordine alfabetica, cele trei evidente, si, pentru fiecare identificator, sa se specifice de cte ori apare n textul citit. Apoi se citeste un al doilea text care se ncheie cu EOF. Se cere sa se tipareasca o lista unica cuprinznd toti identificatorii din cele trei liste, si, pentru fiecare identificator, sa se specifice de cte ori apare n ultimul text citit. Lista se va tipari n ordinea numarului de aparitii.

11. Se citesc dintr-un fisier datele corespunzatoare rezultatelor obtinute de candidatii la examenul de admitere. Datele se introduc ca o succesiune de linii de forma:

http://labs.cs.utt.ro/labs/pc/html/node86.html (5 of 13) [22.07.2003 16:18:30]

Setul 2

nume; sectie; medie Succesiunea de linii se ncheie cu EOF. Sectia este: "calculatoare" sau "automatica", iar media este un numar real. Daca dupa citirea liniei se constata ca sectia nu s-a dat corect, se cere rectificarea pna cnd operatorul raspunde cu una din cele doua variante acceptate. Daca dupa citirea liniei se constata ca numele este deja prezent n evidenta, se actualizeaza vechea nregistrare conform noilor informatii. Dupa ncheierea citirii se vor tipari: a. Lista candidatilor admisi, n ordinea mediilor n forma: nume sectia medie Se stie ca numarul de locuri este 40 la calculatoare si 40 la automatica. Sunt admisi primii 80 de candidati n ordinea mediilor, indiferent de sectia pentru care au optat. Repartizarea pe sectii se face n limita locurilor, n functie de optiunea candidatului, cu prioritate pentru cei cu medie mai mare. b. Lista candidatilor respinsi n ordine alfabetica, sub forma: nume medie

12. Se citeste o secventa de linii de forma: obiect atribut1 atribut2 ... prin care se asociaza unui obiect o secventa de atribute. Acelasi obiect poate aparea pe mai multe linii. Acelasi atribut poate aparea de mai multe ori pe liniile ce caracterizeaza acelasi obiect. Atributul multiplu este retinut o singura data. Secventa de linii se ncheie cu caracterul `.`. Se va scrie un program care raspunde interactiv la urmatoarele comenzi: a - Citeste un atribut si afiseaza n ordine alfabetica toate obiectele care au acel atribut. s - Citeste un atribut si l elimina pentru toate obiectele din evidenta. Daca un obiect nu mai are nici un atribut, el este eliminat din evidenta.

http://labs.cs.utt.ro/labs/pc/html/node86.html (6 of 13) [22.07.2003 16:18:30]

Setul 2

l - Citeste o linie care contine doar atribute. Se afiseaza toate obiectele care contin atributele de pe linie. Listarea obiectelor se face astfel: nti obiectele care contin doar atributele din secventa, apoi pe cele care au un atribut suplimentar, apoi cele care au doua atribute suplimentare, etc. b - Afiseaza n ordine alfabetica toate atributele si, pentru fiecare, numarul obiectelor care contin acel atribut. p - Citeste o linie ce contine doar atribute. Se elimina din evidenta obiectele ce contin atributele specificate. e - Termina programul.

13. Se citeste un fisier care contine linii de forma: nume prenume materia1 nota1 materia2 nota2 ... Secventa de linii se ncheie cu o linie vida. Fiecare linie contine numele, prenumele, materiile si notele obtinute de studentii unui an de studiu. Daca un student nu s-a prezentat la un examen, linia corespunzatoare va contine doar numele materiei fara a aparea si nota. De exemplu: Mihailescu Ion proiectare 5 compilatoare algoritmi 6. n continuare, programul raspunde interactiv la urmatoarele comenzi: afiseaza_top - Afiseaza lista ordonata functie de medie, a studentilor care au promovat toate examenele. Studentii restantieri sunt afisati ntr-o lista separata, ordonata functie de nume, pentru fiecare student indicndu-se numarul restantelor. restante - Calculatorul afiseaza prompterul
$>$ asteptnd

introducerea unui nume

de materie. Dupa ce s-a citit numele materiei sunt afisati, ordonat alfabetic, toti studentii care au acea materie restanta. n continuare, este afisat prompterul $>$ si se asteapta introducerea unei noi materii. Comanda se ncheie atunci cnd se tasteaza o linie vida.

http://labs.cs.utt.ro/labs/pc/html/node86.html (7 of 13) [22.07.2003 16:18:30]

Setul 2

modifica - Citeste numele si prenumele unui student. Apoi calculatorul afiseaza prompterul $>$ si asteapta introducerea unei materii si a notei. Pentru materia specificata se modifica nota studentului. Prompterul introducerea unei linii vide. elimina - Citeste un numar. Din evidenta sunt eliminati toti studentii cu un numar de restante mai mare sau egal cu numarul din comanda. terminare - Termina programul.
$>$ este

afisat pna la

14. Se citeste o secventa de linii de forma: id = cuvant1, cuvant2, ... prin care unui cuvnt i se asociaza o lista de sinonime. Exista posibilitatea ca un identificator sa apara de mai multe ori n partea stnga a semnului $=$, caz n care noua lista a sinonimelor se adauga la cea veche. Secventa de linii se ncheie cu caracterul `.`. n continuare, programul raspunde repetat la urmatoarele comenzi: c - Citeste un cuvnt si afiseaza ordonat alfabetic lista sinonimelor atasate lui. v - Afiseaza ordonat functie de numarul de consoane toti identificatorii din evidenta (cei care apar n stnga semnului $=$). s - Citeste un cuvnt si elimina din evidenta acel cuvnt mpreuna cu lista atasata de sinonime. x - Se citeste un cuvnt si se cere afisarea tuturor cuvintelor cu care el este sinonim. e - Termina programul.

15. Se citesc linii cu urmatoarele forme:

http://labs.cs.utt.ro/labs/pc/html/node86.html (8 of 13) [22.07.2003 16:18:30]

Setul 2

(1) numar: expresie n forma poloneza (2) delete: numar (3) afis: numar (4) evalueaza: numar (5) identificator: numar Pentru o linie cu forma (1) se construieste o lista nlantuita, cu un nod pentru fiecare element (operand sau operator) astfel: pentru un operator se construieste un nod nou, iar pentru un operand se verifica daca a aparut ntr-o expresie anterioara. n caz afirmativ, se considera nodul deja existent, iar n caz negativ se construieste un nod nou. Pentru o linie de forma (2), se sterge expresia cu numarul numar. Se sterg nodurile corespunzatoare operatorilor, precum si referintele spre nodurile operanzilor. Daca spre un operand nu mai indica nici o referinta atunci se sterge si nodul. Linia (3) afiseaza expresia cu numarul numar. Linia (4) evalueaza expresia cu numarul numar, iar linia (5) asociaza unui identificator o valoare.

16. Sa se realizeze un program pentru traducerea unui text dintr-o limba n alta. n plus, programul are facilitatea de a nlocui un cuvnt printr-un sinonim. Programul citeste dintr-un fisier linii de forma: cuvnt, echivalent strain, sinonim, sinonim, ... Secventa de linii se ncheie cu caracterul `.`. n continuare, se citeste un text care se ncheie tot cu caracterul `.`. Textul este parcurs cuvnt cu cuvnt si pentru fiecare cuvnt se afiseaza lista sinonimelor sale. Utilizatorul poate selecta sinonimul dorit, care este nlocuit automat n textul initial. Textul astfel obtinut este tradus automat. Daca nu exista un echivalent strain pentru un cuvnt atunci se afiseaza un mesaj de eroare la care utilizatorul raspunde cu:

http://labs.cs.utt.ro/labs/pc/html/node86.html (9 of 13) [22.07.2003 16:18:30]

Setul 2

A - cuvnt strain, daca cuvntul necunoscut este corect. C - cuvnt corect, daca cuvntul necunoscut este incorect. Textul tradus este afisat.

17. Dintr-un fisier se citesc linii avnd forma: identificator identificator numar identificator numar ... Secventa de linii se ncheie cu o linie vida. Fiecare linie introduce o unitate de masura noua, precum si subunitatile ei si relatiile de conversie ntre acestea si unitatea de baza. Numerele au forma: secventa_de_cifre.secventa_de_cifre. Exemplu de linie: m cm 0.01 mm 0.001. Aceeasi unitate de masura poate fi definita prin mai multe linii, dar toate unitatile si subunitatile se retin o singura data. Dupa citirea liniilor, programul raspunde interactiv la urmatoarele comenzi: (1) identificator
$<=$

numar unitate_de_masura

comanda asociaza unui identificator o valoare si o unitate de masura. n cazul n care identificatorul are deja o valoare asociata si daca unitatile apartin aceleiasi unitati de baza, dupa ce s-a dat un mesaj de atentionare, se retine pentru identificator ultima valoare citita. n caz contrar, se da un mesaj de eroare si comanda se ncheie. (2) identificator conversie unitate_de_masura converteste valoarea asociata identificatorului n unitatea specificata. (3) identificator tiparire pi pf pi si pf sunt doua numere ntregi. Afiseaza valoarea asociata identificatorului cu pi cifre la partea ntreaga si pf cifre pentru partea zecimala. De exemplu, daca a este 1305 cm, comanda: a tiparire 1 2 va afisa: a = 1.30 E3 cm.

http://labs.cs.utt.ro/labs/pc/html/node86.html (10 of 13) [22.07.2003 16:18:30]

Setul 2

(4) stergere valoare unitate_de_masura Sterge din evidenta toti identificatorii care au o valoare mai mica dect cea din linia de comanda, iar unitatile apartin aceleiasi unitati de baza. (5) afisare Afiseaza identificatorii din evidenta n urmatoarea forma: unitate_de_baza : unitati de masura apartinnd unitatii de baza Identificatorii sunt afisati ordonat alfabetic.

18. Sa se scrie un program care rezolva urmatoarea problema. Se citesc dintr-un fisier linii de forma: identificator = numar unde numar are o parte ntreaga, care este eventual urmata de o parte zecimala. Partea ntreaga si cea zecimala sunt secvente de cifre care sunt separate prin punct. Secventa de linii se ncheie cu caracterul `.`. Fiecare identificator este retinut ntr-o evidenta mpreuna cu valoarea asociata lui. Daca identificatorul apare deja n evidenta, de fiecare data se retine si noua lui valoare. n continuare, programul raspunde interactiv la urmatoarele comenzi: s numar - unde numar are forma prezentata anterior. Se elimina din evidenta toti identificatorii care au asociata valoarea din comanda. talf - afiseaza n ordine alfabetica toti identificatorii si pentru fiecare identificator valorile asociate lui. c identificator - cauta identificatorul si, daca l gaseste, afiseaza toate valorile atasate lui. tval - afiseaza, n ordinea valorii, identificatorii care au valoarea respectiva. e - termina programul.

19. Se citeste o secventa de reguli (o regula pe linie) cu forma: identificator = identificator; identificator; ... Secventa de linii se ncheie cu carcaterul `.`. Prin aceste reguli se asociaza fiecarui
http://labs.cs.utt.ro/labs/pc/html/node86.html (11 of 13) [22.07.2003 16:18:30]

Setul 2

identificator din stnga semnului = o secventa de identificatori. Un identificator poate fi definit prin mai multe reguli. Regulile sunt memorate ntr-o evidenta. n continuare programul raspunde interactiv la urmatoarele comenzi: a - Afiseaza ordonat, functie de identificatorul care apare n stnga lui =, toti identificatorii si secventele asociate lor. c - Citeste un cuvnt. Pentru acest cuvnt se afiseaza toti identificatorii atasati. n cazul n care nu exista identificatori atasati, programul afiseaza un mesaj de eroare corespunzator. s - Citeste un cuvnt, dupa care se sterg din evidenta toate regulile pentru care cuvntul citit apare n partea stnga a semnului =. f - Citeste un cuvnt. Pentru cuvntul citit, pe baza regulilor atasate, se formeaza un grup astfel: doua reguli apartin grupului daca partea din dreapta semnului = ncepe cu cel putin un identificator comun. Acest grup este afisat mpreuna cu partea comuna. e - Termina programul.

20. Sa se scrie un program care implementeaza diferite operatiuni bancare. Programul citeste de la tastatura numele clientului (un singur cuvnt, doar litere mici) si o parola (parola trebuie "ascunsa" la citire). Parola este criptata (algoritmul de criptare aplica un XOR ntre fiecare caracter al parolei si o cheie de criptare, cheia reprezentnd un numar ntreg pe 8 biti (tipul char) care reprezinta media codurilor ASCII ale literelor numelui) si este confruntata cu parola criptata aflata n fisierul "passwd.txt" sub forma: nume_client_1 parola_criptata_1 nume_client_2 parola_criptata_2 ...... Daca parola e corecta, se afiseaza un prompt (: sau comenzile:
$>$)

si se asteapta una din

http://labs.cs.utt.ro/labs/pc/html/node86.html (12 of 13) [22.07.2003 16:18:30]

Setul 2

restituire suma - se restituie suma specificata (daca soldul acopera suma ceruta); depunere suma - depunere suma n cont; sold - afisare sold. Informatiile bancare sunt memorate ntr-un fisier de conturi; la ncheierea fiecarei operatii, se actualizeaza fisierul de conturi.
next up previous contents

Next: Bibliografie Up: Probleme propuse spre rezolvare Previous: Setul 1 Cuprins Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node86.html (13 of 13) [22.07.2003 16:18:30]

Bibliografie

next

up

previous

contents

Next: About this document ... Up: carte Previous: Setul 2 Cuprins

Bibliografie
6 Brian W. Kernighan, Denis M. Ritchie, Le Langage C, Dunod, Paris, 2000 6 Niklaus Wirth, Algorithms & Data Structures, Prentice-Hall, Englewood Cliffs, 1986 6 Herbert Schildt, Teach Yourself C, McGraw-Hill, Berkeley, 1995 6 Alina Ilin, Alexa Doboli, Tehnici de Programare - ndrumator de laborator, Universitatea "Politehnica", Timisoara, 1996 6 Samuel P. Harbison, Guy L. Steele, C - A Reference Manual, Prentice Hall, Englewood Cliffs, 1991 6 Steve Oualine, Practical C Programming (Nutshell Handbook), O''Reilly, Cambridge, 1997

Cristian Gavrila 2001-10-02

http://labs.cs.utt.ro/labs/pc/html/node87.html [22.07.2003 16:18:31]

You might also like