Introduzione alle operazioni di I/O con formato e tipi primitivi Un programma C legge normalmente i dati su cui operare dallo standard input (stdin) e comunica con l esterno scrivendo dati sullo standard output (stdout) I dati sono visti come sequenze di caratteri (stream) organizzare in righe La libreria standard mette (fra l altro) a disposizione due funzioni per l I/O con formato (scanf e printf) e senza formato (getchar e putchar) scanf getchar printf putchar stream Testina di lettura Testina per la scrittura memoria STDIN STDOUT
scanf (<stringa-formato>, <sequenza-variabili>) La funzione scanf struttura i caratteri dello stdin in campi, separati da uno o più caratteri di separazione Un campo è composto da uno o più caratteri che non siano quelli di separazione Sono caratteri di separazione: lo spazio, newline, return, tab orizzontale e verticale Caso particolare ingresso di un carattere La funzione scanf legge i campi dallo stdin, li interpreta (converte) in base alla stringa di formato ed assegna i valori convertiti alle variabili i cui indirizzi sono forniti in <sequenza-variabili> La funzione termina quando: (i) esaurisce la stringa di formato o (ii) incontra un incongruenza fra input e specifica di formato Attenzione: non quando legge un carattere di andata a capo Ogni chiamata di scanf riprende riprende dal carattere immediatamente dopo quello convertito riga riga 1 5 \n 4 5. 5 \n campo int n; scanf( %d,&n); n 0000 0000 0000 1111 Ipotesi: interi occupano 2 byte
riga riga 1 5 \n 1 0 \n campo campo int n,m; scanf( %d%d,&n,&m); n 0000 0000 0000 1111 m 0000 0000 0000 1010 Ipotesi: interi occupano 2 byte E possibile inserire nella stringa di formato anche caratteri specifici che ci sia aspetta di trovare durante la lettura Esempio scanf( %d:%d,&n,&m); Due interi separati da un punto (.) 12:21 n=12, m=21
printf (<stringa-formato>, <altri-argomenti>) La <stringa-formato> descrive il formato dell output, mentre <altri-argomenti> è opzionale ed è composto dalle variabili che corrispondono alle singole specifiche di conversione indicate nella stringa Vedremo le funzionalità caso per caso Sono i tipi messi a disposizione direttamente dal linguaggio E possibile definire nuovi tipi sulla base dei primitivi Il tipo caratterizza una variabile in termini di Valori che la variabile può assumere Intervallo di valori Notazione per i valori (ex. 3.4e+12, 1U) Operazioni ammissibili sulle variabili Operatori Predicati (operatori relazionali) Ad ogni tipo corrispondono caratteri di conversione differenti (ex: %d -> intero, %c carattere )
char (caratteri) int (interi) float (reali, virgola mobile singola precisione) double (reali, virgola mobile doppia precisione) void ( nessun tipo, nessun valore ) E possibile modificare l ampiezza dei valori relativi al tipo mediante i qualificatori short e long, o le caratteristiche dei valori che una variabile di quel tipo può assumere mediante i qualificatori signed e unsigned Esempio: long double (reali, precisione estesa) Servono per valutare la relazione fra due valori x>y (x maggiore y) x>=y (x maggiore o uguale y) x<y (x minore di y) x<=y (x minore o uguale a y) x ==y (x è uguale ad y) x!=y (x è diverso da y) Valore restituito (0 indica falso, un valore diverso da 0 tipicamente 1 indica vero)
() da sinistra a destra * / % + - < <= > >= ==!= = da destra a sinistra 3 tipi: signed char unsigned char char, può corrispondere a signed char o unsigned char (dipende dal compilatore). Intervallo di valori interi corrispondenti al codice utilizzato per la codifica dei caratteri (tipicamente il codice ASCII) Occupano (normalmente) 1 byte. In questo caso [-128..127] per signed e [0..255] per unsigned Il file <limits.h> contiene le definizioni delle costanti CHAR_MAX, CHAR_MIN, UCHAR_MAX, SCHAR_MIN,SCHAR_MAX Esempi char c= a /*Assegna a c il codice di a, ossia 97 se ASCII*/ char c=97 /*Sconsigliato: non portabile*/ c= \n /*Assegna il codice di new line, non sono due caratteri*/ c= \\ backslash Specifica di conversione %c Operazioni: quelle fra interi (hanno sempre senso?)
Consideriamo il seguente frammento: char c= a ; printf( %c\n,c-32); Ipotizziamo l uso del codice ASCII per la codifica dei caratteri. Cosa viene stampato sul video? Risposta: A 3 Tipi unsigned short (oppure unsigned short int) unsigned (oppure unsigned int) unsigned long (o solo unsigned long in) Intervallo di valori [0 2 n -1], n numero di bit Il file <limits.h> contiene le definizioni delle costanti (il minimo è sempre 0) USHRT_MAX, UINT_MAX, ULONG_MAX Vincoli sizeof(long) sizeof(int) sizeof (short); sizeof(short) 2 byte sizeof(long) 4 byte Il devcpp usa 2 e 4 byte unsigned short [0..65 535] unsigned, unsigned long [0 4 294 967 295] Operatori +,- (priorità bassa, associano da sinistra a destra) %,* (priorità alta, associano da sinistra a destra)
3 tipi short (oppure short int,signed short, signed short int) int (oppure signed int, signed) long (oppure long int, signed long, signed long int) Intervallo di valori [-2 n-1 2 n-1-1], n numero di bit Il file <limits.h> contiene le definizioni delle costanti (il minimo è sempre 0) SHRT_MIN, SHRT_MAX, INT_MIN,INT_MAX, LONG_MIN,LONG_MAX Il devpp usa 2 e 4 byte short [-32 768 32 767] int,long [-2 147 483 648 2 147 483 647] Operatori +,- (priorità bassa, associano da sinistra a destra) %, *(priorità alta, associano da sinistra a destra) x=5+3 x=5+3*3 (=14: 5+9) x=(5+3)*3 (=24: 8*3) x=5+3*3/2 (=9: prima 3*3, poi 9/2=4, poi 5+4) x=p*r%q+w/x-y (ordine: *,%,/,+,-)
Formati Decimale: 12 oppure -12 Esedecimale: 0xFF Ottale: 023 12L, 56l (l,l=costante tipo long int) 45u (u,u=costante unsigned) 12ul (ul=costante unsigned long) Specifiche di conversione in output %d notazione decimale (base 10) %i idem %u decimale priva di segno %o base 8, senza segno e senza zero iniziale %x base 16, senza segno, senza 0x iniziale, lettere minuscole (a..f) %X base 16, senza segno, senza 0x iniziale, lettere maiuscole (A F) Tipo int unsigned int (decimale) unsigned int (ottale) unsigned int (esadecimale) short %hd %hi %hu %ho %hx %hx int %d %i %u %o %x %X long %ld %li %lu %lo %lx %lx Tipo short int long int %hd %d %ld unsigned int (decimale) %hu %u %lu unsigned int (ottale) %ho %o %lo unsigned int (esadecimale) %hx %hx %x %X %lx %lx Con la specifica %i (intero) il numero può essere in notazione base 10,8,16
#include <stdio.h> main(){ int a,b; a=255; b=0xff; printf("%x\t%d",a,b); return 0; } FF 255 Esercizio: determinare se devcpp usa signed o unsigend per il tipo char int y=98; char c='a',d=7; printf("%d %c %d %c %c",c,c,y,y,d); (codice 97=codice ASCII di a ) 97 a 98 b output più il beep!
int i,j; char c; printf("immetti 2 interi: \n"); scanf("%d%c%d",&i,&c,&j); printf("%d %d %d",i,c,j); ASCII di a 97 ASCII di spazio 32 Immetti 2 interi: 12a20 12 97 20 Immetti 2 interi: 10 20 10 32 20 int i=-1; printf("%x %hd %d %hu %u",i,i,i,i,i); Risposta FFFFFFFF -1-1 65535 4294967295 2 byte per short e 4 byte per int %X = base 16 %hd = short %hu = unsigned short %u = insigned Perché: 2 16-1= 65535 2 32-1= 4294967295
Sono rappresentati in virgola mobile (floating point) 3 tipi Tipo byte Cifre significative Min esp. Max esp. float 4 6-37 38 double 8 15-307 308 long double 12 18-4931 4932 Caratteristiche nel file <float.h> Le funzioni della libreria standard definite in <math.h> operano in double Operatori aritmetici: +,-,/,* Notazione con punto decimale o notazione esponenziale Esempio 123.45 0.0012.0012 34.5E+20 34.5e+20 43e-13 (double) 27.0f 2.7E1f (float) %f notazione virgola fissa (float o double) %e %E notazione esponenziale (float o double) %g %G fissa o esponenziale (float double) Usa %e usa %e o %E se l esponente è minore di 4 o maggiore o uguale alla precisione specificata (per default 6 cifre), altrimenti usa %f. Gli zeri superflui non sono stampati Esempio stampa di x=0 %f 0.000000 %e 0.000000e+000 %E 0.000000E+000 %g 0 Il prefisso L viene usato in output per i numeri long double (%Lf) In input il suffisso l indica il tipo double Esempio %lf, %le, %le
float double long double printf %f,%e,%g %e,%f,%g %Le,%Lf,%Lg scanf %f,%e,%g %le,%lf,%lg %Le,%Lf,%Lg E possibile specificare l ampiezza del campo ed il numero di cifre di precisione Esempio %9.3f campo da 9 cifre complessive (il segno + occupa un posto) di cui 3 dopo la virgola %-9.3f campo da 9 cifre con allineamento a sinistra, di cui 3 dopo la virgola Esempio printf( %9.3f -9.3f,1234.5,1234.5) Output: 1234.500 1234.500
Quando un operatore ha operandi di tipo diverso, questi sono convertiti implicitamente e temporaneamente in un tipo comune prima della valutazione (prima della valutazione si ottiene cioè un espressione con tipi omogenei) Esempio int i; double r,f; i=2;f=3.5; r=i+f La valutazione avviene nei seguenti passi La variabile i viene temporaneamente convertita nel tipo double (promotion) Viene valutata la somma Il risultato è assegnato ad r Le regole di conversione seguono il criterio di promuovere i tipi inferiori in tipi superiori long double double float unsigned long int long int unsigned int int short char Osservazioni: La conversione da signed ad unsigned (es. long int -> signed int) può produrre risultati non aspettati -1>1U (11.1) > (00.1) La conversione da int a float può causare perdita di precisione Il tipo float ha 6 cifre significative
Nell istruzione di assegnamento x=y il tipo di x può essere inferiore rispetto ad y Il risultato dell espressione a destra viene sempre convertito in quello del tipo a sinistra Esempio double x=2.3, y=4.5; int i; i=x+y; /*i = 6, troncamento della parte frazionaria*/ Si ha conversione implicita anche nel passaggio dei parametri a funzione e per il valore restituito (lo vedremo dopo)!" # In qualunque espressione è possibile forzare la conversione al tipo <tipo> usando l operatore di cast Sintassi: (<tipo>) <espressione> Esempio: int somma, n; float media; /*somma = 9, n=2*/ media = somma/n; /*media = 4*/ media = (float)somma/n; /*media = 4.5*/