La funzione scanf() permette di gestire l'input l'input da tastiera in modo più flessibile rispetto alla funzione getchar(). Infatti, mentre con quest'ultima funzione potevamo passare al programma solo dei caratteri, con la funzione scanf() è possibile passare al programma un dato appartenente ad uno qualsiasi dei quattro tipi fondamentali; e non solo.
La dichiarazione della funzione si trova in stdio.h; il suo prototipo è
int scanf("stringa di formato", ...);
La dichiarazione è molto simile a quella adottata per printf(): nella stringa di formato compaiono gli specificatori di formato che indicano al programma come effettuare la conversione dei caratteri inseriti nel buffer di input. Come nel caso di getchar(), anche scanf() fa uso del buffer per gestire l'input dal canale di input standard, ovvero stdin (-> dobbiamo premere il tasto ENTER per poter passare al programma il valore scritto sulla tastiera).
Dopo la stringa di formato non compaiono i nomi delle variabili ma i corrispondenti indirizzi, ovvero i puntatori a tali variabili.
Come mai compaiono i puntatori (ovvero gli indirizzi) e non, come in printf(), solo i nomi delle variabili ?
Facciamo un esempio: supponiamo di voler leggere un float dalla tastiera.
float numero;
float altro_numero = 0.;
printf("inserisci un numero decimale :");
scanf("%f", & numero ); // supponiamo che l'utente inserisca 3.5 e poi schiacci invio
altro_numero = numero + 4.; // ora altro_numero vale 7.5
ATTENZIONE: per la lettura dei double usare lo specificatore %lf, non %f
Qual è il significato dello specificatore di formato ? Per capirlo dobbiamo ricordarci una cosa: il buffer di input è fatto da CARATTERI !!
Supponiamo che all'utente sia stato richiesto di inserire un numero intero:
int intero=0;
printf("inserisci un numero intero");
scanf("%d",& intero); // a questo punto il buffer viene riempito dall'utente
Quando il programma va a leggere dal buffer, tenta di interpretare quei caratteri come se fossero quelli che compongono un numero intero; nel caso specifico, la sequenza di caratteri 12345 viene convertita nel numero intero 12345
Una cosa simile succede se tentiamo di inserire un double
double numero=0.0;
printf("inserisci un numero decimale in doppia precisione ");
scanf("%lf",& numero); // a questo punto il buffer viene riempito dall'utente
La sequenza di caratteri è la seguente: 34, poi c'è il punto, e poi 2544. Il programma interpreta i due raggruppamenti di cifre separati dal punto come la parte intera e quella decimale di un numero decimale. Quindi ciò che sta nel buffer di imput viene preso e convertito nel numero 34.2544.
Che cosa succede se l'utente sbaglia ?
int numero_intero;
printf("inserisci un numero intero");
scanf("%d", & numero_intero);
Supponiamo che l'utente inserisca
Il punto decimale non si trova all'interno di un numero di tipo intero, e quindi le cifre che concorrono a formare il numero intero sono solo 3 e 4. Di conseguenza il valore della variabile numero_intero, dopo l'esecuzione di scanf() sarà 34. Possiamo interpretare questo come un "cast", ovvero un valore di tipo double che, essendo stato inserito in un int, ha perso la parte decimale ?
Non proprio. Nel buffer rimangono dei caratteri, che corrispondono alla parte decimale inserita prima. Non abbiamo perciò perso la parte decimale; semplicemente non siamo riusciti a "prenderla".
Morale: è vero che con scanf() possiamo passare dei valori di tipo arbitrario, ma dobbiamo comunque fare attenzione nel momento in cui passiamo tali valori al programma. Infatti, nel caso appena considerato, i caratteri .2544 rimangono a disposizione per altre funzioni che dovessero accedere al buffer (e quindi c'è la possibilità che chiamate a getchar() o a scanf() vengano saltate).
DA EVITARE:
attenzione, mai fare una cosa di questo tipo:
int valore;
scanf("inserisci il valore %d",&
valore);
Se scrivete un'istruzione di questo tipo e volete passare il valore 32 allora, quando la funzione scanf() aspetta che voi inseriate l'input, dovete scrivere
inserisci il valore 32
in quanto deve esserci una esatta corrispondenza tra i caratteri della stringa di scanf() e quelli inseriti dall'utente.
Se viceversa inserite solo 32, la variabile valore non viene inizializzata in modo corretto.
E' meglio quindi usare due istruzioni:
int valore
printf("inserisci il valore :");
scanf("%d",& valore
);