Sei sulla pagina 1di 8

2

Abstact Data Type


 ADT, definisce un concetto astratto e il suo
comportamento
Abstact Data Type  Viene utilizzato come una “scatola nera”
(oggetto) di cui è visibile solo che cosa fa e
non come
 Ha funzioni (dette metodi nella
Ver. 2.4
programmazione a oggetti) che possono
essere chiamate per far uso dell’ADT

© 2010 - Claudio Fornaro - Corso di programmazione in C

3 4

Pubblico e privato Struttura di un ADT


 Le parti pubbliche dell’ADT sono visibili e  Un ADT è costituito da:
accessibili da parte di tutte le funzioni del  un’implementazione: uno o più file che
programma (scope globale) contengono il codice che realizza le funzioni/metodi
(pubbliche e private) e le strutture dati interne
 I metodi sono pubblici private
 Le parti private dell’ADT sono visibili e  un’interfaccia: file che descrive le funzioni
accessibili solo dalle funzioni definite nello pubbliche (metodi) che il resto del programma può
stesso file dove è definito l’ADT (scope locale chiamare per utilizzare l’ADT
al file di implementazione)
 Le strutture dati e le funzioni di supporto ai
metodi sono private: non sono accessibili
dall’esterno dell’ADT
5
Esempio 6

Sostituibilità Specifiche richieste


 Se ADT diversi risolvono lo stesso scopo (es.  Si vuole definire il tipo di dato Counter
gestiscono uno stack) e hanno la stessa  Deve poter essere:
interfaccia (es. le funzioni push e pop con lo
visualizzato
stesso prototipo), possono essere utilizzati 

uno in sostituzione dell’altro  azzerato


 La scelta di utilizzare un’implementazione  incrementato di 1
piuttosto che un’altra per risolvere un  I metodi forniti devono essere:
problema è dettata dalle migliori  getCounter()
caratteristiche di una di esse in relazione al  resetCounter()
problema specifico (un’implementazione  incCounter()
potrebbe essere più veloce, ma avere uno
stack di dimensione fissa; un’altra più lenta
ma con uno stack di dimensione variabile)

Esempio – 1a soluzione 7
Esempio – 1a soluzione 8

Scelta della struttura dati counter.h – Interfaccia


 Serve una variabile intera da incrementare: la  L’interfaccia contiene i tipi di dati e i prototipi
struttura dati che conterrà il contatore sarà di dei metodi
tipo int:  typedef int Counter;
typedef int Counter; int getCounter(Counter c);
void resetCounter(Counter *c);
void incCounter(Counter *c);
 Per modificare il parametro c, questo deve
essere passato “per riferimento” (o meglio,
tramite puntatore)
Esempio – 1a soluzione 9
Esempio – 1a soluzione 10

counter.c – Implementazione main()


typedef int Counter; #include <stdio.h>
int getCounter(Counter c) #include "counter.h"
{ main()
return c; {
} Counter x;
void resetCounter(Counter *c)
{ resetCounter(&x);
*c = 0; incCounter(&x);
printf("Valore: %d\n",
}
getCounter(x));
void incCounter(Counter *c)
{ printf("Valore: %d\n", x);
(*c)++; return 0;
}
}

Esempio – 1a soluzione 11 12

Problema Richiamo sulla typdef


 La definizione di Counter è pubblica, chiunque  Si può definire (ma non deferenziare) una
può accedere al valore di una variabile di tipo variabile puntatore ad una struct TAG
Counter anche senza tramite delle funzioni (Tag non omesso) che sarà dichiarata
(ad es. la seconda printf) successivamente o in un altro file
 Si può dichiarare un tipo puntatore (con
 Se nel programma si accede direttamente al typedef) ad una struct TAG che sarà
valore interno di Counter, viene meno la dichiarata successivamente o in un altro file
sostituibilità e non si può sostituire con un  File 1:
altro ADT implementato in un altro modo struct TAG
 In sostanza: non è Abstract { int t; };
 File 2:
 Funziona, ma solo grazie all’autodisciplina del typedef struct TAG *p;
programmatore Questo secondo file non conosce i dettagli
interni di struct TAG
13 14

