Structurile sunt tipuri de date agregate care grupeaza mai multe date, in general de tipuri diferite - desi nu obligatoriu! - care au o caracteristica comuna: descriu diverse atribute ale aceleiasi entitati.
Ex. Datele unui angajat dintr-o intreprindere, datele care definesc o adresa (domiciliu) coordonatele unui punct din spatiul bi, tri, n-dimensional, etc. Structurile sunt echivalente cu tipuri de date similare din alte limbaje, precum tipul record din Pascal.
Intrucat fiecare tip de "obiect" care se modeleaza printr-o structura are atribute distincte, structurile nu sunt de fapt tipuri concrete ci permit definirea (de catre programator) a caracteristicilor tipului respectiv. Caracteristicile respective alcatuiesc un "sablon", o matrita care specifica atributele tuturor obiectelor de acelasi tip.
Structurile (ca tip de date specifice) se declara in felul urmator:
struct eticheta_tip
Cuvantul cheie struct p 333h72d recizeaza ca declaratia care urmeaza este pentru un nou tip de date ale carui atribute sunt precizate de membrii structurii. Un anumit tip de structura poate fi precizat, de exemplu pentru a declara instante ale acelei structuri (variabile), cu ajutorul etichetei care precizeaza ce tip de structura se declara
O structura poate fi initializata cu Ajutorul unei liste de initializatori, cate unul pentru fiecare membru. Exemplu
struct s ;
struct s v=; /*declaratia si initializarea variabilei v de tipul struct s*/
O structura poater fi asignata altei structuri, ca o entitate;
u=v; /*membrii variabilei u au aceleasi valori ca si cei ai variabilei v */
Variabilele de tip structura pot fi transmise ca argumente la functii si pot fi returnate ca valori ale unei functii.
struct s funct(struct s x); /*declaratie de functie care are un argument de tip struct s */
/* si returneaza o valoare de tip struct s */
u=funct(v); /*apelul functiei si asignarea valorii returnate la o variabila de tip struct s*/
Variabilele de tip structura nu sunt utile daca nu pot fi acesati, individual, membrii lor. Accesul la membrii unei variabile de tip structura se face cu ajutorul operatorului . (punct).
Generic:
nume_variabila.nume_membru /* valoarea membrului nume_membru al variabilei
/* cu numele nume_variabila */
Ex. v.c /* membrul c al variabilei v */
u.c /* membrul c al variabilei u */
Membrii unei structuri pot fi structuri (de un tip diferit!).
Ex.
struct point ;
struct rectangle ;
struct s; /* eroare: membrii unei structuri nu pot fi structuri de acelasi tip*/
Variabilele de tip structura fiind. variabile, ele ocupa o anumita zona de memorie si ca atare au o adresa - adresa de inceput a zonei de memorie unde este stocata variabila respectiva. Adresa unei variabile structura se poate memora intr-o variabila de tipul pointer la o structura de acel tip.
Ex.
struct s v, *pv=&v;
struct s t[DIM];
Structurile reprezinta metoda preferata pentru implementarea listelor, arborilor, tablourilor de cautare (vezi si discutia referitoare la Probleme care implica utilizarea tablourilor sau a listelor
Structurile nu pot contine, ca membri, structuri de acelasi tip! Explicatia consta in imposibilitatea rezervarii de spatiu pentru o variabila de acest tip, dupa cum rezulta din exemplul urmator:
struct s v;
Oridecate ori compilatorul intalneste o declaratie (de definire) a unei variabile, una din actiunile intreprinse o reprezinta generarea de cod pentru rezervarea de spatiu ("crearea variabilei") pt variabila respectiva. In cazul unei variabile structura, aceasta implica rezervarea de spatiu pentru fiecare membru in parte.
v.c - 1 byte
v.n - variabila structura
v.n.c - 1 byte
v.n.n - variabila structura
v.n.n.c - 1 byte
v.n.n.n - variabila structura.
.si procesul nu poate fi terminat!
In schimb, o structura poate contine ca membru un pointer la o structura de acelasi tip
struct s v;
v.c - 1 byte
v.next - 2 (4) bytes
si procesul de rezervare de spatiu s-a incheiat!
Structurile care contin ca membri pointeri spre structuri de acelasi tip se numesc structuri cu autoreferire. Structurile cu autoreferire reprezinta mijlocul de implementare a listelor, arborilor, tabelelor de cautare sau hashing.
Limbajul C permite definirea de noi nume de tipuri pentru tipuri de date existente. Aceasta facilitate este accesibila prin operatorul typedef. Sintaxa operatorului este:
OBS. Noul nume de tip, creat cu typedef poate fi folosit in acelasi mod ca si vechiul nume, cu care este sinonim!
Ex.
typedef int Coord; /* Coord este un intreg */
typedef struct tnode * Treeptr; /*Treeptr este un pointer la struct tnode */
typedef char * String; /* String este un pointer la char */
OBS. In ultimul exemplu, desi String este sinonim cu un pointer la char si deci poate fi folosit (legal) in :
char c;
String p=&c;
Dar o astfel de utilizare ar fi improprie, intrucat, string inseamna "sir" (de caractere, in context!), ceea ce nu e .cazul in exemplul anterior! Exemplul urmator indica o utilizare pertinenta pentru String:
char t[ ] = "Timisoara";
String p = s, q;
Q = (String)malloc( strlen(p)+1);
intrucat, valoarea lui p este intradevar adresa unui sir (de caractere)!
Numele "create" cu typedef au aceeasi semnificatie ca si sinonimele lor si pot fi utilizate oriunde se poate utiliza un nume de tip predefinit!
Uniunile sunt tipuri de date care permit partajarea aceluiasi spatiu de memorie de catre mai multe variabile (de tipuri diferite) care nu trebuie sa coexiste (simultan). Sintaxa declaratiei unei uniuni:
union eticheta ;
Ca si in cazul structurilor, declaratia unei uniuni precizeaza un "model"/"sablon" si ca atare nu este insotita de rezervare de spatiu. Spatiu se rezerva doar in momentul declararii unei variabile de tip uniune.
Spatiul necesar unei variabile uniune trebuie sa fie (este) suficient pentru a pastra cel mai mare (care are nevoie de cel mai mult spatiu) membru.
Initializarea (pe linia de declaratie a) unei variabile uniuni se poate face doar cu o valoare corespunzatoare primului membru.
Ca si in cazul structurilor, variabilele uniune pot fi asignate/copiate (inclusiv transmise ca argumente actuale la apelul unei functii, respectiv returnate de o functie), li se poate prelua adresa si membri sai pot fi accesati individual. Operatorul de acces la membri este acelasi ca la structuri, adica .
Cade in sarcina programatorului sa urmareasca care dintre membri variabilei uniune este memorat in aceasta. Exista o modalitate standard pentru a realiza aceasta urmarire.
Ex.
#define INT 0
#define FLOAT 1
#define STRING 2
union u {
int ival;
float fval;
char *sval;
; v;
int v_type;
Oridecate ori se memoreaza un membru in variabila uniune v, actiuneaeste insotita de actualizarea valorii variabilei v_type:
v.ival=val_intreaga;
.
v.fval=val_flotanta;
v_type=FLOAT;
.
v.sval=adresa_sir_caractere;
v_type=STRING;
Oridecate ori trebuie "exploatata" valoarea variabilei uniune, se verifica tipul valorii memorate curent in v prin "interogarea" variabilei v_type:
if(v_type == INT)
printf(" %d ", v.ival; /* "exploateaza" pe v.ival */
else if (v-type == FLOAT)
printf(" %f ", v.fval); /* "exploateaza" pe v.fval */
else if(v_type == STRING)
printf(" %s ", v.sval; /* "exploateaza" pe v.sval */
else
printf("bad union member! ");
|