prof. Nunzio Brugaletta | Programmazione e linguaggio C |
Negli esempi trattati fino a questo punto tutte le variabili sono state dichiarate di tipo int. È bene però chiarire che esistono anche altri tipi di dichiarazione delle variabili in modo che, le stesse, possano contenere valori di natura diversa. D'altra parte ciò è facilmente intuibile: basta pensare alle limitazioni dettate appunto dal tipo int. In realtà i vari linguaggi di programmazione permettono di definire le variabili in diversi modi; ciò in relazione al tipo di dato da contenere e alle esigenze specifiche del tipo di problemi cui si rivolge il linguaggio stesso.
Nel linguaggio C esistono cinque tipi di dati primari (o tipi elementari): carattere, intero, reale, doppia precisione e indefinito. Le parole chiavi utilizzate per dichiarare variabili di questi tipi sono: char, int, float, double e void. La dimensione del dato che può essere conservato nella variabile dipende dallo spazio riservato in memoria per ogni tipo di dichiarazione e dalla modalità di conservazione.
Per quanto riguarda il tipo void (tipo indefinito), si tratterà di ciò in un secondo tempo. Per il momento l'attenzione sarà rivolta agli altri tipi.
I tipi di dati primari, eccetto il tipo void, ammettono dei modificatori di tipo. Tali modificatori (signed, unsigned, long, short) sono impiegati per adattare con maggiore precisione i tipi di dati fondamentali alle esigenze del programmatore.
Per conoscere occupazione e limiti dei tipi elementari, le implementazioni dei compilatori rendono disponibili un insieme di costanti predefinite che possono essere visualizzate in modo semplice:
#include <stdio.h> #include <limits.h> #include <float.h> main(){ printf("INTERI dim. %d\n",sizeof(int)); printf("minimo %d ",INT_MIN); printf("massimo %d\n",INT_MAX); printf("\nFLOAT dim. %d\n",sizeof(float)); printf("Cifre di precisione %d\n",FLT_DIG); printf("minimo esp. %d ",FLT_MIN_10_EXP); printf("massimo esp. %d\n",FLT_MAX_10_EXP); printf("\nDOUBLE dim. %d\n",sizeof(double)); printf("Cifre di precisione %d\n",DBL_DIG); printf("minimo esp. %d ",DBL_MIN_10_EXP); printf("massimo esp. %d\n",DBL_MAX_10_EXP); printf("\nLONG DOUBLE dim. %d\n",sizeof(long double)); printf("Cifre di precisione %d\n",LDBL_DIG); printf("minimo esp. %d ",LDBL_MIN_10_EXP); printf("massimo esp. %d\n",LDBL_MAX_10_EXP); }
L'esecuzione del programma, nel computer su cui sono state effettuate le prove dei programmi riportati in questi appunti, e con la versione di compilatore installata, produce questi risultati:
INTERI dim. 4 minimo -2147483648 massimo 2147483647 FLOAT dim. 4 Cifre di precisione 6 minimo esp. -37 massimo esp. 38 DOUBLE dim. 8 Cifre di precisione 15 minimo esp. -307 massimo esp. 308 LONG DOUBLE dim. 12 Cifre di precisione 18 minimo esp. -4931 massimo esp. 4932
Il programma mostra l'occupazione, in byte, di ogni variabile dichiarata di quel tipo, i limiti e, nel caso delle rappresentazioni in virgola mobile (float, double e long double), le cifre di precisione.
I tipi signed (char, int, long) conservano in memoria i dati utilizzando il metodo del complemento a 2
Il tipo float e il tipo double sono rappresentazioni floating-point: vengono comunemente indicati, rispettivamente, come numeri a singola precisione e a doppia precisione
Il tipo char viene utilizzato sia per conservare piccoli numeri che per conservare il set di caratteri, cioè dati apparentemente completamente diversi fra di loro dal punto di vista della elaborazione. La cosa è meno strana di quello che può sembrare a prima vista, basta riflettere sulla circostanza che, anche se si tratta di caratteri, la conservazione in memoria avviene associando ad ogni carattere una configurazione binaria e, quindi, un numero. Si può allora considerare la stessa configurazione come numero o come carattere corrispondente a quella configurazione binaria: la configurazione 0100.0001 (secondo la codifica ASCII) può essere il numero 65 come anche il carattere ‘A’. Tutto ciò può tornare utile per certi tipi di elaborazione sui caratteri.
Per ogni tipo è prevista dal C una stringa di controllo per l'output formattato della printf (per il tipo int, come già utilizzato, tale stringa è %d): per la conversione del tipo char la stringa %c, per quella di tipo float o double la stringa %f, %l sta per long e %u per unsigned, la stringa %e fa in modo che il valore della variabile mandata in output sia visualizzato con il formato esponenziale.
Nelle assegnazioni è spesso necessario specificare meglio il valore da assegnare:
... long a; double b; char c; ... a = 12L; b = 15.0; c = ‘A’;
Il valore 12 andrebbe pure in una variabile di tipo int, il suffisso L fa in modo che venga espanso in un long.
Nelle assegnazioni ai tipi in virgola mobile è necessario specificare sempre la parte decimale anche quando, come nel caso dell'assegnazione alla variabile b, non sarebbe indispensabile.
Nelle assegnazioni alle variabili di tipo char il carattere da assegnare deve essere racchiuso fra apici.
Viene proposto, adesso, un programma che trasforma un carattere minuscolo nella sua rappresentazione maiuscola. Le righe più significative sono commentate da etichette numeriche cui si farà riferimento poi per alcune osservazioni:
/* Conversione di un carattere da minuscolo a maiuscolo Vale per la codifica ASCII */ #include <stdio.h> #define SCARTO 32 /*1*/ main(){ char min,mai; printf("\n Conversione minuscolo-maiuscolo"); printf("\n Introduci un carattere minuscolo"); scanf("%c",&min); /*2*/ if (min>=97 && min<=122) { /*3*/ mai = min-SCARTO; /*4*/ printf("\n Rappresentazione maiuscola %c",mai); /*5*/ printf("\n Codice ASCII %d",mai); /*6*/ }else printf("\n Carattere non convertibile"); }
Nella riga con etichetta 1 è definita la costante SCARTO. Il valore 32 dipende dal fatto che, nel codice ASCII, tale è la distanza fra le maiuscole e le minuscole (es. ‘A’ ha codice 65, ‘a’ ha codice 97).
Nella riga con etichetta 2 si effettua l’input del carattere da elaborare. Si noti l’uso di %c per indicare che si tratta appunto di un carattere.
Nella riga con etichetta 3 si controlla, utilizzando la sua rappresentazione numerica, se il carattere immesso rientra nei limiti della codifica ASCII delle lettere minuscole. Le lettere minuscole, in ASCII, hanno codice compreso fra 97 (la lettera minuscola a) e 122 (la lettera minuscola z). Il confronto poteva anche essere fatto sulla rappresentazione alfanumerica:
if (min>=’a’ && min<=’z’)
Nella riga con etichetta 4 si effettua in pratica la trasformazione in maiuscolo. Al codice numerico associato al carattere viene sottratto il valore 32. In questo caso è utilizzato il codice numerico del carattere. Si noti che in questo contesto ha senso assegnare ad un char il risultato di una sottrazione (operazione numerica).
Nella riga con etichetta 5 si effettua l’output di mai inteso come carattere (è usato %c), laddove nella riga 6 si effettua l’output del suo codice numerico (è usato %d).
Le direttive di conversione possono avere varianti che specificano l'ampiezza dei campi, il numero di cifre decimali e un indicatore per l'allineamento del margine sinistro.
Un intero posto fra il segno di percentuale e il carattere di conversione indica l'ampiezza minima del campo (vengono aggiunti spazi per assicurare che questa ampiezza sia garantita, se, invece degli spazi si voglio tanti zeri, basta aggiungere uno zero prima dello specificatore di ampiezza). La direttiva %05d, per esempio, usa zeri come caratteri riempitivi in modo da portare la lunghezza totale a cinque caratteri. Per specificare il numero di cifre decimali di un numero in virgola mobile, si scrive, dopo lo specificatore di ampiezza, un punto seguito dal numero di cifre che si vuole siano stampate. La direttiva %10.4f, per esempio, stampa un numero di non meno di 10 cifre con 4 cifre dopo la virgola. Si può inoltre fare in modo che la stampa sia allineata a sinistra (per default lo è a destra) ponendo un segno meno: %-10.2f.
http://ennebi.solira.org | ennebi@solira.org |