−Indice
Esercitazione 3
Dove si parla di librerie generiche, make e altro …..
Esercizio 1. Variabili static
scrivere una funzione conta
di segnatura
int conta (void);
che restituisce come valore il numero di volte che e' stata invocata dall'inizio del programma, quindi 1 la prima volta, 2 la seconda etc senza utilizzare variabili globali.
Esercizio 2. Static e visibilità
Verificare che dichiarando static una funzione all'interno di un file non e' possibila invocarla da funzioni definite in altri file (suggerimento: provare a definire static
la funzione somma
dell'esempio fatto per la compilazione separata).
Esercizio 3. Liste generiche in C
In questo esercizio si richiede di realizzare alcune funzioni che lavorano su liste generiche in C. Una lista generica e' rappresentata con la seguenti struct
typedef struct elem { /** chiave */ void * key; /** informazione */ struct elem * next; } elem_t; typedef struct { /** la testa della lista */ elem_t * head; /** la funzione per confrontare due chiavi */ int (* compare) (void *, void *); /** la funzione per copiare una chiave */ void * (* copyk) (void *); } list_t;
la prima struttura (elem_t
) rappresenta un nodo della lista generica. Ogni nodo contiene una chiave key
che puo' avere tipo qualsiasi.
La seconda struttura (list_t
) permette di definire una particolare lista a partire da quella generica. Per farlo bisogna fornire due funzioni:
compare
permette di confrontare due chiavi, ritorna 0 se sono uguali ed un valore diverso da 0 altrimenticopyk
crea una copia della chiave (allocando la memoria necessaria) e ritorna il puntatore alla copia (se tutto e' andato bene) o NULL (se si e' verificato un errore)
Si chiede di realizzare le funzioni che permettono di creare/distruggere una lista generica e quelle per inserire ed estrarre un elemento generico. Realizzare un main di test che prova ad istanziare la lista in due versioni: una prima a valori interi usando le seguenti funzioni per il confronto e la copia:
/** funzione di confronto per lista di interi \param a puntatore intero da confrontare \param b puntatore intero da confrontare \retval 0 se sono uguali \retval p (p!=0) altrimenti */ int compare_int(void *a, void *b) { int *_a, *_b; _a = (int *) a; _b = (int *) b; return ((*_a) - (*_b)); } /** funzione di copia di un intero \param a puntatore intero da copiare \retval NULL se si sono verificati errori \retval p puntatore al nuovo intero allocato (alloca memoria) */ void * copy_int(void *a) { int * _a; if ( ( _a = malloc(sizeof(int) ) ) == NULL ) return NULL; *_a = * (int * ) a; return (void *) _a; }
e una seconda che ha come chiavi stringhe usando analoghe funzioni per la copia ed il confronto.
Sviluppare un opportuno main di test di pari passo allo sviluppo delle funzioni.
Esercizio 4: Ancora genericita'....
Modificare il tipo dell'esercizio 3 in modo da riuscire ad implementare anche le funzioni che scrivono su file e leggono da file una lista generica.
Sviluppare un opportuno main di test di pari passo allo sviluppo delle funzioni.
Esercizio 5: Makefile per libreria di liste di interi
Con riferimento all es 2 della scorsa volta definire un file Makefile che contenga
- le regole per generare correttamente i moduli oggeto relativi amain.o e lista.o
- la regola PHONY
lib
per generare correttamente la libreria libList.a - la regola per generare l'eseguibile a partire da oggetti e librerie
- un target PHONY
cleanall
che elimini gli oggetti e gli eseguibili
utilizzare dove possibile le regole implicite, le variabili e le convenzioni viste a lezione. Usare gcc -MM
per generare automaticamente le liste di dipendenze per i target relativi ai moduli oggetto.
Esercizio 6: Makefile per liste generiche
Sviluppare un makefile opportuno che gestisca l'aggiornamento automatico dei file utilizzati per gli esercizi 3 e 4 di questa esercitazione e crei automaticamente la libreria corrispondente con un target “lib”.