La presentazione è in caricamento. Aspetta per favore

La presentazione è in caricamento. Aspetta per favore

Anno accademico 2010-2011 1 Le strutture e le unioni in C.

Presentazioni simili


Presentazione sul tema: "Anno accademico 2010-2011 1 Le strutture e le unioni in C."— Transcript della presentazione:

1 Anno accademico Le strutture e le unioni in C

2 Anno accademico Sommario Le strutture e le unioniLe strutture e le unioni Le liste concatenateLe liste concatenate Allocazione dinamica Allocazione dinamica Creazione ed aggiunta di un nuovo elemento alla lista Creazione ed aggiunta di un nuovo elemento alla lista Inserimento e cancellazione di elementi Inserimento e cancellazione di elementi La ricerca di un elemento La ricerca di un elemento

3 Anno accademico Le strutture e le unioni

4 Anno accademico Gli array sono uno strumento adeguato per il trattamento di insiemi di variabili di uno stesso tipo strutturarecordQuando i tipi di dati, che devono essere logicamente aggregati, sono disomogenei, è necessario usare il tipo struttura (o record) unione record a lunghezza variabileLulteriore tipo composto unione consente di interpretare il contenuto delle stesse locazioni di memoria con modalità diverse (è la realizzazione del concetto di record a lunghezza variabile) 4 Introduzione

5 Anno accademico Esempio:Esempio: Supponiamo di voler memorizzare, relativamente a ciascun abitante di un dato comune, nome e cognome, data di nascita e codice fiscale: Nome e cognome costituiscono un array di caratteri La data è composta da tre numeri interi, che descrivono giorno, mese ed anno Il codice fiscale è un array di 16 caratteri (15 per il codice ed uno per il carattere nullo di terminazione) Le informazioni non possono essere collezionate in un unico array di caratteri, perché sono disomogenee Le informazioni non possono essere collezionate in un unico array di caratteri, perché sono disomogenee 5 Le strutture 1

6 Anno accademico Possibile soluzione:Possibile soluzione: memorizzare le informazioni in variabili distinte strutturaUnorganizzazione più naturale consiste nella definizione di una variabile che contenga tutti i dati relativi ad una persona: utilizzando un tipo struttura campi nomiUna struttura è simile ad un array, ma è costituita da campi (piuttosto che da elementi) che sono identificati da nomi (piuttosto che da indici) e possono contenere informazione di tipo diverso Le informazioni relative ad una persona sono sparse per la memoria char name[20], fiscode[16]; short day, month, year; 6 Le strutture 2

7 Anno accademico schema vitalstat vs struct vitalstatVi sono due dichiarazioni: la prima contiene lo schema della struttura vitalstat, la seconda dichiara una variabile vs di tipo struct vitalstat Nota:Nota: includere un prefisso nei nomi dei campi, per distinguerli da campi di strutture diverse struct vitalstat { char vs_name[20],vs_fiscode[16]; short vs_day,vs_month,vs_year; }; struct vitalstat vs; vsLallocazione della struttura vs sulla macchina di riferimento presuppone che i campi siano memorizzati consecutivamente, nellordine in cui sono dichiarati, ma non necessariamente in maniera contigua Esempio vs_fiscode[] vs_year[] vs_name[] vs_day[]vs_month[] 7 Le strutture 3

8 Anno accademico vitalstat etichettatag struct vitalstatIl nome vitalstat è unetichetta (o tag) e struct vitalstat rappresenta un nuovo tipo di dati definito dallutente, per il quale non viene riservata memoria Letichetta può essere utilizzata ogni volta che è necessario creare ulteriori variabili che contengono gli stessi campi La sintassi della dichiarazione di una struttura può assumere diverse forme: Dichiarazione delletichetta e uso delletichetta struct per definire le variabili Dichiarazione delletichetta e uso delletichetta (insieme alla parola chiave struct ) per definire le variabili Uso di typedef per definire un particolare tipo struttura Uso di typedef per definire un particolare tipo struttura struct vitalstat vsa[1000], *pvs; pvs &vsa[10]; 8 Le strutture 4

