Strutture (struct) in C
In questa pagina 6
In questa pagina 3
Definizione
Definizione (struct). Una
structraggruppa in un unico tipo più campi di tipo anche diverso (come una tupla con nomi o un semplice oggetto Python con soli attributi).
Esempio. Con struct punto p = {1.0, 2.0}; p.x = 4.0; si ha p.x == 4.0 e p.y == 2.0.
struct punto {
double x;
double y;
};
struct punto p = {1.0, 2.0};
struct punto q = {.y = 5.0, .x = 3.0}; /* inizializzatori con nome */
p.x = 4.0; /* accesso ai campi con . */Con typedef si dà un nome più corto al tipo:
typedef struct {
char nome[32];
int matricola;
double media;
} Studente;
Studente s = {"Ada", 123456, 28.5};Proprietà (assegnazione e dimensione di una struct)
- Una
structsi può assegnare (q = p;copia tutti i campi, anche gli array interni) ma non confrontare con==.sizeof(Studente)può essere maggiore della somma dei campi per l'allineamento in memoria (padding).
Esempio. Con Studente (char nome[32], int, double) sizeof(Studente) vale 48, più dei byte dei campi per il padding; q = p copia tutti i campi.
Struct e funzioni
Definizione (struct passate a funzioni). Una
structpassata per valore viene copiata per intero; per modificarla o per evitare la copia di strutture grandi si passa un puntatore. Con un puntatore i campi si raggiungono con->:ps->mediaequivale a(*ps).media.
Esempio. medio applicata ai punti e restituisce per valore la struct .
double distanza(struct punto a, struct punto b) { /* per valore */
return sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y));
}
void aggiorna_media(Studente *ps, double nuovo_voto, int n_esami) {
ps->media = (ps->media * (n_esami - 1) + nuovo_voto) / n_esami;
}
struct punto medio(struct punto a, struct punto b) { /* struct come valore di ritorno */
struct punto m = {(a.x + b.x) / 2, (a.y + b.y) / 2};
return m;
}Restituire una struct è il modo pulito di restituire più valori insieme (alternativa ai parametri puntatore di Puntatori in CUn puntatore contiene un indirizzo di memoria; operatori & e *, NULL, puntatori come parametri per modificare variabili del chiamante, aritmetica dei puntatori, legame tra array e puntatori, const, puntatori a puntatori.Puntatori in C →).
Array di struct
Studente classe[3] = {
{"Ada", 1, 29.0},
{"Alan", 2, 27.5},
{"Grace", 3, 30.0},
};
int migliore = 0;
for (int i = 1; i < 3; i++)
if (classe[i].media > classe[migliore].media)
migliore = i;
printf("%s\n", classe[migliore].nome);Struct dinamiche
Studente *ps = malloc(sizeof *ps);
if (ps != NULL) {
strcpy(ps->nome, "Ada");
ps->matricola = 1;
free(ps);
}Struct autoreferenziali
Definizione (struct autoreferenziale). Una
structnon può contenere se stessa, ma può contenere un puntatore al proprio tipo. È la base delle strutture collegate:typedef struct nodo { int valore; struct nodo *succ; /* serve il nome "struct nodo": il typedef non è ancora completo */ } Nodo;
Esempio. Con Nodo n1 = {1, NULL}; Nodo n2 = {2, &n1}; si ha n2.succ->valore == 1.
Uso in Liste concatenateLista concatenata semplice: nodi allocati dinamicamente collegati da puntatori; inserimento e rimozione in testa, scorrimento, ricerca, inserimento ordinato, deallocazione; confronto dei costi con l'array; versione in Python.Liste concatenate → e, come tipo che nasconde la rappresentazione, in Tipi di dato astrattiUn ADT è definito dalle operazioni e dal loro comportamento, non dalla rappresentazione; interfaccia e implementazione; realizzazione in Python con le classi e in C con header e tipo opaco; esempio di un ADT Frazione.Tipi di dato astratti →.
Errori tipici
ps.campocon un puntatore (serveps->campo) os->campocon una struct (serves.campo).- Aspettarsi che una funzione modifichi una struct ricevuta per valore.
- Dimenticare il
;dopo la}della definizione. - Copiare una struct che contiene puntatori pensando di copiare anche i dati puntati: si copiano solo gli indirizzi (copia superficiale, come in Liste in Pythonlist come sequenza mutabile (array dinamico); indici, slicing e assegnamento a fette; metodi e loro costo; aliasing, copia superficiale e profonda; list comprehension; liste annidate e matrici.Liste in Python →).
Versione ripasso
Definizione e uso
Una struct raggruppa più campi di tipo anche diverso; typedef dà un nome più corto al tipo.
typedef struct {
char nome[32];
int matricola;
double media;
} Studente;
Studente s = {"Ada", 123456, 28.5}; /* campo con ".": s.media */- Si possono assegnare (
q = p;copia tutti i campi), ma non confrontare con==. sizeofpuò essere maggiore della somma dei campi per l'allineamento in memoria (padding).
Passaggio alle funzioni:
- Per valore: viene copiata intera.
- Tramite puntatore: si evitano copie e si modificano i campi con
->(ps->mediaequivale a(*ps).media). - Valore di ritorno: modo pulito per restituire più valori insieme (alternativa ai puntatori di Puntatori in CUn puntatore contiene un indirizzo di memoria; operatori & e *, NULL, puntatori come parametri per modificare variabili del chiamante, aritmetica dei puntatori, legame tra array e puntatori, const, puntatori a puntatori.Puntatori in C →).
Array, allocazione dinamica e autoreferenzialità
- Array di struct: dichiarati e indicizzati come gli array normali (
classe[i].media). - Struct dinamiche: allocate con
malloc(sizeof *ps)(vedi Gestione della memoria in CSegmenti di memoria di un processo (codice, dati statici, stack, heap); durata delle variabili; allocazione dinamica con malloc, calloc, realloc e free; errori classici: memory leak, dangling pointer, double free, buffer overflow; strumenti di controllo.Gestione della memoria in C →). - Struct autoreferenziali: contengono un puntatore al proprio tipo (base per Liste concatenateLista concatenata semplice: nodi allocati dinamicamente collegati da puntatori; inserimento e rimozione in testa, scorrimento, ricerca, inserimento ordinato, deallocazione; confronto dei costi con l'array; versione in Python.Liste concatenate → e Tipi di dato astrattiUn ADT è definito dalle operazioni e dal loro comportamento, non dalla rappresentazione; interfaccia e implementazione; realizzazione in Python con le classi e in C con header e tipo opaco; esempio di un ADT Frazione.Tipi di dato astratti →).
typedef struct nodo {
int valore;
struct nodo *succ; /* serve il nome "struct nodo" */
} Nodo;Errori tipici
- Usare
ps.campocon un puntatore (serveps->campo) os->campocon una struct (serves.campo). - Aspettarsi che una funzione modifichi una struct ricevuta per valore.
- Dimenticare il
;dopo la}della definizione. - Copiare struct con puntatori aspettandosi una copia profonda dei dati (copia superficiale, vedi Liste in Pythonlist come sequenza mutabile (array dinamico); indici, slicing e assegnamento a fette; metodi e loro costo; aliasing, copia superficiale e profonda; list comprehension; liste annidate e matrici.Liste in Python →).