struct — Strutture Dati

Una struct raggruppa variabili di tipi diversi in un unico tipo personalizzato. È la base della programmazione a oggetti in C.

CStruct base e typedef
#include <stdio.h>
#include <string.h>

// Definizione della struct
typedef struct {
    char nome[50];
    char cognome[50];
    int  eta;
    double stipendio;
} Dipendente;

// Funzione che riceve struct per valore (copia)
void stampa_dipendente(Dipendente d) {
    printf("%-15s %-15s  Età: %2d  Stipendio: %.2f\n",
           d.nome, d.cognome, d.eta, d.stipendio);
}

// Funzione che riceve per puntatore (più efficiente, evita la copia)
void aumento(Dipendente *d, double percentuale) {
    d->stipendio *= (1.0 + percentuale / 100.0);
}

int main() {
    // Inizializzazione
    Dipendente d1 = {"Mario", "Rossi", 35, 2500.0};
    Dipendente d2 = {"Giulia", "Bianchi", 28, 3200.0};

    // Accesso con operatore punto
    printf("Nome: %s %s\n", d1.nome, d1.cognome);
    d1.eta = 36;

    // Array di struct
    Dipendente team[] = {d1, d2};
    int n = sizeof(team) / sizeof(team[0]);

    printf("\n--- Team ---\n");
    for (int i = 0; i < n; i++) {
        stampa_dipendente(team[i]);
    }

    // Modifica tramite puntatore
    aumento(&team[0], 10.0);  // +10% a Mario
    printf("\nDopo aumento:\n");
    stampa_dipendente(team[0]);

    return 0;
}
. vs -> Usa il punto . per accedere ai campi di una struct. Usa la freccia -> quando hai un puntatore a struct. p->campo è equivalente a (*p).campo.

Struct Annidate

CStruct dentro struct
#include <stdio.h>

typedef struct {
    double x, y;
} Punto;

typedef struct {
    Punto centro;
    double raggio;
} Cerchio;

typedef struct {
    Punto p1, p2;  // Due angoli opposti
} Rettangolo;

double distanza(Punto a, Punto b) {
    double dx = b.x - a.x;
    double dy = b.y - a.y;
    return __builtin_sqrt(dx*dx + dy*dy);  // o #include <math.h> e sqrt
}

double area_rettangolo(Rettangolo r) {
    return (r.p2.x - r.p1.x) * (r.p2.y - r.p1.y);
}

int main() {
    Cerchio c = {{0, 0}, 5.0};
    printf("Centro: (%.1f, %.1f), Raggio: %.1f\n",
           c.centro.x, c.centro.y, c.raggio);

    Punto a = {0, 0}, b = {3, 4};
    printf("Distanza tra (0,0) e (3,4): %.2f\n", distanza(a, b));

    Rettangolo rect = {{1, 1}, {5, 4}};
    printf("Area rettangolo: %.1f\n", area_rettangolo(rect));

    return 0;
}

enum — Enumerazioni

Un enum definisce un insieme di costanti intere con nomi significativi.

Cenum
#include <stdio.h>

typedef enum { LUNES=1, MARTES, MIERCOLES, JUEVES, VIERNES, SABADO, DOMINGO } DiaSett;
typedef enum { ROSSO, GIALLO, VERDE } Semaforo;

// enum per errori (pattern comune)
typedef enum {
    OK = 0,
    ERR_FILE_NON_TROVATO = -1,
    ERR_PERMESSO_NEGATO  = -2,
    ERR_MEMORIA          = -3
} Errore;

const char* nome_giorno(DiaSett g) {
    const char* nomi[] = {"", "Lunedì", "Martedì", "Mercoledì",
                          "Giovedì", "Venerdì", "Sabato", "Domenica"};
    return nomi[g];
}

int main() {
    DiaSett oggi = MERCOLEDÌ;  // = MIERCOLES dopo fix, usiamo un int
    DiaSett giorno = 3;  // Mercoledì

    printf("Giorno %d: %s\n", giorno, nome_giorno(giorno));

    Semaforo s = VERDE;
    switch (s) {
        case ROSSO:   printf("STOP\n"); break;
        case GIALLO:  printf("Attenzione\n"); break;
        case VERDE:   printf("VIA!\n"); break;
    }

    Errore risultato = OK;
    if (risultato == OK) printf("Operazione riuscita\n");

    return 0;
}