9 Anno accademico Il nome di tipo è scritto maiuscolo, per distinguerlo dai nomi di etichette e variabili typedefUnetichetta o un typedef consentono di definire una sola volta lo schema di una struttura, per dichiarare variabili del tipo struttura quando necessario file headerLe dichiarazioni di struttura sono normalmente raggruppate in file header, così da poter essere accedute da più file sorgente VITALSTAT structIl tipo VITALSTAT rappresenta lintera struttura, compresa la parola chiave struct typedef struct { char vs_name[20],vs_fiscode[16]; short vs_day, vs_month, vs_year; } VITALSTAT; 9 Le strutture 5

10 Anno accademico Una struttura può essere inizializzata facendo seguire al nome della variabile di tipo struttura il simbolo di uguale e la lista dei valori iniziali racchiusi tra parentesi graffe Ogni valore iniziale deve essere dello stesso tipo del corrispondente campo della struttura VITALSTAT vs {Marco Rossi, MRCRSS91C23D612K, 23, 3, 1991}; 10 Linizializzazione di strutture 1

11 Anno accademico typedefUn valore iniziale non può essere incluso in una dichiarazione che contiene solo unetichetta o un typedef, poiché tali dichiarazioni definiscono lo schema della struttura, ma non riservano memoria typedef struct { int a; float b; } s {1, 1.0}; /* non ammesso */ 11 Linizializzazione di strutture 2

12 Anno accademico Laccesso ai campi della struttura Esistono due modalità diverse di accesso ai campi di una struttura, dipendenti dalla modalità di accesso alla struttura, diretta o mediante puntatore. Nel caso di accesso diretto alla struttura, si usano il nome della struttura ed il nome del campo, separati dalloperatore punto. > Nel caso di accesso tramite puntatore alla struttura, si usa loperatore freccia destra >, formato dalla concatenazione del segno meno e del simbolo maggiore >Loperatore > è una forma abbreviata per accedere allindirizzo contenuto nel puntatore e quindi applicare loperatore punto VITALSTAT *pvs; … … … pvs >vs_day 23; pvs >vs_month 3; pvs >vs_year 1991; pvs >vs_day è equivalente a (*pvs).vs_day vs.vs_day 23; vs.vs_month 3; vs.vs_year 1991;

13 Anno accademico include v_stat.h /* file header che contiene la dichiarazione * typedef VITALSTAT */ int agecount(vsa,size,low_age,high_age,current_year) VITALSTAT vsa[]; int size, low_age, high_age, current_year; { int age, count 0; VITALSTAT *p vsa, *p_last &vsa[size]; for (; pvs_year; if ((age > low_age) && (age < high_age)) count ; } return count; } Esempio: Esempio: Funzione che calcola il numero di persone con età compresa in un intervallo specificato p p_last vsa Le variabili locali p e p_last sono state introdot- te per mantenere invariato il valore del parametro formale vsa (che altrimenti potrebbe essere usato direttamente nel ciclo) typedefGli array di strutture vengono dichiarati facendo precedere al nome dellarray il nome typedef della struttura 13 Gli array di strutture

14 Anno accademico struttura innestataUna struttura innestata è una struttura in cui almeno uno dei campi è, a sua volta, una struttura Le strutture innestate sono comuni in C perché consentono di creare gerarchie di dati typedef struct { char day; char month; short year; } DATE; typedef struct { char vs_name[20], vs_fiscode[16]; DATE vs_birth_date; } VITALSTAT; typedef struct { char vs_name[20], vs_fiscode[16]; struct vs_birth_date { short vs_day; short vs_month; short vs_year; }; } VITALSTAT; vsVITALSTAT Per identificare lanno di nascita in una struttura vs dichiarata VITALSTAT, si deve scrivere vs.vs_birth_date.vs_year 14 Le strutture innestate 1

