Altri esempi di tipi

La definizione di un nuovo tipo equivalente a un vecchio tipo numerico è il caso più semplice. Ora vediamo dei casi più complessi. Iniziamo dal caso in cui definiamo il tipo vettore. La definizione di tipo risulta in questo caso più complessa:

typedef int TipoVettore[100];

Questa definizione non è facile da interpretare. Assomiglia alla dichiarazione di una variabile vettore di tipo intero, con 100 elementi. In effetti, fa qualcosa di simile: definisce un nuovo nome di tipo TipoVettore, in modo tale che le variabili di questo tipo sono vettori di interi di 100 elementi.

In altre parole, dopo la definizione di sopra, se si fa una dichiarazione di tipo:

TipoVettore x, y;

Allora x e y sono definite come array di interi con cento elementi.

Questa regola generale di definizione di tipo si può riassumere come segue:

una definizione di tipo è simile alla definizione di una variabile, ma ha la parola chiave typedef davanti;

quello che sarebbe il nome della variabile diventa il nome del tipo;

le variabili definite di questo tipo sono del tipo che si otterebbe mettendo il nome della variabile al posto del tipo e togliendo typedef.

Seguendo queste regole, se è possibile dichiarare una variabile di un certo tipo, allora è anche possibile dichiarare un tipo. Dato che possiamo definire variabili di tipo vettori di interi di cento elementi, allora possiamo anche definire il tipo ``vettore di interi di cento elementi'', e questo si ottiene prendendo una dichiarazione di variabile, sostituendo al nome di variabile il nome che abbiamo deciso di usare per il nuovo tipo e mettendo typedef davanti.

Da questo momento TipoVettore rappresenta un nuovo nome di tipo. Quindi, possiamo definire delle variabili di questo tipo usando una semplice dichiarazione:

TipoVettore x, y;

Per capire come esattamente è definita la variabile x, bisogna considerare la dichiarazione del tipo, cancellare typedef e mettere x al posto del nome del tipo. Quello che si ottiene è:

typedef int TipoVettore[100];
        int           x[100];

Ossia x è un vettore di cento interi. Si noti che questo meccanismo è implicito nella dichiarazione della variabile x. In altre parole, TipoVettore x; è equivalente a int x[100];, per cui non è necessario (anzi, è un errore) scrivere esplicitamente la dichiarazione int x[100];. La variabile y è ovviamente definita nello stesso modo, per cui è anche essa un vettore di cento interi.

Il seguente programma tipovettore.c definisce il tipo vettore, dichiara una variabile di questo tipo, e la usa.

/*
  Definisce un tipo per un vettore.
*/

typedef int TipoVettore[100];

int main() {
  TipoVettore x;
  int i;

  for(i=0; i<=10; i++)
    x[i]=i*i;

  for(i=0; i<=10; i++)
    printf("%d ", x[i]);

  printf("\n");

  return 0;
}

Riassumendo: se ho una variabile fatta in un certo modo, posso definire un tipo corrispondente. Si possono poi definire variabili di quel tipo, che risultano definite in modo analogo alla variabile di partenza.


Questo meccanismo di definizione di nuovi tipi, come si è detto, è applicabile a tutti i tipi di variabili. Per esempio, dato che è possibile definire una variabile struttura, possiamo definire un tipo. Una variabile struttura si dichiara con:

struct NomeStruttura variabile;

Il tipo corrispondente si ottiene mettendo typedef davanti, e mettendo il nome che si vuole dare al tipo al posto del nome della variabile. Quello che si ottiene è:

typedef struct NomeStruttura TipoNomeStruttura;

Da questo momento in poi, TipoNomeStruttura è un nome di tipo. Possiamo quindi definire delle variabili di questo tipo. Queste variabili sono costruite nello stesso modo della variabile da cui siamo partiti, quindi sono delle strutture. Per essere più precisi, una dichiarazione come TipoNomeStruttura x;, applicando la regola, è equivalente a struct NomeStruttura x;.

Il programma tipostruttura.c definisce un tipo per delle strutture usate per memorizzare i dati di un lotto di articoli, e che è in particolare composta dal peso degli articoli e dalla loro quantità. Viene dichiarata una variabile di tipo struttura, e usata.

/*
  Definisce un tipo per una struttura.
*/

struct Lotto {
  float peso;
  int quantita;
};

typedef struct Lotto TipoLotto;

int main () {
  TipoLotto x;

  x.peso=1.2;
  x.quantita=10;

  printf("Peso=%f quantita'=%d\n", x.peso, x.quantita);

  return 0;
}



Questo ultimo esempio riguarda i puntatori. Dato che possiamo definire delle variabili che sono puntatori, possiamo definire un tipo. Consideriamo il caso delle di una struttura definita per rappresentare i dati di un lotto di merce. Le sue componenti sono: il peso degli articoli, e poi la quantità di articoli.

struct Lotto {
  float peso;
  int quantita;
};

Possiamo definire una variabile struttura, come segue:

struct Lotto x;

Possiamo quindi definire un tipo struttura usando la solita regola:

typedef struct Lotto TipoLotto;

Dato che TipoLotto è un tipo equivalente a una struttura, possiamo definire variabili come strutture dichiarandole come TipoLotto x. Possiamo però anche dichiarare puntatori a struttura come:

TipoLotto *p;

Ora possiamo applicare ancora la regola, e definire un tipo per i puntatori a struttura, mettendo typedef, e poi sostituendo a p il nome che vogliamo dare al tipo.

typedef TipoLotto * TipoPuntLotto;

Queste due definizioni di tipo, insieme, definiscono il tipo TipoPuntLotto come il tipo delle variabili puntatore alla struttura Lotto. In altre parole, quando si definisce una variabile come TipoPuntLotto p questo è un puntatore a una struttura Lotto.

Il seguente programma tipopuntatore.c è un esempio di uso di queste definizioni.

/*
  Definisce un tipo per un puntatore a strutture.
*/

struct Lotto {
  float peso;
  int quantita;
};

typedef struct Lotto TipoLotto;
typedef TipoLotto * TipoPuntLotto;

int main () {
  TipoLotto x;
  TipoPuntLotto p;

  p=&x;

  p->peso=1.2;
  p->quantita=10;

  printf("Peso=%f quantita'=%d\n", x.peso, x.quantita);

  return 0;
}


Un modo alternativo di definire questo tipo si ottiene partendo dalla considerazione che una variabile puntatore a struttura si dichiara come:

struct Lotto *p;

Per cui si può definire un tipo cosí:

typedef struct Lotto *TipoPuntLotto;