union — Unioni

Una union è come una struct, ma tutti i campi condividono lo stesso spazio di memoria. La dimensione è quella del campo più grande.

Cunion — uso pratico
#include <stdio.h>

union Dato {
    int   i;
    float f;
    char  c[4];
};

// Pattern comune: tagged union (discriminated union)
typedef enum { TIPO_INT, TIPO_FLOAT, TIPO_STRING } TipoDato;

typedef struct {
    TipoDato tipo;
    union {
        int    i;
        float  f;
        char   s[32];
    } valore;
} Variabile;

void stampa_var(Variabile v) {
    switch (v.tipo) {
        case TIPO_INT:    printf("int:    %d\n",  v.valore.i); break;
        case TIPO_FLOAT:  printf("float:  %.2f\n",v.valore.f); break;
        case TIPO_STRING: printf("string: %s\n",  v.valore.s); break;
    }
}

int main() {
    // Dimensione union
    union Dato d;
    printf("Dimensione union Dato: %zu byte\n", sizeof(d));

    d.i = 42;
    printf("Come int:   %d\n", d.i);
    d.f = 3.14f;
    printf("Come float: %.2f\n", d.f);
    printf("i ora vale: %d (sovrascritto!)\n\n", d.i);

    // Tagged union
    Variabile vars[] = {
        {TIPO_INT,    {.i = 100}},
        {TIPO_FLOAT,  {.f = 3.14f}},
        {TIPO_STRING, {.s = "ciao"}}
    };

    for (int i = 0; i < 3; i++) stampa_var(vars[i]);

    return 0;
}
🏋️ Esercizi
Applica struct, enum e union a problemi reali.
1
Gestione studenti
Facilestruct array

Definisci una struct Studente con nome, cognome, matricola (int) e media voti (double). Crea un array di 5 studenti (inizializzati staticamente). Stampa la lista, trova lo studente con la media più alta, e ordina per media decrescente.

C
#include <stdio.h>

typedef struct {
    char nome[30], cognome[30];
    int matricola;
    double media;
} Studente;

void stampa(Studente s[], int n) {
    printf("%-10s %-12s  Mat.   Media\n", "Nome", "Cognome");
    printf("------------------------------------------\n");
    for (int i=0; i<n; i++)
        printf("%-10s %-12s  %05d  %.2f\n",
               s[i].nome, s[i].cognome, s[i].matricola, s[i].media);
}

int main() {
    Studente studenti[] = {
        {"Marco",  "Ferrari",  12345, 27.5},
        {"Laura",  "Conti",    12346, 29.8},
        {"Luca",   "Marino",   12347, 24.0},
        {"Anna",   "Ricci",    12348, 28.3},
        {"Paolo",  "Greco",    12349, 26.7}
    };
    int n = 5;

    stampa(studenti, n);

    // Migliore
    int migliore = 0;
    for (int i=1; i<n; i++)
        if (studenti[i].media > studenti[migliore].media) migliore = i;
    printf("\nMigliore: %s %s (%.2f)\n",
           studenti[migliore].nome, studenti[migliore].cognome,
           studenti[migliore].media);

    // Ordina per media decrescente (bubble sort)
    for (int i=0; i<n-1; i++)
        for (int j=0; j<n-i-1; j++)
            if (studenti[j].media < studenti[j+1].media) {
                Studente tmp = studenti[j];
                studenti[j]   = studenti[j+1];
                studenti[j+1] = tmp;
            }

    printf("\nOrdinati per media:\n");
    stampa(studenti, n);
    return 0;
}
2
Gestione inventario
Mediostruct / puntatori

Crea un sistema di inventario con struct Prodotto (id, nome, prezzo, quantità). Implementa funzioni: aggiungi_prodotto, cerca_per_nome, aggiorna_quantita, valore_totale (somma prezzo*quantità). Usa un array dinamico di struct.

C
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