15 Anno accademico Una struttura innestata viene inizializzata racchiudendo i valori iniziali fra parentesi graffe nestingNon esistono limiti al numero di livelli di nesting delle strutture, anche se i riferimenti agli elementi diventano sempre più difficili da leggere perché contengono i nomi di tutte le strutture intermedie typedef struct { DATE d; char event[20]; } CALENDAR; CALENDAR holiday {{25, 12, 2010}, Natale}; 15 Le strutture innestate 2

16 Anno accademico Le strutture e le unioni non possono contenere istanze di sé stesse, ma possono contenere puntatori a sé stesse Il compilatore consente di dichiarare un puntatore ad una struttura prima che sia stata dichiarata la struttura struct s { int a, b; float c; struct s *pointer_to_s; }; 16 Le strutture contenenti puntatori a sé stesse 1

17 Anno accademico Le strutture contenenti puntatori a sé stesse 2 riferimento in avantiIl riferimento in avanti a strutture (e unioni) è uno dei pochi casi nel linguaggio C in cui un identificatore può essere utilizzato prima di essere dichiarato typedefIl riferimento in avanti non è ammesso con la definizione di tipo ( typedef ) typedef struct neg { int a; FOO *p; /* errato perché FOO non * è ancora stato dichiarato */ } FOO;

18 Anno accademico Lallineamento dei campi delle strutture 1 charAlcune architetture (come i processori Motorola) richiedono che ogni oggetto di dimensioni superiori ad un char venga memorizzato in locazioni di memoria con indirizzo pari spazi vuotiI problemi di allineamento non sono normalmente visibili al programmatore, ma possono creare spazi vuoti allinterno delle strutture struct align_examp { char mem1; short mem2; char mem3; } s1; mem1mem2mem3 mem1mem2 mem3 spazio vuoto Allocazione con restrizioni di allineamento Allocazione senza restrizioni di allineamento

19 Anno accademico Lallineamento dei campi delle strutture 2 Gli spazi vuoti vengono eliminati da una redistribuzione delle dichiarazioni degli elementi Poiché le strutture possono essere memorizzate in modi diversi sui diversi calcolatori, è necessario accedervi con modalità portabili allineamento naturaleLallineamento naturale (tutti gli oggetti di 2 byte iniziano da indirizzi pari, gli oggetti di 4 byte a indirizzi divisibili per quattro, etc.) è il requisito più stringente imposto dai calcolatori Se la struttura è allineata in modo naturale è portabile struct align_examp { char mem1, mem3; short mem2; } s1;

20 Anno accademico Il passaggio di strutture come parametri di funzione 1 Esistono due modalità per passare strutture come argomenti di funzione: per valore Passaggio della struttura vera e propria, per valore per indirizzo Passaggio di un puntatore alla struttura, per indirizzo Il passaggio per indirizzo è più efficiente perché solo il puntatore viene copiato nellarea di memoria degli argomenti, mentre il passaggio per valore richiede la copia dellintera struttura VITALSTAT vs; … … … func1(vs); /* Passaggio per valore */ … … … func2(&vs); /* Passaggio per indirizzo */

21 Anno accademico Il passaggio di strutture come parametri di funzione 2 Le strutture dovrebbero essere passate per valore solo se… …la struttura è molto piccola (di dimensione paragonabile al puntatore) …è necessario garantire che la funzione chiamata non ne alteri il contenuto originale In dipendenza della modalità di passaggio prescelta, occorre dichiarare il parametro allinterno della funzione come struttura o come puntatore a struttura void func2(pvs) VITALSTAT *pvs; /* largomento è un puntatore a struttura */ void func1(vs) VITALSTAT vs; /* largomento è una struttura */

22 Anno accademico Il passaggio di strutture come parametri di funzione 3 La scelta della modalità di passaggio dei parametri struttura definisce gli operatori da impiegare allinterno della funzione chiamata: il punto se la struttura è passata per valore la freccia destra se è passata per indirizzo

