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 câmp pentru pastrarea identificatorului, care este indicat de char *id, un câmp pentru memorarea valorii asociate identificatorului, câmpul int valoare, si un câmp pentru a crea înlantuirea cu nodul urmator din lista, câmpul struct elem *urm. Lista este ordonata crescator functie de câmpurile 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 apelând 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 (apelând functia caut). Daca identificatorul apare în lista, atunci se afiseaza valoarea asociata lui, în caz contrar se tipareste un mesaj de eroare adecvat.

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 */ memoreaza caracterul ''$\backslash$0'' ce indica sfârsitul identificatorului. Daca la parcurgerea lui temp este întâlnita 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 */, calculându-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, cautând 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 încât sa indice începutul listei. La sfârsitul 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 != 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 ramâne 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.

introduc creeaza un nod nou care contine sirul indicat de parametrul char *s, iar câmpul lui de valoare este egal cu parametrul int v. Nodul este inserat în lista indicata de parametrul nod *lista, astfel încât dupa introducere, lista ramâne 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, câmpurile id si valoare sunt initializate corespunzator. Linia /* introduc 2 */ parcurge lista cautând 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