Tipul struct în C++ – Crearea propriilor tipuri de date!

Tipul struct în C++ – Crearea propriilor tipuri de date!

O structură reprezintă un grup de date grupate împreună sub același nume. Aceste date, numite câmpuri, pot avea tipuri și lungimi diferite (pot fi chiar tablouri). În C++, structurile pot fi definite folosind tipul struct, moștenit din limbajul C. Astfel, ne putem crea propriile tipuri de date, pentru a lucra mai ușor cu anumite informații.

Desigur, o soluție mai flexibilă este folosirea claselor, care sunt noutatea principală adusă de C++, însă când vrem să definim un tip care să reunească doar câteva date, eventual să supraîncărcăm câțiva operatori pentru el și să-i scriem un constructor, este de ajuns tipul struct.

Declararea unei structuri

O structură poate fi declarată astfel:

struct NumeTip {
tipCamp1 numeCamp1;
tipCamp2 numeCamp2;
...
tipCampN numeCampN;
} var1, var2, ..., varN; // variabile de tipul NumeTip

Numele noului tip va fi NumeTip, cu variabilele var1, var2, …, varN. NumeTip poate începe și cu literă mică, ca orice identificator din C++, însă mi se pare mai convenabil să înceapă cu majusculă, pentru ca apoi să pot declara o variabilă cu numele numeTip. Nu este obligatoriu să declarăm variabilele imediat după definirea tipului; acestea pot fi declarate oriunde în program, după asta, prin sintaxa:

NumeTip var1, var2, ..., varN; // varianta C++
struct NumeTip var1, var2, ..., varN; // varianta C (valabilă și în C++)

Când declarăm un struct, nu este obligatoriu să-i dăm și nume, dar trebuie să declarăm măcar o variabilă după acolada închisă, ca apoi să putem folosi decltype pentru a le declara pe celelalte. În acest caz, noul tip se va numi structură anonimă.

struct {
int a, b;
} x;
decltype(x) y; // y va avea tipul anonim al lui x.

Exemple de structuri

Iată câteva exemple utile de structuri:

struct Punct {
int x, y;
};
struct Elev {
int varsta;
char nume[20];
char prenume[20];
float medieGenerala;
float medieMatematica;
float medieInformatica;
};
struct Produs {
int pret;
int greutate;
char nume[20];
};
struct NrComplex {
int real;
int imag;
};

Inițializarea unei variabile de tip struct

O variabilă de tip struct se poate inițializa scriindu-i între acolade, separate prin virgulă, valorile pentru fiecare câmp, în ordinea în care apare acesta în definiție. Înaintea primei acolade se poate pune operatorul de atribuire, dar la noile versiuni C++ a devenit ceva opțional.

struct Cerc {
int x, y;
double raza;
} cerc1 = {0, 0, 1};
Cerc cerc2 {2, 3, 1.618};

De asemenea, unele compilatoare suportă această sintaxă și pentru atribuirea unei valori variabilei după declarare, însă nu este recomandat.

Dacă nu le inițializăm noi cu anumite valori, toate câmpurile dintr-o variabilă de tip struct declarată global sunt inițializate automat cu 0, iar în cazul declarării locale, cu valori random rămase pe stivă, exact ca la variabilele obișnuite.

Accesarea câmpurilor unei variabile de tip struct

Pentru a accesa un câmp al unei variabile de tip struct se folosește operatorul de selecție directă (.), sintaxa fiind variabila.camp. Exemplu:

struct Punct {
int x, y;
} punct = {1, 2}, x;
// var e declarat global:
Punct var;
x.x = 3;
x.y = 3;
cout << punct.x << ' ' << punct.y << '\n'; // 1 2
cout << var.x << ' ' << var.y << '\n'; // 0 0
cout << x.x << ' ' << x.y << '\n'; // 3 3

Operatorul de atribuire

Singurul operator predefinit pentru tipul struct este cel de atribuire. Acesta copiază valoarea fiecărui câmp din operandul stâng în cel drept, iar în cazul câmpurilor tablou, le copiază pe rând elementele. Alți operatori pot fi supraîncărcați, dar voi arăta cum într-un articol despre OOP :smile:

struct {
int a, b;
} x, y = {1, 2};
x = y;
cout << x.a << ' ' << x.b << '\n'; // 1 2

Pointeri la structuri

Există pointeri și pentru struct, la fel ca pentru orice tip de date, și funcționează la fel.

struct Punct {
int x, y;
} pct = {1, 2}, *pPct;
pPct = &pct; // pPct indică adresa variabilei pct.

Problema apare la accesarea câmpurilor unei variabile indicată de un pointer. Operatorul punct nu funcționează, însă există un operator de dereferențiere, numit operator de selecție indirectă, creat special pentru această situație (->).

cout << pPct->x << '\n'; // 1
cout << pPct->y << '\n'; // 2

pointer->camp este echivalent cu (*pointer).camp.

Dacă aveți vreo întrebare despre tipul struct în C++, nu ezitați să o adresați mai jos printr-un comentariu ca să vă pot răspunde :smile:

