Ce face struct
Un struct (structură) definește un tip format din mai multe câmpuri. După definire, poți declara variabile de acest tip, le poți copia cu =, trimite funcțiilor și returna din funcții.
Câmpurile se accesează cu punct (p.varsta). Când ai un pointer la structură, folosești săgeata: ptr->varsta, care înseamnă (*ptr).varsta. Din C99 poți inițializa câmpurile după nume: {.nume = "Ana", .varsta = 30}; câmpurile nemenționate devin 0.
Compilatorul poate adăuga octeți de completare (padding) între câmpuri, ca fiecare să fie aliniat corect. De aceea sizeof unei structuri poate fi mai mare decât suma câmpurilor. Structurile mari se trimit de obicei prin pointer (const struct persoana *), ca să nu se copieze.
Exemple
Exemplul 1: O structură pentru un produs
Inițializarea cu nume de câmpuri face codul ușor de citit. Copierea cu = copiază toate câmpurile.
#include <stdio.h>
struct produs {
char nume[30];
double pret;
int stoc;
};
int main(void) {
struct produs p = {.nume = "Cafea", .pret = 24.5, .stoc = 12};
struct produs copie = p;
copie.stoc = 0;
printf("%s: %.2f lei, stoc %d\n", p.nume, p.pret, p.stoc);
printf("copia are stoc %d\n", copie.stoc);
return 0;
}
Rezultat
Cafea: 24.50 lei, stoc 12
copia are stoc 0
Exemplul 2: Pointer la structură și operatorul ->
Funcția modifică structura originală prin pointer. Funcția de afișare primește const, deci promite că nu schimbă nimic.
#include <stdio.h>
struct cont {
char titular[30];
double sold;
};
void depune(struct cont *c, double suma) {
c->sold += suma;
}
void afiseaza(const struct cont *c) {
printf("%s are %.2f lei\n", c->titular, c->sold);
}
int main(void) {
struct cont c = {"Ana Popescu", 150.0};
depune(&c, 350.0);
afiseaza(&c);
return 0;
}
Rezultat
Ana Popescu are 500.00 lei
Exemplul 3: Tablou de structuri și padding
Structura are un char și un int (1 + 4 octeți), dar sizeof dă 8 pe acest calculator: compilatorul a adăugat 3 octeți ca int-ul să fie aliniat la 4.
#include <stdio.h>
struct nota {
char materie; // 'M' = matematică, 'R' = română
int valoare;
};
int main(void) {
struct nota note[] = {{'M', 9}, {'R', 10}, {'M', 7}};
size_t n = sizeof note / sizeof note[0];
int suma_m = 0, cate_m = 0;
for (size_t i = 0; i < n; i++) {
if (note[i].materie == 'M') {
suma_m += note[i].valoare;
cate_m++;
}
}
printf("media la matematică: %.1f\n", (double)suma_m / cate_m);
printf("sizeof(struct nota) = %zu\n", sizeof(struct nota));
return 0;
}
Rezultat
media la matematică: 8.0
sizeof(struct nota) = 8
Greșeli frecvente
- Uiți punctul și virgula de după acolada de închidere a definiției:
struct p { int x; }fără;dă erori greu de înțeles pe rândul următor. - Folosești
.pe un pointer (ptr.camp) sau->pe o variabilă. Punctul este pentru structuri, săgeata pentru pointeri la structuri. - Compari două structuri cu
==. Nu este permis; compară câmp cu câmp. Nicimemcmpnu e sigur, pentru că octeții de padding pot avea orice valoare. - Scrii doar
produs p;în loc destruct produs p;. În C, numele structurii trebuie precedat destruct, dacă nu ai definit untypedef.
Comenzi înrudite
typedef: Dă un nume nou, mai scurt sau mai clar, unui tip existent: o structură, un pointer sau un tip de funcție.union: Ca un struct, dar toate câmpurile folosesc aceeași zonă de memorie, așa că la un moment dat păstrează o singură valoare.enum: Definește un set de constante întregi cu nume, de exemplu zilele săptămânii sau stările unei comenzi.Pointeri (& și *): O variabilă care păstrează adresa altei variabile; cu * citești sau modifici valoarea de la acea adresă.sizeof: Operatorul care spune câți octeți ocupă un tip sau o variabilă; calculat de compilator, rezultatul are tipul size_t.malloc: Cere sistemului un bloc de memorie de mărimea dată, în timpul rulării, și returnează adresa lui sau NULL dacă nu reușește.