Struttura di un ADT in C Struttura di un ADT in C


 L’interfaccia viene realizzata da un header  L’ implementazione viene realizzata da uno
file (.h) contenente: o più file (.c) contenenti:
 la definizione del nome dell’ADT  l’ #include dell’interfaccia (il file .h)
 i prototipi dei metodi pubblici dell’ADT  strutture di immagazzinamento dei dati (private)
 L’interfaccia viene inclusa con #include (con  funzioni di creazione di oggetti di quel tipo
le virgolette) in tutti i file che fanno uso (costruttori, pubblici)
dell’ADT e dai file di implementazione dell’ADT  funzioni di accesso per leggere i dati (pubbliche)
stesso  funzioni di manipolazione per modificare i dati
(pubbliche)
 funzioni di rimozione di oggetti di quel tipo
(distruttori, pubblici)
 altre funzioni e variabili di supporto (private)

Esempio – 2a soluzione 15
Esempio – 2a soluzione 16

Scelta della struttura dati Scelta della struttura dati


 Serve una variabile intera da incrementare: la  Il tipo Counter deve essere noto a tutte le
struttura dati che conterrà il contatore sarà di funzioni in tutti i file, quindi viene definito in
tipo int counter.h che viene incluso in tutti i file .c
 Per evitare che sia accessibile senza il tramite  Perché una funzione possa modificare i valori
delle funzioni, la si “nasconde” in dell’oggetto Counter (ossia modificare il
una struct locale dichiarata dentro il file membro nascosto x) bisogna passarle il
counter.c: puntatore all’oggetto stesso, definiamo il tipo
struct CounterInnerType {int x;}; Counter già come puntatore:
typedef
struct CounterInnerType *Counter;
 Si accederà a ciascun oggetto di tipo Counter
mediante questo puntatore detto handler
Esempio – 2a soluzione 17
Esempio – 2a soluzione 18

I metodi counter.h
 L’accesso all’ADT avviene sempre attraverso il /* Tipo Counter */
typedef struct CounterInnerType *Counter;
corrispondente handler: /* Costruttore di un Counter = 0 */
 i costruttori costruiscono un oggetto Counter newCounter(void);
(o istanza) e ne restituiscono l’handler /* Costruttore di un Counter con val */
Counter newInitializedCounter(int initialValue);
 i distruttori distruggono un oggetto, quello di cui
/* Restituisce il valore del Counter */
viene passato l’handler int getCounter(Counter c);
 i metodi di accesso accedono tramite l’handler /* Restituisce il numero di Counter */
all’oggetto, non lo modificano int howmanyCounter(void);
 i metodi di manipolazione accedono tramite /* Azzera un Counter */
l’handler all’oggetto, lo modificano void resetCounter(Counter c);
/* Incrementa un Counter */
void incCounter(Counter c);
/* Distruttore di un Counter */
void deleteCounter(Counter c);

Esempio – 2a soluzione 19
Esempio – 2a soluzione 20

counter.c counter.c
#include <stdlib.h> /****************************/
#include "counter.h" /*prototipi e tipo Counter*/ /* VARIABILI PRIVATE LOCALI */
/****************************/
/* Struttura su cui si basa Counter */
/* è definito qui e non nell'header perche' non
/* Variabile (globale) che tiene conto di quanti
sia visibile fuori dal file */
Counter sono stati creati. Deve essere privata
struct CounterInnerType
dell'ADT, quindi static */
{
static int numCounters = 0;
int x;
};

/* Tipo Counter, così come visto dal programma */


/* deve essere visibile pubblicamente quindi
viene definito nell'header e non qui */
/* typedef struct CounterInnerType *Counter; */
Esempio – 2a soluzione 21
Esempio – 2a soluzione 22

counter.c counter.c
/****************************/ /*****************/
/* FUNZIONI PRIVATE LOCALI */ /* COSTRUTTORI 1 */
/****************************/ /*****************/