23 Anno accademico Il passaggio di strutture ed array come parametri di funzione 1 Le modalità per il passaggio di strutture e di array come parametri di funzione non sono omogenee Per passare un array, si specifica il solo nome dellarray senza indici: il compilatore interpreta il nome come un puntatore al primo elemento dellarray, che viene passato per indirizzo Non è possibile passare un array per valore, se non includendolo in una struttura passata per valore Per le strutture, il nome viene interpretato come lintera struttura Applicando la stessa sintassi si ottiene una semantica diversa int ar[100]; struct tag st; … … … funcv(ar); /* viene passato un puntatore al primo elemento di ar[] */ … … … funcs(st); /* viene passata lintera struttura */

24 Anno accademico Il passaggio di strutture ed array come parametri di funzione 2 La stessa inconsistenza si riproduce anche allinterno delle funzioni Le due versioni basate su array sono equivalenti: Le due versioni basate su strutture non lo sono: void funcs(st) struct tag st; /* st è una struttura completa */ void funcs1(st); struct tag *st; /* st è un puntatore a struttura */ void funcv(ar) int ar[]; /* ar viene convertito in puntatore ad intero */ void funcv(ar); int *ar; /* ar è un puntatore ad intero */

25 Anno accademico Strutture restituite da funzioni 1 Le funzioni possono restituire strutture o puntatori a strutture La dichiarazione del tipo di dato restituito da una funzione deve essere concorde con il valore effettivamente restituito Generalmente, è preferibile restituire puntatori a strutture per motivi di efficienza Se si restituisce un puntatore a struttura, la struttura deve avere durata fissa, perché altrimenti non sarebbe più accessibile al termine della funzione La restituzione di strutture è particolarmente utile quando si voglia comunicare allesterno più di un valore

26 Anno accademico Strutture restituite da funzioni 2 include define TOO_LARGE 100 /* dipendente dalla macchina */ define NULL (void *) 0 typedef struct { double sine, cosine, tangent; } TRIG; TRIG *get_trigvals(radian_val) double radian_val; { static TRIG result; /* se radian_val è troppo grande, i valori sin, cos, tan non sono significativi */ if (radian_val > TOO_LARGE) { printf(Valore di ingresso troppo grande); return NULL; } result.sine sin(radian_val); result.cosine cos(radian_val); result.tangent tan(radian_val); return (&result); }

27 Anno accademico Lassegnamento di strutture Lo standard ANSI consente di assegnare una struttura ad una variabile struttura dello stesso tipo struct { int a; float b; } s1, s2, sf(), *ps; … … … s1 s2; s2 sf(); ps &s1; s2 *ps; … … …

28 Anno accademico Le unioni 1 Le unioni consentono agli elementi di sovrapporsi luno sullaltro per condividere la stessa area di memoria Esempio:Esempio: Il compilatore riserva sempre una quantità di memoria sufficiente allelemento più grande e tutti gli elementi iniziano allo stesso indirizzo typedef union { struct struct { char c1, c2; char c1, c2; } s; } s; long j; long j; float x; float x; } U; x j c1 c

29 Anno accademico Esempio sulle unioni 1 I dati viaggiano sulla linea un byte alla volta; le unioni consentono di raggruppare i byte in modo tale che i dati possano essere ricostruiti nella loro forma originale get_byte()Sia get_byte() una funzione che restituisce un singolo byte prelevato da un dispositivo di comunicazione double get_byte()Un valore double a otto byte può essere estratto dal dispositivo mediante otto chiamate successive alla funzione get_byte()

30 Anno accademico Esempio sulle unioni 2 union doub { char c[8]; double val; }; double get_double() { extern char get_byte(); int j; union doub d; for (j 0; j<8; j ) d.c[j] get_byte(); return d.val; } c[] double valI caratteri ricevuti vengono memo- rizzati in elementi successivi di c[] : il valore del numero double si ottiene accedendo al campo val dellunione Laccesso ai campi di ununione non ha impatto alcuno sui bit contenuti in memoria (non si effettuano conversioni di tipo): il compilatore interpreta in modo diverso gli stessi bit

31 Anno accademico Le liste concatenate

