Esercitazione #5



Esercizi sulla compilazione separata

  • [29] Scrivere una macro con parametri FATT che calcoli il fattoriale di un numero positivo passato per parametro. La macro non deve fare assunzioni sul modo nel quale verranno passati i parametri.
    Cosa accade annidando due chiamate? Ad esempio, nel frammento
    FATT(FATT(4 + 1)) ?
    
    Si controlli a tal fine il codice prodotto dal preprocessore.


  • [30] Si realizzi una struttura dati pila che implementa il tipo di dato pila di interi. Oltre alle operazioni di inserzione ed estrazione, una ulteriore operazione int top (pila * p, int x) deve restituire il valore a distanza x dalla testa della pila. Ad esempio, partendo per una pila p dalla situazione
      5   <-- testa della pila
      4
      6   <-- base della pila
    allora push(&p, 7) inserisce il valore 7 sopra la testa 5; poi pop(&p) estrae il valore appena inserito; e top(&p, 2) restituisce 6.
    Si scriva un file pile.c che, oltre alle funzioni richieste, realizzi anche le operazioni pila_new, pila_free e pila_print.

    Soluzione: pila.h, pila.c e testPila.c .


  • [31] Si realizzi un semplice programma che serva per testare la struttura dati pila. Questo deve includere un opportuno file pile.h con i tipi e i prototipi delle funzioni che lavorano sulle pile, ed invocare tutte tali funzioni.

  • [32] Si realizzi una struttura dati lista che implementa il tipo di dato lista concatenata di interi. Si scriva cioè un file liste.c che contenga le definizioni di tipo
      typedef struct nodo {
        int valore;
        struct nodo * next;
      } nodo;
    
      typedef nodo * lista;
    
    e definisca le seguenti funzioni che operano sulla lista
      /* @description -- crea una lista con un singolo nodo
         @param v -- valore del nodo creato
         @return -- il puntatore alla lista */
      lista newNode (int valore);
    
      /* @description -- dealloca una lista con un singolo nodo
         @param l -- la lista da deallocare */
      void freeNode (lista l);
    
      /* @description -- inserisce il nodo n nella lista l dopo il primo elemento
         @param l -- una lista (con numero arbitrario di elementi >=1)
         @param n -- lista con solo il nodo da inserire */
      void insertNext (lista l, lista n);
    
      /* @description -- cancella il secondo elemento dalla lista l 
         @param l -- una lista (con numero arbitrario di elementi >=1)
         @return -- puntatore al nodo estratto */
      lista deleteNext (lista l);
    
      /* @description -- ritorna il valore del primo elemento della lista l
         @param l -- una lista (con numero arbitrario di elementi >=1)
         @return -- il valore del primo elemento di l */
      int valore (lista l);
    
      /* @description -- ritorna il puntatore del secondo elemento della lista l
         @param l -- una lista (con numero arbitrario di elementi >=1)
         @return -- il puntatore al secondo elemento */
      lista next (lista l);
    Definire, oltre a lista.c, un opportuno file lista.h e testarli utilizzando mainListe.c.

  • [33] Si arricchisca la struttura dati dell'esercizio precedente inserendo le due ulteriori funzioni
      /* @description -- costruisce una nuova lista in cui ogni elemento e' ottenuto
                         applicando f al corrispondente elemento di i
         @param l -- una lista (con numero arbitrario di elementi >=0)
         @param f -- la funzione da mappare
         @return -- il puntatore al primo elemento della lista creata */
      lista map (int (*f) (int), lista l);
    
      /* @description -- combina gli elementi della lista l usando un operatore binario associativo 
         @param l -- una lista (con numero arbitrario di elementi >=0)
         @param f -- l'operatore binario
         @param en -- l'elemento neutro di f
    
         @return -- la 'somma' degli elementi di l secondo f (l1 f l2 f ... f lN f en) */
      int reduce(int (*f) (int, int), int en, lista l);
    Si testi il risultato con il file mainListe.c togliendo dal commento la parte compresa fra
     /*DDD DDD */

  • [34] Invasion percolation è una semplice forma frattale basata su un modello di diffusione di fluidi. Su due dimensioni, la sua costruzione può essere simulata nel modo seguente

    • [passo 1] si genera una griglia quadrata di lato s contenente interi nell'intervallo 1...r. Ad esempio, una griglia di lato 5 di numeri minori di 100 può essere

      26 17 72 45 38
      10 38 39 92 38
      44 29 12 29 77
      61 26 90 35 11
      83 84 18 56 52

    • [passo 2] poi si marca il centro della griglia come pieno ('o' indica la cella piena)
       
      26 17 72 45 38
      10 38 39 92 38
      44 29 o 29 77
      61 26 90 35 11
      83 84 18 56 52

    • [passo 3] si effettua un ciclo in cui ad ogni passo: (a) si esaminano i quattro vicini di tutte le celle già piene (ovvero, già marcate con 'o'); (b) si sceglie la cella con il valore minore; e (c) si marca tale cella come piena. Ad esempio, i quattro vicini della cella (2,2) nella griglia sono
       
               
          39    
        29 o 29  
          90    
               
    • L'evoluzione della forma frattale è la seguente (dove '*' indica la cella selezionata ad ogni nuovo passo)
       
      26 17 72 45 38
      10 38 39 92 38
      44 * o 29 77
      61 26 90 35 11
      83 84 18 56 52

       
      26 17 72 45 38
      10 38 39 92 38
      44 o o 29 77
      61 * 90 35 11
      83 84 18 56 52

       
      26 17 72 45 38
      10 38 39 92 38
      44 o o * 77
      61 o 90 35 11
      83 84 18 56 52

    Si richiede di implementare il comando percolation s r che simula la costruzione del frattale su una griglia di lato s con valori nell'inmtervallo 1...r.
    Ogni iterazione viene visualizzata sullo schermo, e la computazione si ferma quando la metà delle celle risulta marcata.

  • Le matrici possono essere rappresentate come array di puntatori a righe. Il file dmat2.c contiene una implementazione delle funzioni per creare e distruggere le matrici rappresentate in questo modo -- mat2_new( ) e mat2_free( ) (verificare i commenti in dmat2.h).
  • Per pulire lo schermo fra una stampa e l'altra si può usare system("clear").
  • Per attendere un istante fra le varie visualizzazioni (che altrimenti non sono visibili) si può usare sleep(1).
  • Per usare system e sleep si deve includere unistd.h