Sommario
< Home
Stampa

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;
}