32 Anno accademico Allocazione dinamica 1 Finora, per gestire insiemi di dati, sono stati utilizzati array (di strutture) Tale approccio è valido se si conosce a priori il numero di elementi che si devono gestire Viceversa, lutilizzo di array può essere estremamente oneroso, perché rende necessaria lallocazione di una quantità di memoria sufficiente a memorizzare il caso peggiore: Parte della memoria può andare sprecata (perché inutilizzabile per scopi diversi) Non è possibile accedere ad una quantità di memoria maggiore di quella allocata inizialmente

33 Anno accademico Allocazione dinamica 2 malloc() calloc()La soluzione consiste nellallocare memoria in modo dinamico, con malloc() o calloc() che, tuttavia, non garantiscono la contiguità fisica per elementi logicamente contigui e nellutilizzare liste concatenate liste semplicemente/doppiamenteconcatenateIl modo più comune per garantire la contiguità logica di strutture allocate dinamicamente è infatti luso delle liste semplicemente/doppiamente concatenate

34 Anno accademico Le liste concatenate 1 In una lista concatenata, ogni struttura contiene un elemento aggiuntivo (un puntatore) che punta alla struttura successiva liste semplici liste doppiamente concatenateEsistono liste semplici e liste doppiamente concatenate, in cui ogni struttura possiede due puntatori, rispettivamente allelemento precedente ed al successivo typedef struct vitalstat { char vs_name[20], vs_fiscode[16]; unsigned int vs_day, vs_month, vs_year; struct vitalstat *next; } VITALSTAT; Dati Lista concatenata semplice

35 Anno accademico Le liste concatenate 2 Le operazioni che si effettuano sulle liste sono: Creazione di un elemento Creazione di un elemento Aggiunta di un elemento alla fine della lista Aggiunta di un elemento alla fine della lista Inserimento di un elemento in una lista Inserimento di un elemento in una lista Cancellazione di un elemento da una lista Cancellazione di un elemento da una lista Ricerca di un elemento in una lista Ricerca di un elemento in una lista Tutte le operazioni, tranne la ricerca, sono indipen- denti dal contenuto informativo delle strutture (dai campi dati) e possono essere formulate in modo generale

36 Anno accademico La creazione di un elemento 1 Per creare un elemento di una lista, è sufficiente riservare memoria per la struttura e restituire un puntatore allarea allocata include v_stat.h include ELEMENT *create_list_element() { ELEMENT *p; p (ELEMENT *)malloc(sizeof(ELEMENT)); if (p NULL) { printf(create_list_element: malloc non riuscita.\n); exit(1); } p > next NULL; return p; } Alloca la memoria ad un elemento della lista, ma non lo collega alla lista stessa

37 Anno accademico La creazione di un elemento 2 Note:Note: ELEMENT Il nome ELEMENT rende la funzione indipendente dal tipo di dati effettivamente gestiti create_list_element() vitalstat v_stat.h Per utilizzare la funzione create_list_element() in relazione alla struttura vitalstat, è necessario includere nel file v_stat.h (che contiene la definizione del tipo struttura) le ulteriori dichiarazioni: ELEMENTstruct vitalstat ELEMENT diviene un sinonimo di struct vitalstat typedef typedef Per dichiarare il puntatore occorre usare unetichetta invece di un typedef : è la sola modalità con cui una struttura può fare riferimento a sé stessa, dato che il nome di typedef non è definito fino al termine della dichiarazione define NULL (void *) 0 typedef struct vitalstat ELEMENT;

38 Anno accademico Laggiunta di un nuovo elemento 1 include v_stat.h static ELEMENT *head; void add_element(e) ELEMENT *e; { ELEMENT *p; /* se il primo elemento non esiste, * viene creato */ if (head NULL) { head e; return; } /* altrimenti, trova lultimo elemento */ for (p head; p >next ! NULL; p p >next) ; /* istruzione vuota */ p > next e; } headLa variabile head è un puntatore allinizio della lista ed è dichiarata con ambito di visibilità a li- vello di file, per renderla disponibile a più funzioni for p->next NULLNel ciclo for, la scan- sione della lista è basata sul controllo del valore di p->next : se è diver- so da NULL, esiste un elemento successivo, al- trimenti è stata rag- giunta la fine della lista