/* Imposta il valore di un Counter al valore dato, /* Costruttore di un Counter con val iniz 0 */
e' una funzione di supporto: non deve essere Counter newCounter(void)
utilizzata se non dai metodi di questo ADT, {
quindi static per renderla locale,
inoltre non e' nell’interfaccia */ Counter c;
static void setCounter(Counter c, int value)
{ c = (Counter)malloc(sizeof(CounterInnerType));
c->x = value; resetCounter(c);
} numCounters++;
return c;
}

Esempio – 2a soluzione 23
Esempio – 2a soluzione 24

counter.c counter.c
/*****************/ /*********************/
/* COSTRUTTORI 2 */ /* METODI DI ACCESSO */
/*****************/ /*********************/

/* Restituisce il valore del Counter indicato */


/* Costruttore di un Counter con il valore
iniziale indicato */ int getCounter(Counter c)
{
Counter newInitializedCounter(int initialValue)
return c->x;
{
}
Counter c = newCounter();
setCounter(c, initialValue); /* chiamata ad una
/* Restituisce il numero di Counter creati */
funzione locale */
int howmanyCounter(void)
return c;
{
}
return numCounters;
}
Esempio – 2a soluzione 25
Esempio – 2a soluzione 26

counter.c counter.c
/***************************/ /***************/
/* METODI DI MANIPOLAZIONE */ /* DISTRUTTORI */
/***************************/ /***************/

/* Azzera un Counter */
/* Distruttore di un Counter */
void resetCounter(Counter c)
void deleteCounter(Counter c)
{
{
c->x = 0;
} free(c);
numCounters--;
/* Incrementa un Counter */ }
void incCounter(Counter c)
{
(c->x)++;
}

Esempio – 2a soluzione 27 28

main.c Esercizi
#include<stdio.h>
1. Si realizzi un ADT che implementi uno stack
#include "counter.h"
main() con un vettore di interi, il numero di elementi
{ int v; venga passato al costruttore. Stessa
Counter x = newCounter(); interfaccia dell’esercizio visto nelle funzioni,
salvo che serve passare anche l’handler allo
Counter y = newInitializedCounter(10);
v = getCounter(x);
v = howmanyCounter(); stack da utilizzare. Il main deve poter agire
incCounter(x); sulle due istanze degli stack a scelta.
v = getCounter(x);
resetCounter(x); 2. Si realizzi un ADT che implementi una coda
v = getCounter(x); circolare con un vettore di interi, il numero di
deleteCounter(y); elementi venga passato al costruttore. Il resto
v = howmanyCounter();
è come per l’esercizio precedente.
deleteCounter(x);
}
29 30

Homework 12 Homework 13
Si realizzi un ADT che implementi un tipo di dato Si realizzi un ADT (con controlli di errore e
denominato Matrice contenente una matrice documentazione) che realizzi con liste le
di valori int, con metodi per: funzionalità di uno stack e di una pila di int.
 creare una matrice date le dimensioni
Si usino opportune typedef o #define per
 distruggerla dato l’handler
 azzerare una matrice
poter permettere di cambiare facilmente il tipo
 inserire un valore in una casella (riga,colonna)
primitivo int in un altro.
 restituire il valore di una casella Fare il test dell’ADT mediante un main che
 visualizzare tutta la matrice istanzi due o più pile e stack.
 sommare due matrici
 moltiplicare due matrici
Si facciano gli opportuni controlli sui possibili
errori

31 32

Homework 14 Homework 14
Si continui l’Homework precedente aggiungendo Inoltre si modifichi la gestione dei cursori in
i metodi seguenti. modo che ce ne possa essere più di uno, a tal
 listShowAll (mostra tutta la lista da head) scopo si aggiungano opportune typedef per
 listMerge (mette insieme due liste, in modo che il tipo e i metodi:
la prima contenga anche i valori della seconda, la  listNewCursor (crea un nuovo cursore)
seconda sarà azzerata; se una delle due è  listDeleteCursor (cancella un cursore)
ordinata, la lista risultante deve essere ordinata)
 listSplit (divide una lista – ordinata o no – in
due liste, viene passato come argomento l’indice
dell’elemento che sarà il primo della seconda lista,
restituita dal metodo come valore di ritorno)
 listClearFrom (elimina la parte della lista che
inizia dall’elemento indicato, incluso)