Tipul struct din C++ îți permite să grupezi într-o singură variabilă mai multe informații care țin de același „obiect”: numele și media unui elev, coordonatele unui punct, ziua, luna și anul unei date calendaristice. La BAC Informatică, structurile apar mai ales ca item scurt la Subiectul II: ți se dă o declarare și ți se cere o expresie sau o secvență care folosește câmpurile. Sunt puncte ușoare, dacă știi sintaxa exact.
Declararea unei structuri
O structură (numită și înregistrare) se declară cu cuvântul struct, urmat de numele noului tip și de lista câmpurilor, fiecare cu tipul lui:
struct elev
{
char nume[31];
double medie;
int varsta;
};
Două detalii care contează:
- După acolada de închidere urmează obligatoriu punct și virgulă. Uitarea lui e o eroare de compilare clasică.
- Declarația de mai sus creează un tip nou, nu o variabilă. Variabilele le declari apoi ca pe oricare altele:
elev e, v[100];. În C++ nu trebuie să mai scriistructîn fața numelui tipului.
Poți declara variabilele și direct, odată cu tipul, ceea ce apare des în enunțurile de BAC:
struct
{
int zi, luna, an;
} d;
Aici structura nu are nume, iar d este singura variabilă de acest tip.
Accesul la câmpuri: operatorul punct
Un câmp se accesează cu numele variabilei, punct, numele câmpului:
elev e;
cin >> e.nume >> e.medie;
e.varsta = 18;
if (e.medie >= 9.5)
cout << e.nume << " are media peste 9.50";
Un câmp se comportă exact ca o variabilă de tipul lui: e.medie este un double, e.nume este un șir de caractere (deci îl compari cu strcmp, nu cu ==), iar e.nume[0] este prima literă a numelui.
Structuri imbricate
Un câmp poate fi el însuși o structură. Atunci folosești operatorul punct de mai multe ori, de la exterior spre interior:
struct punct
{
int x, y;
};
struct cerc
{
punct centru;
int raza;
} c;
Abscisa centrului este c.centru.x, iar ordonata este c.centru.y. O cerință tipică pentru itemul scurt: „Scrieți o expresie care are valoarea 1 dacă originea sistemului de coordonate se află în interiorul cercului c și 0 altfel.” Originea e în interiorul cercului dacă distanța de la centru la origine este mai mică decât raza. Ca să eviți radicalul, compari pătratele:
c.centru.x * c.centru.x + c.centru.y * c.centru.y < c.raza * c.raza
Pentru un cerc cu centrul în (3, 4) și raza 6: 9 + 16 = 25 < 36, deci expresia are valoarea 1. Pentru raza 5, 25 < 25 este fals, deci 0: originea este chiar pe cerc, nu în interior.
c.Centru.x sau c.x în loc de c.centru.x sunt considerate greșite.Atribuire și comparare
Două variabile de același tip structură se pot atribui direct: e2 = e1; copiază toate câmpurile, inclusiv șirul de caractere. Asta e foarte comod la interschimbări. În schimb, nu le poți compara direct: e1 == e2 nu compilează pentru o structură obișnuită. Compari câmp cu câmp, după criteriul cerut.
Structuri ca parametri
Structurile se transmit subprogramelor ca orice alt tip. Prin valoare, funcția primește o copie; prin referință (&), poate modifica originalul.
bool inInterior(punct p, cerc c)
{
int dx = p.x - c.centru.x;
int dy = p.y - c.centru.y;
return dx * dx + dy * dy < c.raza * c.raza;
}
void mutaPunct(punct &p, int a, int b)
{
p.x = p.x + a; // modifică punctul original
p.y = p.y + b;
}
Vectori de structuri: un program complet
Cea mai utilă combinație este vectorul de structuri. Problemă: fișierul elevi.in conține pe prima linie numărul n de elevi, apoi n linii cu numele (un singur cuvânt) și media fiecăruia. Afișați elevii în ordinea descrescătoare a mediilor; la medii egale, în ordine alfabetică.
#include <iostream>
#include <fstream>
#include <cstring>
using namespace std;
struct elev
{
char nume[31];
double medie;
};
elev v[100];
int main()
{
ifstream fin("elevi.in");
int n;
fin >> n;
for (int i = 0; i < n; i++)
fin >> v[i].nume >> v[i].medie;
for (int i = 0; i < n - 1; i++)
for (int j = i + 1; j < n; j++)
if (v[i].medie < v[j].medie ||
(v[i].medie == v[j].medie && strcmp(v[i].nume, v[j].nume) > 0))
{
elev aux = v[i]; // interschimbăm structuri întregi
v[i] = v[j];
v[j] = aux;
}
for (int i = 0; i < n; i++)
cout << v[i].nume << ' ' << v[i].medie << '\n';
fin.close();
return 0;
}
Pentru fișierul:
4
Ana 9.50
Mihai 8.75
Bogdan 9.50
Ioana 10
programul afișează Ioana 10, Ana 9.5, Bogdan 9.5, Mihai 8.75, fiecare pe câte o linie. Observă că cout afișează 9.5, nu 9.50: zerourile de la final nu se scriu implicit. Și observă avantajul structurii: la interschimbare, numele și media se mută împreună, cu o singură atribuire. Cu doi vectori separați ar fi trebuit să interschimbi de două ori și ai fi riscat să „decuplezi” numele de medie.
Greșeli frecvente
v.nume[i]în loc dev[i].nume. Primul înseamnă litera i din câmpul nume al lui v (și nu are sens dacă v este vector); al doilea, numele elevului i.- Lipsa lui
;după acolada care închide structura. - Compararea șirurilor cu
==sau atribuirea cu=pentru un câmp de tipchar[]; foloseștistrcmpșistrcpy. - Folosirea numelui tipului în loc de numele variabilei:
elev.medieeste greșit, corect estee.medie.
De reținut
- ● struct definește un tip nou; declarația se încheie cu punct și virgulă după acoladă.
- ● Câmpurile se accesează cu operatorul punct; la structuri imbricate: c.centru.x.
- ● Structurile se pot atribui direct (e2 = e1), dar nu se pot compara cu ==.
- ● Pentru un vector de structuri: v[i].camp, nu v.camp[i].
- ● La sortare, interschimbi structuri întregi, așa că informațiile unui element rămân împreună.