39 Anno accademico Laggiunta di un nuovo elemento 2 Lassegnamento p >next e; aggiunge una nuova struttura alla fine della lista eLargomento e della funzione è un puntatore alla struttura che è stata allocata dalla funzione chiamante Esempio: vitalstatEsempio: Creare una lista concatenata di dieci strutture vitalstat include v_stat.h static ELEMENT *head; main() { for (j 0; j<10; j ) add_element(create_list_element()); }

40 Anno accademico Linserimento di un elemento Per inserire un elemento in una lista concatenata, deve essere specificata la posizione in cui deve avvenire linserimento q >next >next dopo q pprima q q >next include v_stat.h void insert_after(p,q) /* inserimento di p dopo q */ ELEMENT *p, *q; { /* controllo di validità degli argomenti */ if((p NULL)) || (q NULL) || (p q)|| (q >next p)) { printf(insert_after: argomenti errati.\n); return; } p > next q > next; q > next p; }

41 Anno accademico La cancellazione di un elemento 1 Per la cancellazione di un elemento da una lista concatenata, occorre individuare lelemento che precede quello da eliminare per riallacciare i puntatori della lista dopo leliminazione free()Inoltre, è necessario utilizzare la funzione free() per rilasciare la memoria dellelemento eliminato dopo p p >next prima p p >next >next goner

42 Anno accademico La cancellazione di un elemento 2 include v_stat.h static ELEMENT *head; void delete_element(goner) ELEMENT *goner; { ELEMENT *p; if (goner head) head goner >next; else { for (p head;(p! NULL) && (p >next! goner);p p >next) ; /* istruzione vuota */ if (p NULL) { printf(delete_element: elemento non contenuto nella lista.\n); return; } p >next p >next >next ; } free(goner); } Loperatore freccia destra ha associatività sinistra e pertanto lespressione p >next >next viene valutata come (p >next) >next

43 Anno accademico La ricerca di un elemento 1 La funzione di ricerca di un elemento della lista viene fatta in base al contenuto di uno o più campi della struttura Esempio: vitalstat nameEsempio: Funzione che ricerca, fra strutture di tipo vitalstat, un elemento per cui il valore del campo name coincida con largomento della funzione

44 Anno accademico La ricerca di un elemento 2 include v_stat.h include static ELEMENT *head; ELEMENT *find(aname) char *aname; { ELEMENT *p; for (p head; p ! NULL; p p >next) if (strcmp(p >vs_name, aname) 0) return p; return NULL; }

45 Anno accademico Costruzione di una lista ordinata 1 /* ** Letta in input una sequenza di numeri interi la ** memorizza in una lista in ordine crescente. ** */ #include /* ** struttura per la rappresentazione dei nodi della ** lista */ struct nodo { int info; struct nodo *next; }; /* * Funzione principale. */ main(void) { struct nodo *primo; primo leggi_lista_ordinata(); stampa_lista(primo); exit(0); }

46 Anno accademico Costruzione di una lista ordinata 2 /* * Legge una sequenza di numeri interi e li memorizza in * una lista ordinata (in ordine crescente). * Restituisce il puntatore al primo elemento della lista. */ struct nodo *leggi_lista_ordinata(void) { struct nodo *p, *p1, *primo, *prec; int i, n, num; primo = NULL; printf(Inserire numero di elementi: ); scanf(%d, &n); for (i 0; iinfo num; p1 primo; prec NULL; while((p1! NULL)&&(p1->info info)) { prec p1; p1 p1->next; } if (prec ! NULL) prec->next p; else primo p; p->next p1; } return(primo); }

47 Anno accademico Costruzione di una lista ordinata 3 /* * Stampa la lista, a partire dallelemento puntato dal * puntatore p, ricevuto come parametro. */ void stampa_lista(p) struct nodo *p; { while (p ! NULL) { printf(%d --->, p->info); p p->next; } printf(NULL\n); return; }


Scaricare ppt "Anno accademico 2010-2011 1 Le strutture e le unioni in C."

Presentazioni simili


Annunci Google