Strutture, Union ed Enum
Tipi di dato personalizzati: struct, union, enum e typedef.
struct — Strutture Dati
Una struct raggruppa variabili di tipi diversi in un unico tipo personalizzato. È la base della programmazione a oggetti in C.
#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;
}
. per accedere ai campi di una struct. Usa la freccia -> quando hai un puntatore a struct. p->campo è equivalente a (*p).campo.
Struct Annidate
#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.
#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.
#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;
}
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.
#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;
}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.
#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;
}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.
#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;
}