Tipul struct
Cum grupezi mai multe câmpuri sub un singur nume, cum lucrezi cu vectori de structuri și cum sortezi după un câmp.
Problema
Vrei să reții, pentru fiecare elev, numele, media și numărul de absențe. Cu vectori separați ar arăta așa:
char nume[100][31];
double media[100];
int absente[100];Merge, dar singurul lucru care ține cei trei vectori împreună e indicele comun. Dacă sortezi unul și uiți să-i sortezi pe ceilalți, datele se amestecă și nu primești nicio eroare.
Soluția
O structură este un tip nou, format din mai multe câmpuri:
struct Elev {
char nume[31];
double media;
int absente;
};Punctul și virgula de după acolada de închidere sunt obligatorii și se uită des.
Acum poți declara variabile de acest tip:
Elev e;
e.media = 9.15;
e.absente = 4;
strcpy(e.nume, "Popescu");Accesul la câmpuri se face cu punct. Câmpul nume este un tablou de caractere, deci se copiază cu strcpy, nu cu =.
Vectori de structuri
Aici se vede la ce folosește:
Elev v[101];
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> v[i].nume >> v[i].media >> v[i].absente;
}v[i] este un elev întreg, iar v[i].media este media lui. Toate cele trei informații se mută împreună, deci nu mai au cum să se amestece.
Sortarea după un câmp
Sortarea merge exact ca la vectorii de numere. Se schimbă doar ce compari și ce muți.
for (int i = 1; i < n; i++)
for (int j = i + 1; j <= n; j++)
if (v[i].media < v[j].media) {
Elev aux = v[i];
v[i] = v[j];
v[j] = aux;
}Două lucruri de observat:
Se compară un câmp, se mută structura întreagă. Exact asta rezolvau prost vectorii separați.
Structurile se atribuie cu =. Spre deosebire de tablourile de caractere, o structură se copiază normal, inclusiv câmpurile ei de tip tablou.
Pentru sortare după nume, se schimbă doar condiția:
if (strcmp(v[i].nume, v[j].nume) > 0) { /* interschimb */ }Pentru criterii combinate (media descrescător, iar la medii egale alfabetic):
if (v[i].media < v[j].media ||
(v[i].media == v[j].media && strcmp(v[i].nume, v[j].nume) > 0)) { ... }Structuri ca parametri
O structură se transmite ca orice altă variabilă: prin valoare se copiază, prin referință nu.
void afiseaza(Elev e) { // copie
cout << e.nume << " " << e.media;
}
void mareste(Elev &e) { // modifică originalul
e.media += 0.5;
}La structurile mari, transmiterea prin referință te scapă și de o copiere inutilă.
Un vector de structuri se transmite ca orice vector, fără copiere:
void sorteaza(Elev v[], int n) { ... }Structuri imbricate
Un câmp poate fi el însuși o structură:
struct Data {
int zi, luna, an;
};
struct Elev {
char nume[31];
Data nastere;
};e.nastere.an = 2008;Ajungi la câmp cu puncte succesive. Comparația a două date se scrie firesc:
bool inainte(Data a, Data b) {
if (a.an != b.an) return a.an < b.an;
if (a.luna != b.luna) return a.luna < b.luna;
return a.zi < b.zi;
}Tiparul „compară după primul câmp, iar dacă e egal, treci la următorul" apare de fiecare dată când sortezi după criterii multiple.
Un exemplu complet
Se citesc n produse, fiecare cu denumire, preț și cantitate. Să se afișeze produsul cu valoarea totală cea mai mare.
#include <iostream>
#include <cstring>
using namespace std;
struct Produs {
char nume[31];
double pret;
int cantitate;
};
Produs v[101];
int main() {
int n;
cin >> n;
for (int i = 1; i <= n; i++)
cin >> v[i].nume >> v[i].pret >> v[i].cantitate;
int best = 1;
for (int i = 2; i <= n; i++)
if (v[i].pret * v[i].cantitate > v[best].pret * v[best].cantitate)
best = i;
cout << v[best].nume << " " << v[best].pret * v[best].cantitate;
return 0;
}Se reține poziția celui mai bun, nu o copie a lui. E aceeași idee ca la maximul dintr-un vector și e la fel de utilă aici, pentru că la final ai acces la toate câmpurile.
De reținut
structgrupează câmpuri de tipuri diferite sub un tip nou. Nu uita;după acoladă.- Accesul la câmpuri se face cu punct.
- Structurile se atribuie cu
=, dar câmpurile de tip șir se copiază custrcpy. - La sortare compari un câmp și muți structura întreagă.
- Criterii multiple: compară pe rând, coborând la următorul câmp doar la egalitate.