typedef struct {
    int    id;
    char   nome[50];
    double prezzo;
    int    quantita;
} Prodotto;

typedef struct {
    Prodotto *items;
    int size, cap;
    int prossimo_id;
} Inventario;

Inventario crea_inventario() {
    Inventario inv = {malloc(4 * sizeof(Prodotto)), 0, 4, 1};
    return inv;
}

void aggiungi(Inventario *inv, const char *nome, double prezzo, int qty) {
    if (inv->size == inv->cap) {
        inv->cap *= 2;
        inv->items = realloc(inv->items, inv->cap * sizeof(Prodotto));
    }
    Prodotto *p = &inv->items[inv->size++];
    p->id = inv->prossimo_id++;
    strncpy(p->nome, nome, 49);
    p->prezzo   = prezzo;
    p->quantita = qty;
}

Prodotto* cerca(Inventario *inv, const char *nome) {
    for (int i=0; i<inv->size; i++)
        if (strcmp(inv->items[i].nome, nome) == 0)
            return &inv->items[i];
    return NULL;
}

double valore_totale(Inventario *inv) {
    double tot = 0;
    for (int i=0; i<inv->size; i++)
        tot += inv->items[i].prezzo * inv->items[i].quantita;
    return tot;
}

void stampa(Inventario *inv) {
    printf("\n%-4s %-20s %8s %6s\n", "ID", "Nome", "Prezzo", "Qty");
    printf("------------------------------------------\n");
    for (int i=0; i<inv->size; i++)
        printf("%-4d %-20s %8.2f %6d\n",
               inv->items[i].id, inv->items[i].nome,
               inv->items[i].prezzo, inv->items[i].quantita);
    printf("Valore totale: %.2f\n", valore_totale(inv));
}

int main() {
    Inventario inv = crea_inventario();
    aggiungi(&inv, "Laptop",     899.99, 5);
    aggiungi(&inv, "Mouse",       29.99, 20);
    aggiungi(&inv, "Tastiera",    59.99, 15);
    aggiungi(&inv, "Monitor",    349.99, 8);
    stampa(&inv);

    Prodotto *p = cerca(&inv, "Mouse");
    if (p) { p->quantita += 10; printf("\nAggiornato Mouse a %d pezzi\n", p->quantita); }
    stampa(&inv);

    free(inv.items);
    return 0;
}
3
Stack con struct
Difficilestruct / pila

Implementa uno stack (pila LIFO) generico usando una struct. Operazioni: push, pop, peek (guarda in cima senza rimuovere), is_empty, size. Usalo per verificare se le parentesi di una stringa sono bilanciate: es. "({[]})" → OK, "({)}" → Errore.

C
#include <stdio.h>
#include <string.h>

#define MAX_STACK 100

typedef struct {
    char dati[MAX_STACK];
    int cima;
} StackChar;

void stack_init(StackChar *s)      { s->cima = -1; }
int  stack_empty(StackChar *s)     { return s->cima == -1; }
int  stack_size(StackChar *s)      { return s->cima + 1; }
void stack_push(StackChar *s, char c) { s->dati[++s->cima] = c; }
char stack_pop(StackChar *s)       { return s->dati[s->cima--]; }
char stack_peek(StackChar *s)      { return s->dati[s->cima]; }

int parentesi_bilanciate(const char *str) {
    StackChar s;
    stack_init(&s);

    for (int i = 0; str[i]; i++) {
        char c = str[i];
        if (c=='(' || c=='[' || c=='{') {
            stack_push(&s, c);
        } else if (c==')' || c==']' || c=='}') {
            if (stack_empty(&s)) return 0;
            char top = stack_pop(&s);
            if ((c==')' && top!='(') ||
                (c==']' && top!='[') ||
                (c=='}' && top!='{')) return 0;
        }
    }
    return stack_empty(&s);
}

int main() {
    const char *test[] = {"({[]})", "()[]{}", "({)}", "(((", "{[()]}"};
    for (int i = 0; i < 5; i++) {
        printf("%-12s → %s\n", test[i],
               parentesi_bilanciate(test[i]) ? "BILANCIATO ✓" : "ERRORE ✗");
    }
    return 0;
}