Mulțumesc că ai citit acest articol.
Dacă vrei să susții blogul, poți cumpăra un abonament de 2$.

patreon

Lasă un comentariu!

6 comentarii

Paul
pe 24/01/2022 la 18:37

Salutare!
Mă poți ajuta la problema 2736 de pe PbInfo?
Cu această soluție am primit 60 de puncte.

#include <iostream>
#include <cstring>
using namespace std;
#define ll int long long unsigned
struct articol {
char prenume[300], nume[300];
ll salariu;
ll varsta;
char functie[300];
char nrtlf[300];
char email[300];
};
int main(void) {
articol a[81];
int p;
char semn;
int n;
cin >> n;
for (int i = 1; i <= n; i++) {
cin >> a[i].prenume >> a[i].nume >> a[i].salariu >> a[i].varsta >> a[i].functie >> a[i].nrtlf >> a[i].email;
}
cin >> p;
cin >> semn;
if (semn == '+') {
switch (p) {
case 1:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (strcmp(a[j].prenume, a[i].prenume) < 0) {
swap(a[j], a[i]);
}
}
}
break;
case 2:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (strcmp(a[j].nume, a[i].nume) < 0) {
swap(a[j], a[i]);
}
}
}
break;
case 3:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (a[j].salariu<a[i].salariu) {
swap(a[j], a[i]);
}
}
}
break;
case 4:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (a[j].varsta< a[i].varsta) {
swap(a[j], a[i]);
}
}
}
break;
case 5:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (strcmp(a[j].functie,a[i].functie)<0) {
swap(a[j], a[i]);
}
}
}
break;
case 6:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (strcmp(a[j].nrtlf, a[i].nrtlf) < 0) {
swap(a[j], a[i]);
}
}
}
break;
case 7:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (strcmp(a[j].email, a[i].email) < 0) {
swap(a[j], a[i]);
}
}
}
break;
}
for (int i = 1; i <= n; i++) {
cout << a[i].prenume << " " << a[i].nume << " " << a[i].salariu << " " << a[i].varsta << " " << a[i].functie << " " <<a[i].nrtlf << " " << a[i].email<<"\n";
}
}
else {
switch (p) {
case 1:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (strcmp(a[j].prenume, a[i].prenume) > 0) {
swap(a[j], a[i]);
}
}
}
break;
case 2:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (strcmp(a[j].nume, a[i].nume) > 0) {
swap(a[j], a[i]);
}
}
}
break;
case 3:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (a[j].salariu > a[i].salariu) {
swap(a[j], a[i]);
}
}
}
break;
case 4:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (a[j].varsta > a[i].varsta) {
swap(a[j], a[i]);
}
}
}
break;
case 5:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (strcmp(a[j].functie, a[i].functie) > 0) {
swap(a[j], a[i]);
}
}
}
break;
case 6:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (strcmp(a[j].nrtlf, a[i].nrtlf) > 0) {
swap(a[j], a[i]);
}
}
}
break;
case 7:
for (int i = 1; i < n; i++) {
for (int j = i + 1; j <= n; j++) {
if (strcmp(a[j].email, a[i].email) > 0) {
swap(a[j], a[i]);
}
}
}
break;
}
for (int i = 1; i <= n; i++){
cout << a[i].prenume << " " << a[i].nume << " " << a[i].salariu << " " << a[i].varsta << " " << a[i].functie << " " <<a[i].nrtlf << " " << a[i].email<<"\n";
}
}
}
pe 24/01/2022 la 23:07

Time Limit? Dacă da, încearcă un algoritm de sortare mai bun.

Paul
pe 25/01/2022 la 06:58

Nu, răspuns greșit.

pe 25/01/2022 la 10:40

Ah, da. În enunț scrie așa:

Dacă două articole au aceeași valoare a câmpului în raport cu care se face sortarea, ordinea lor nu se va modifica.

O sortare care respectă această condiție se numește sortare stabilă. Când sortezi numere nu prea îți dai seama dacă o sortare este stabilă. Însă la struct-uri da, deoarece criteriul de sortare poate fi bazat pe un subset de câmpuri, deci nu pe întreaga „valoare” a elementului.

Tu ai folosit sortarea prin selecție, care nu este o sortare stabilă (poți căuta un contraexemplu). În schimb, poți folosi sortarea prin inserție sau Bubble Sort. Sau funcția stable_sort din STL, care are aceeași structură ca sort.

Paul
pe 25/01/2022 la 17:33

Mă gândeam că nu e bună sortarea prin selecție pentru problema asta, dar nu am găsit un contraexemplu, așa că am considerat-o stabilă și am zis că nu mai scriu cu bubble că e prea mult :))

Paul
pe 25/01/2022 la 17:54

Am găsit acum și contraexemplu, trebuia să pun mai multe subșiruri strict crescătoare și strict descrescătoare: 1212121. Mulțumesc frumos! Am primit 100 de puncte cu bubble.