Struct
Introduzione
La Struct è un tipo di dato che permette di collegare tra loro più dati in una unica struttura e memorizzarla in una variabile.
Vediamo un esempio:
struct Studente {
char nome[20];
char cognome[20];
int voto;
};
In questo esempio vediamo che viene creata una struttura dati Studente che contiene al suo interno 3 attributi: nome, cognome e voto. Una volta creata è possibile dichiarare una variabile di tipo Studente e valorizzare questi attributi.
Studente studente;
studente.nome = "Mario";
studente.cognome = "Rossi";
studente.voto = 8;
cout << studente.nome << " " << studente.cognome << ": " << studente.voto << endl;
Come si può vedere l’operatore .
permette di accedere all’attributo della struct Studente e quindi assegnarne un valore, modificarlo e leggerlo.
Possiamo anche assegnare direttamente i valori in fase di dichiarazione:
Studente studente = {"Maria", "Bianchi", 10};
E’ anche possibile creare un array di struct:
Studente studenti[10];
strcpy(studenti[1].nome, "Mario");
strcpy(studenti[1].cognome, "Rossi");
strcpy(studenti[1].voto, 7);
Creiamo adesso un programma che legge da tastiera i voti di un certo numero di studenti scelto dall’utente e salva il tutto su un file.
#include <iostream>
#include <string.h>
#include <fstream>
using namespace std;
#define LEN 20
struct Studente {
char nome[LEN];
char cognome[LEN];
int voto;
};
int main()
{
int numero_alunni;
cout<<"Inserisci il numero di alunni: ";
cin >> numero_alunni;
Studente studenti[numero_alunni];
for (int i=0; i<numero_alunni; i++) {
cout << "alunno: " << i+1 << endl;
cout << "Nome: ";
cin >> studenti[i].nome;
cout << "Cognome: ";
cin >> studenti[i].cognome;
cout << "Voto: ";
cin >> studenti[i].voto;
}
ofstream file("studenti.csv");
for (int i=0; i<numero_alunni; i++) {
file << studenti[i].nome << "," << studenti[i].cognome << "," << studenti[i].voto << endl;
}
return 0;
}
Puntatori a struttura
E’ possibile dichiarare ed assegnare una variabile di tipo struct usando i puntatori. Vediamo con un esempio:
Studente* studente = new Studente;
L’istruzione new cerca uno spazio libero nella memoria heap e alloca (blocca) uno spazio di memoria per la struttura dati. Ricordiamo lo schema della memoria:

Vediamo meglio questo concetto:
Studente studente1;
studente *studente2 = new Studente
La differenza tra queste due dichiarazioni non è quindi solo data da un puntatore:
- studente1 è una variabile locale della funzione, quindi è memorizzata nello stack. Al termine dell’esecuzione della funzione la memoria dello stack viene liberata e quindi viene resa di nuovo disponibile; si ricorda che anche il main() è una funzione;
- studente2 è un puntatore ad un’area di memoria (nello heap) nella quale viene allocata la variabile di tipo Studente. Al termine della funzione, oppure se studente2 viene riassegnata ad altra variabile (o messa a NULL) la struttura dati continua ad essere allocata nella memoria heap, che resta quindi inutilizzabile per altri usi, e nemmeno è più raggiungibile (il suo puntatore è stato riassegnato, cancellato o distrutto). Questo tipo di problematica viene chiamata memory leak e richiede la massima attenzione del programmatore a gestire il rilascio della memoria utilizzata.
Per evitare il problema del memory leak di un’area di memoria che non viene più usata bisogna usare l’istruzione delete:
delete studente2;
Con delete il puntatore viene messo a NULL, ma prima viene liberata l’area di memoria a cui punta.
Con un puntatore non è ovviamente possibile accedere direttamente con l’operatore . agli attributi della struttura, ma è necessario accedere alla struttura dati stessa:
(*studente2).nome = "Sandro";
Questa notazione può essere resa più leggibile con l’operatore -> (freccia, “arrow operator” in inglese):
studente2->nome = "Sandro";
Di norma si usa la notazione freccia.
Strutture e funzioni
Completiamo con un esempio completo in cui usiamo puntatori e struct e funzioni insieme nello stesso programma.
#include <iostream>
#include <string.h>
#include <fstream>
using namespace std;
#define LEN 20
struct Studente {
char nome[LEN];
char cognome[LEN];
float italiano;
float storia;
float matematica;
float media;
};
void calcola_media(Studente *stud) {
stud->media = (stud->italiano + stud->storia + stud->matematica) / 3;
}
int main() {
int numero_alunni;
cout<<"Inserisci il numero di alunni: ";
cin >> numero_alunni;
Studente studenti[numero_alunni];
for (int i=0; i<numero_alunni; i++) {
cout << "alunno: " << i+1 << endl;
cout << "Nome: ";
cin >> studenti[i].nome;
cout << "Cognome: ";
cin >> studenti[i].cognome;
cout << "Italiano: ";
cin >> studenti[i].italiano;
cout << "Storia: ";
cin >> studenti[i].storia;
cout << "Matematica: ";
cin >> studenti[i].matematica;
calcola_media(&studenti[i]);
}
ofstream file("studenti.csv");
for (int i=0; i<numero_alunni; i++) {
file << studenti[i].nome << "," << studenti[i].cognome << "," << studenti[i].media << endl;
}
return 0;
}