STRUCTURI, TIPURI UTILIZATOR
Datele de acelaşi tip se pot grupa în tablouri. Limbajul C permite gruparea unor date de tipuri diferite sub alte forme de organizare numite structuri.
Tablourile au un tip şi anume tipul comun elementelor lor. Astfel, distingem tablouri de tip întreg, de tip caracter, de tip flotant, etc. În cazul structurilor, nu mai avem un tip comun. Fiecare structură reprezintă un nou tip de date, tip care se introduce prin declaraţia structurii respective.
Un exemplu simplu de structură este data calendaristică, cu componentele următoare:
ziua;
luna;
anul.
unde: ziua şi anul sunt date de tip întreg iar luna este un tablou de caractere.
Structura ca şi tabloul, este o mulţine ordonată de elemente. În exemplul de mai sus se consideră că ziua este primul ei element, luna este al doilea iar anul este ultimul ei element. Trebuie să precizăm că referirea la componentele unei structuri nu se mai face cu ajutorul indicilor ci prin calificare.
DECLARAŢIA DE STRUCTURĂ
O structură se poate declara în mai multe feluri, astfel:
Formatul 1:
struct nume_structura
{ lista_declaratii
};
Cu ajutorul acestui format se introduce un nou tip de dată cu numele nume_structură. Lista de declaraţii este formată din declaraţii obişnuite. Tipul data_calendaristica îl putem introduce astfel:
struct data_calendaristica
{ int ziua;
char luna[11];
int anul;
};
O astfel de declaraţie se numeşte declaraţie de tip. Să reţinem că unui nou tip de date nu i se alocă memorie, el este doar contabilizat ca un nou tip utilizator pe lângă tipurile predefinite ale limbajului C.
Formatul 2:
struct nume_structura
{ lista_declaratii
}lista_variabile;
Un astfel de format introduce tipul utilizator nume_structura şi declară o listă de varibile în care fiecare element din listă are tipul nume_structură. Prin exemplu următor se introduc variabilele dc1 şi dc2 ca date elementare de tipul data_calendaristica şi tabloul dc de 13 componente.
struct data_calendaristica
{ int ziua;
char luna[11];
int anul;
} dc1, dc2, dc[13];
Formatul 3:
struct { lista_declaraţii
} lista_variabile;
Acest format se foloseste dacă nu vrem sa dăm nume noului tip structurat şi totodată dacă nu mai vrem să-l folosim. Deci nu vom mai pute declara alte date de tipul structurat nou introdus pentru că tipul nu are nume.
Exemplu:
struct { int ziua;
char luna[11];
int anul;
} dc1, dc2, dc[13];
S-au declarat varibilele dc1, dc2 şi tabloul dc având noul tip structurat utilizator dar nu se mai doreşte să declarăm alte date de acest tip.
Observaţii:
1o. Dacă se foloseşte formatul 1 atunci pentru a declara date de tipul utilizator nou introdus se foloseşte o construcţie de forma:
struct nume_ structura lista_variabile;
Compilatorul alocă memorie varibilelor din lista de variabile, tratând această construcţie ca şi declaraţiile obişnuite.
2o. Componentele unei structuri pot fi ele însele date structurate. O componentă care nu este structurată se numeşte componentă elementară.
3o. Ca şi în cazul celorlalte tipuri de variabile se pot defini structuri globale, statice sau automatice. Structurile statice se declară precedând declaraţiile lor prin cuvântul static, iar cele externe prin cuvântul cheie extern.
4o. Elementele unei date de tip structură pot fi iniţializate după modelul iniţializării variabilelor care au tipuri predefinite.
Exemple:
1) Introducem tipul utilizator data_calendaristica astfel:
struct data_calendaristica
{ int ziua;
char luna[11];
int anul;
};
pentru a iniţializa o dată de tipul data_calendaristică vom scrie:
struct data_calendaristica dc1={31, “martie”, 1956};
2) Dacă declarăm un nou tip date_personale şi în care vrem să folosim tipul data_calendaristica, vom scrie:
struct date_personale
{ char nume[30];
char adresa[50];
struct data_calendaristica data_nasterii, data_angajarii;
};
ACCESUL LA ELEMENTELE UNEI STRUCTURI
Pentru a avea acces la componentele unei date structurate va trebui să folosim o calificare de forma:
nume_data_structurata.nume_componenta
Astfel dacă avem tipul structurat data_calendaristica introdus in exemplele anterioare şi declarăm data dc astfel:
struct data_calendaristica dc;
atunci pentru a ne referi la componentele datei dc vom folosi construcţiile:
dc.ziua
dc.anul
dc.luna (atenţie este pointer spre caractere)
Dacă avem declarat un tablou astfel:
struct data_calendaristica tdc[10];
atunci pentru fiecare componentă i ne vom referi astfel:
tdc[i].ziua
tdc[i].anul
tdc[i].luna (este pointer)
tdc[i].luna[0], tdc[i].luna[1], . . . , tdc[i].luna[11]
Ca şi tablourile structurile se pot transfera prin parametrii, transferând un pointer spre data structurată respectivă, adică adresa de început a zonei alocate structurii. Deci, printr-un apel de forma:
functie(&data_structurata);
se transferă funcţiei functie adresa de început a zonei alocate structurii data_structurata. Dacă data_structurata este o structura de tipul tip, atunci antetul funcţiei functie este următorul:
void functie(tip *p)
unde p este pointer spre tipul structurat tip.
Pentru data structurată dc de tipul data_calendaristica antetul funcţiei functie este:
void functie(struct data_calendaristica *p)
iar apelul pentru data dc se face
functie(&dc);
Printr-un astfel de apel, funcţia apelată nu are acces la numele datei structurate transferate, ci numai la pointerul spre ea. De aceea se pune problema accesului la componentele datei structurate prin pointerul la ea. În acest caz numele datei structurate se va înlocui prin *p. Deci, în cazul datei structurate dc, transferate ca şi mai sus, în locul construcţiei
dc.zi
vom scrie:
(*p).zi
înlocuind numele datei structurate dc prin *p, unde p este un pointer spre dc.
Observaţie:
1o. Parantezele rotunde din construcţia de mai sus sunt obligatorii, deoarece punctul este un operator prioritar operatorului unar *.
2o. Construcţia de mai sus poate fi înlocuită prin p->zi care este identică cu ea. Simbolul -> se compune din caracterele ‘-‘ şi ‘>’ scrise unul după celălalt fără spaţiu între ele. El se numeşte săgeată şi este considerat a fi un operator cu aceeaşi prioritate ca şi punctul, deci de prioritate maximă.