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ă:

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.

La BAC: la itemii cu structuri, scrie numele câmpurilor exact ca în declarația din enunț, inclusiv literele mari și mici. 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

De reținut