This shows you the differences between two versions of the page.
— |
programare:laboratoare:suport-teoretic:tipuri-de-date-definite-de-utilizator-structuri [2025/10/10 16:59] (current) darius.neatu created |
||
---|---|---|---|
Line 1: | Line 1: | ||
+ | ===== PCLP Suport Teoretic pentru Laborator: Tipuri de date definite de utilizator - structuri ===== | ||
+ | |||
+ | ==== Obiective ==== | ||
+ | |||
+ | În urma parcurgerii acestui laborator studentul va fi capabil să: | ||
+ | * organizeze datele din rezolvarea unei probleme complexe în structuri; | ||
+ | * optimizeze scrierea funcţiilor prin minimizarea numărului de parametri şi prin utilizarea structurilor ca parametri returnaţi de funcţie; | ||
+ | * evite utilizarea greşită a structurilor. | ||
+ | |||
+ | ==== Noţiuni teoretice ==== | ||
+ | |||
+ | === Structuri === | ||
+ | Structurile sunt tipuri de date în care putem grupa mai multe variabile eventual de tipuri diferite (spre deosebire de vectori, care conţin numai date de acelasi tip). O structură se poate defini astfel: | ||
+ | |||
+ | <code c> | ||
+ | struct nume_structura { | ||
+ | declaratii_de_variabile | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | Definiția unei structuri poate fi urmată imediat de declararea de variabile de acel tip, forma cea mai generală fiind: | ||
+ | <code c> | ||
+ | struct [structure tag] { | ||
+ | |||
+ | member definition; | ||
+ | member definition; | ||
+ | ... | ||
+ | member definition; | ||
+ | } [one or more structure variables]; | ||
+ | </code> | ||
+ | |||
+ | Unde între ''[]'' se află câmpurile opționale. | ||
+ | |||
+ | Exemple: | ||
+ | <code c> | ||
+ | struct student { | ||
+ | char nume[40]; | ||
+ | int an; | ||
+ | float medie; | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | Variabilele declarate in interiorul structurii se numesc "campurile" structurii: | ||
+ | *nume; | ||
+ | *an; | ||
+ | *medie. | ||
+ | |||
+ | <code c> | ||
+ | struct complex { /* pentru memorarea unui număr complex cu dublă precizie */ | ||
+ | double re; | ||
+ | double im; | ||
+ | }; | ||
+ | </code> | ||
+ | |||
+ | Declararea şi iniţializarea unor variabile de tip structură se poate face astfel: | ||
+ | <code c> | ||
+ | struct student s1 = {"Popescu Ionel", 3, 9.25}; | ||
+ | struct complex c1, c2; | ||
+ | struct complex v[10]; | ||
+ | </code> | ||
+ | |||
+ | Pentru simplificarea declaraţiilor, putem asocia unei structuri un nume de tip de date: | ||
+ | <code c> | ||
+ | typedef struct student Student; | ||
+ | ... | ||
+ | Student s1, s2, s3; | ||
+ | </code> | ||
+ | |||
+ | Redenumirea de tip de mai sus poate fi inclusă și în definirea structurii, caz în care putem folosi - din prima - atât ''struct Student'' cât și tipul de date rezultat din typedef: | ||
+ | |||
+ | <code c> | ||
+ | typedef struct student { | ||
+ | char nume[40]; | ||
+ | int an; | ||
+ | float medie; | ||
+ | } Student; | ||
+ | |||
+ | int main() { | ||
+ | /* Ambele declaratii de mai jos sunt valide */ | ||
+ | struct student s1; | ||
+ | Student s2; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | |||
+ | Accesul la membrii unei structuri se face prin operatorul ".": | ||
+ | <code c> | ||
+ | s1.an = 3; | ||
+ | </code> | ||
+ | |||
+ | În cazul pointerilor la structuri, accesul la membri se poate face astfel: | ||
+ | <code c> | ||
+ | Student *stud = (Student *)malloc(sizeof(Student)); | ||
+ | (*stud).medie = 9.31; | ||
+ | /* altă modalitate mai simplă şi mai des folosită: */ | ||
+ | stud->medie = 9.31; | ||
+ | </code> | ||
+ | |||
+ | Atribuirile de structuri se pot face astfel: | ||
+ | <code c> | ||
+ | struct complex n1, n2; | ||
+ | ... | ||
+ | n2 = n1; | ||
+ | </code> | ||
+ | |||
+ | Prin această atribuire se realizează o copiere bit cu bit a elementelor lui n1 în n2. | ||
+ | |||
+ | Alt exemplu de utilizare: După cum se vede mai jos trebuie facută diferenta când definim un tip şi cand declaram o variabila de tip struct sau typedef struct. | ||
+ | <code c> | ||
+ | typedef struct { | ||
+ | int data; | ||
+ | int text; | ||
+ | } S1; // este un typedef pentru S1, functional in C si C++ | ||
+ | |||
+ | struct S2 { | ||
+ | int data; | ||
+ | int text; | ||
+ | }; // este un typedef pentru struct S2 | ||
+ | |||
+ | |||
+ | struct { | ||
+ | int data; | ||
+ | int text; | ||
+ | } S3; | ||
+ | // este o declaratie a lui S3, variabila de tip struct nu defineste un tip | ||
+ | // spune compilatorului sa aloce memorie pentru variablia S3 | ||
+ | |||
+ | typedef struct S4 { | ||
+ | int data; | ||
+ | int text; | ||
+ | } S4; // este un typedef atât pentru struct S4, cât și pentru S4 | ||
+ | |||
+ | |||
+ | int main() { | ||
+ | // ce se intampla la declarare variabile de tip S1,S2,S3 | ||
+ | S1 mine1; // este un typedef si va merge | ||
+ | struct S2 mine2; // este un typedef si va merge | ||
+ | S2 mine22; // S2 NU este un typedef si NU va merge | ||
+ | S3 mine3; // nu va merge pt ca S3 nu este un typedef. | ||
+ | struct S4 mine4; // este un typedef și va merge | ||
+ | S4 mine4; // este un typedef și va merge | ||
+ | | ||
+ | // ce se intampla la utilizarea ca variabile a S1,S2,S3 | ||
+ | S1.data = 5; // da eroare deoarece S1 este numai un typedef. | ||
+ | struct S2.data = 5; // da eroare deoarece S2 este numai un typedef. | ||
+ | S3.data = 5; // merge doarece S3 e o variabila | ||
+ | return 0; | ||
+ | } | ||
+ | </code> | ||
+ | |||
+ | <note>Dacă declaraţi pointeri la structuri, nu uitaţi să alocaţi memorie pentru aceştia înainte de a accesa câmpurile structurii. Nu uitaţi să alocaţi şi câmpurile structurii, care sunt pointeri, înainte de utilizare, dacă este cazul. De asemenea fiţi atenţi şi la modul de accesare al câmpurilor. | ||
+ | </note> | ||
+ | |||
+ | === Diferenţa dintre copierea structurilor şi copierea pointerilor === | ||
+ | |||
+ | Pentru exemplificarea diferenţei dintre copierea structurilor şi copierea pointerilor să considerăm urmatorul exemplu: | ||
+ | <code c> | ||
+ | struct exemplu { | ||
+ | int n; | ||
+ | char *s; | ||
+ | } | ||
+ | struct exemplu s1, s2; | ||
+ | char *litere = "abcdef"; | ||
+ | s1.n = 5; | ||
+ | s1.s = strdup(litere); | ||
+ | s2 = s1; | ||
+ | s2.s[1]='x'; | ||
+ | </code> | ||
+ | |||
+ | După atribuirea s2 = s1;, s2.s va avea o valoare identică cu s1.s. Deoarece s este un pointer (o adresă de memorie), s2.s va indica aceeaşi adresa de memorie ca şi s1.s. Deci, după modificarea celui de-al doilea caracter din s2.s, atat s2.s cât si s1.s vor fi axcdef. De obicei acest efect nu este dorit şi nu se recomandă atribuirea de structuri atunci cand acestea contin pointeri. | ||
+ | |||
+ | Totuşi, putem atribui ulterior lui s2.s o altă valoare (o altă adresă), iar ca urmare a acestei operaţii, stringurile vor fi distincte din nou. | ||
+ | |||
+ | Un alt caz (diferit de cel expus anterior) este cel al atribuirii aceleiaşi structuri către două variabile pointer diferite: | ||
+ | <code c> | ||
+ | struct exemplu { | ||
+ | int n; | ||
+ | char * s; | ||
+ | } | ||
+ | struct exemplu s1; | ||
+ | struct exemplu *p1; | ||
+ | struct exemplu *p2; | ||
+ | p1 = &s1; | ||
+ | p2 = &s1; | ||
+ | </code> | ||
+ | |||
+ | În acest caz observăm că din nou p1->s şi p2->s indică către acelaşi şir de caractere, dar aici adresa către şirul de caractere apare memorată o singura dată; spre deosebire de cazul anterior, dacă modificăm adresa din p2->s, ea se va modifica automat şi în p1->s. | ||
+ | |||
+ | |||
+ | ==== Referinţe ==== | ||
+ | * [[http://crasseux.com/books/ctutorial//Data-structures.html#Data%20structures|The GNU Programming Tools - Data structure]] | ||
+ | * [[http://publications.gbdirect.co.uk/c_book/chapter6/unions.html|The C Book - Unions]] |