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:

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

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”.