STRUCTURI DE DATE. FUNCTII DE TIMP (CU STRUCTURI) 1. Structuri de date O structura de date grupeaza date diferite. Fiecare structura poate fi considerata ca un nou tip de date, introdus prin declararea structurii respective. Forma generala pentru declararea unei structuri este: struct nume { declaratii; }nume1, nume2,... numen; Oricare din nume, nume1,...numen, poate lipsi, cu conditia sa existe în declaratie cel putin unul din ele. - struct este cuvânt cheie; - nume se poate utiliza pentru a declara un nou tip de date, introdus prin declaratia de structura; - nume1 ... numen sunt variabile care au tipul declarat nume. Exemplu - data calendaristica poate fi declarata struct data{ int zi; char *nume_luna; int an; }; Am declarat tipul data. Daca scriem: struct data d; atunci d va fi o variabila de tip data pentru care se aloca memorie. Acelasi lucru se poate declara si astfel: struct data { int zi; char *nume_luna; int an; }d; situatie în care se face declararea si alocarea de memorie pentru noul tip de data. Variabilele declarate într-o structura se numesc membri ai structurii. Între membrii unei structuri pot fi si alte structuri. Exemplu Sa consideram un model simplificat al unei structuri de date referitoare la personalul unei firme: struct personal { char nume[20]; char init_tata; char prenume[20]; struct data data_nast, data_ang; }pers; Orice structura poate fi initializata. Exemplu: struct personal pers= {"Popescu", `I', "Vasile", 19, "Ianuarie", 1960, 1, "Septembrie", 1984}; Accesul la elementele structurii se face cu ajutorul operatorului de selectie "." aflat pe prima linie a tabloului de prioritati a operatorilor. De exemplu, an din structura d, se refera astfel: d.an. Daca dorim sa aflam anul nasterii lui pers, vom scrie astfel: pers.data_nast.an Membrii structurii pot fi utilizati în diferite expresii, conform tipului lor astfel: Exemplu if (d.an == 2001) printf ("Mileniu TREI a sosit"); sau: struct data d1, d2; d1 = d2; Membrii unei structuri pot fi parametrii unei functii. Se pot utiliza si pointeri la structuri , mai ales când acestea sunt folosite ca parametri în functii. Spre exemplu, se poate apela functia f, al carei parametru este adresa de început a unei zone de memorie alocata structurii d astfel: f(&d) Functia f va fi declarata astfel: void f(struct data *pd) unde pd este un pointer la structura data , care la apel se va initializa cu adresa structurii (&d). Pentru a accesa un membru al ei, utilizam operatorul de selectie indirecta "->" tot cu prioritate maxima. Exemplu pd->an Acest acces este echivalent cu (*pd).an dar se prefera utilizarea operatorului -> Deci, pentru a avea acces la membrii unei structuri în corpul unei functii - se declara functia având parametru pointer spre acea structura functie( struct nume_structura *nume_parametru_formal) - apelul se face astfel : functie(&nume_parametru_efectiv) - iar în corpul functiei se folosesc constructii de genul: nume_parametru_formal->nume_membru Ca orice tip de data, tipurile structurate pot fi denumite de utilizator si în acest sens se utilizeaza specificatorul typedef astfel: typedef struct data { int zi, luna, an; }DC; O structura particulara se va declara, în continuare, utilizând tipul DC definit mai sus. DC d; care este echivalenta cu declaratia: struct data d; Se recomanda, pentru lizibilitatea programelor, ca noile nume date de utilizator sa fie scrise cu majuscule (ex. DC). Exemplu typedef struct{ double real, imaginar; } COMPLEX; Se poate calcula modulul unui numar complex, utilizând urmatoarea functie: double modul (COMPLEX *a) { return (sqrt(a->real * a->real + a->imaginar *a->imaginar)); } Functia modul a utilizat functia sqrt din biblioteca math.h Se pot defini tablouri de structuri. Exemplu Revenind la structura de tip personal, putem defini un tablou de structuri astfel: struct personal{ char nume [20]; char init_tata; char prenume [20]; struct data data_nast, data_ang; }tab pers[20]; În acest exemplu fiecare element tab_pers[i] este o structura de tip personal. Daca am fi declarat: struct personal *tab_pers[20]; atunci tab_pers ar fi fost un tablou de pointeri la structuri. Deci tab_pers[i] este un pointer la o structura de tip personal. 2. Functii de timp a) time_t time(time_t *timer); - returneaza numarul de secunde scurse de la 00:00:00 GMT, 1 ianuarie 1970, memorând valoarea respectiva la adresa timer (cu conditia sa fie diferita de NULL) - alegerea anului 1970 ca referinta s-a facut pentru compatibilitatea cu UNIX (referinta DOS fiind 1980); - are prototipul în time.h; - daca se apeleaza în forma time(NULL), valoarea este numai returnata, nu si memorata; - time_t este definita în time.h ca long (typedef long time_t;); Exemplu: time_t *z,x; char *sir; z=(time_t*)malloc(sizeof(time_t)); x=time(z); sir=ctime(z); printf("timpul scurs este %ld, data este: %s\n",x,sir); ... double difftime(time_t time2, time_t time1); - calculeaza diferenta (în secunde) între doua momente de timp (memorate în time1 si time2, tot în secunde); - are prototipul în time.h; - rezultatul diferentei este returnat ca un double; b) char *ctime(const time_t *time); - functia converteste valoarea timpului de la adresa pointata de argumentul din time (completata printr-un apel al functiei time() într-un sir de 26 de caractere de forma: DDD MMM dd hh:mm:ss YYYY , unde DDD=ziua (Mon, Tue...) MMM=luna (Jan,Feb...) dd=ziua din luna (1..31) hh:mm:ss=ora:min:sec YYYY=an - are prototipul în time.h; - returneaza un pointer pe sirul de caractere format (o zona de memorie alocata static, rescrisa la fiecare apel); Exemplu: .... time_t *z,x; char *sir; z=(time_t*)malloc(sizeof(time_t)); x=time(z); sir=ctime(z); printf("data este: %s\n",sir); ... Rezultatul este de forma: Thu Aug 23 12:15:30 2001 c) int stime(time_t *tp); - fixeaza data si ora sistem; - are prototipul în time.h; - tp pointeaza pe valoarea dorita, masurata în secunde de la 00:00:00 GMT, 1 ianuarie 1970; - returneaza 0; Exemplu: ... time_t t; char *data; t=time(NULL); //afla timpul scurs data=ctime(&t); // scoate data în formatul specific: DDD MMM dd hh:mm:ss YYYY printf("Data curenta este %s", data); t=t-24L*60L*60L; //scade un numar de secude pentru a ajunge în ziua precedenta; se foloseste L //pentru long int stime(&t) //seteaza data curenta la noua valoare printf("Data de ieri este: %s", ctime(&t)); //o afiseaza .... //se revine la data curenta t=t+24L*60L*60L si se seteaza d) void getdate(struct date *datep); - citeste data sistem, completând structura pointata de datep; - are prototipul în DOS.H; - structura date este definita ca: struct date{ int da_year; /*anul curent*/ char da_day; /*ziua din luna*/ char da_mon; /*luna (1 = ianuarie)*/ }; Exemplu: ... struct date d; getdate(&d); printf("an:%d luna:%d zi:%d",d.da_year,d.da_mon,d.da_day); ... e) void gettime(struct time *timep); - citeste ora sistem, completând structura pointata de timep; - are prototipul în DOS.H; - structura time este definita ca: struct time { unsigned char ti_min; unsigned char ti_hour; unsigned char ti_sec; unsigned char ti_hund; /*sutimi de secunda*/ }; Exemplu: ... struct time t; gettime(&t); printf("ora curenta este %2d:%2d:%2d:%2d",t.ti_hour,t.ti_min,t.ti_sec,t.ti_hund); ... f) void setdate(struct date *datep); - fixeaza data sistem conform continutului structurii de tip date pointata de datep; - are prototipul în DOS.H; Exemplu: struct date d_noua,d_veche; getdate(&d_veche); //retine data curenta d_noua.da_year=2003; //completeaza structura cu valori d_noua.da_mon=5; d_noua.da_day=30; setdate(&d_noua); //seteaza noua data printf("an:%d luna:%d zi:%d",d_noua.da_year,d_noua.da_mon,d_noua.da_day); setdate(&d_veche); //restaureaza vechea data printf("an:%d luna:%d zi:%d",d_veche.da_year,d_veche.da_mon,d_veche.da_day); ... g) void settime(struct time *timep); - fixeaza ora sistemului conform valorilor din structura de tip time, pointata de timep; - are prototipul în DOS.H; Exemplu: ... struct time t; gettime(&t); printf("ora curenta este %2d:%2d:%2d:%2d",t.ti_hour,t.ti_min,t.ti_sec,t.ti_hund); t.ti_min=t.ti_min+5; //adauga 5 minute settime(&t); printf("ora modificata este %2d:%2d:%2d:%2d",t.ti_hour,t.ti_min,t.ti_sec,t.ti_hund); ... h) struct tm *localtime(const time_t *timer); - functia primeste ca parametru adresa unei valori returnate de time() si returneaza un pointer la o structura de tip tm completata corespunzator; - are prototipul în time.h; - structura tm este definita în time.h astfel: struct tm { int tm_sec; /*secunda */ int tm_min; /*minut */ int tm_hour; /*ora 0..23 */ int tm_mday; /* ziua din luna 1..31 */ int tm_mon; /* luna din an 0..11 */ int tm_year; /*anul - 1900*/ int tm_wday; /*0..6, 0=duminica */ int tm_yday; /*ziua din an 0..365 */ int tm_isdst; /* este nenul daca se aplica si corectia pentru ora de vara - USA (daylight saving time) */ }; - returneaza adresa unei structuri statice, rescrisa la fiecare apel; i) time_t mktime(struct tm *t); - completeaza datele calendaristice din structura de tip tm pointata de t; - are prototipul în time.h; - returneaza aceeasi valoare ca time(), -1 daca nu se poate determina corect tm_wday sau tm_yday; (adica ziua din saptamâna ca sir de caractere sau ziua din an , ca numar) j) char *asctime(const struct tm *tblock); - converteste data si ora în ASCII; - are prototipul în time.h; - face conversia datelor dintr-o structura de tip tm, pointata de tblock, într-un sir de caractere, de o maniera identica cu functia ctime(); Pentru o formatare mai sofisticata a afisarii timpului se poate folosi functia strftime(). Exemplu: ... time_t t; struct tm *tblock; t=time(NULL) // afla timpul tblock=localtime(&t); //converteste si completeaza datele din structura tblock printf("Data si Ora locala sunt %s" , asctime(tblock)); ... Teme: Problema nr. 1 Sa se scrie un program care testeaza doua functii proprii de conversie a datei: - daca se da ziua, luna si anul sa se calculeze ziua din an (a câta zi din an este) - daca se da ziua din an si anul, sa se determine ziua si luna care îi corespund. Indicatie: Se va folosi o structura de forma struct data { int zi, luna, an, zian; }d; Se va folosi, de asemenea, un tablou pentru numarul de zile din cele 12 luni ale anului. Se va tine cont si daca anul este bisect (se pot declara 2 tablouri, pentru an bisect /nebisect) Functiile vor folosi ca argument un pointer pe structura d. Apelarea se va face utilizând f(&d). Problema nr. 2 Sa se determine frecventa de aparitie a cuvintelor cheie dintr-un text. Textul se memoreaza pe linii într-un tablou de siruri (de exemplu). Textul va contine cel putin 3 cuvinte cheie. Se va folosi un tablou de structuri de tipul: struct chei { char *cuv; int contor; /*nr.de aparitii a cuvântului*/ } tab_chei[]= {"break", 0, "case", 0, /*alte cuvinte cheie */ "while", 0, }; Problema nr. 3 Sa se scrie un program care citeste de la tastatura data dorita (sub forma zz/ll/aaaa, cu cifre pentru luna-zi-an, sau zz-mmm-aaaa, cu cifre pentru zi-an si trei caractere pentru numele lunii - varianta româna ), seteaza data sistem cu noua valoare, o afiseaza, dupa care se termina refacând data initiala. Problema nr. 4 Se considera un tablou de structuri de tip personal: struct personal{ char *nume; char *prenume; int virsta; }tab_pers[20]; Sa se scrie un program care realizeaza urmatoarele: - citeste datele pentru n persoane; n cerut de la tastatura - afiseaza datele pentru aceste n persoane intr-un tabel (cu cap de tabel) - afiseaza toate persoanele care au vârsta sub 30 ani - afiseaza toate persoanele ordonate alfabetic dupa nume, prenume si chiar dupa vârsta, în cazul în care se gasesc persoane cu acelasi nume si prenume (nu se face distinctie între litere mari si mici).