scanf (abbreviazione dell'inglese scan formatted) è una funzione che viene implementata in diversi linguaggi di programmazione. Viene utilizzata per l'inserimento di dati formattati (caratteri e numeri). Da essa derivano inoltre altre funzioni, tra le cui più citate fscanf e sscanf.

Ha origine dal linguaggio C dove è inclusa nella libreria stdio.h, ma queste funzioni sono precedenti a C e possiedono altri nomi, come ad esempio readf in ALGOL 68.

Storia La funzione è stata implementata da Mike Lesk, assieme al resto della libreria cui appartiene, la quale è stata poi ufficialmente resa parte di Unix dalla versione 7 (1979).

Utilizzo La funzione ha il seguente prototipo:int scanf(const char *format, ...);

Dal C99 e a seguire è stato introdotto restrict con i definitori (vedi anche restrict):int scanf(const char * restrict format, ...);La funzione legge dei caratteri dal canale standard di input (stdin), solitamente la tastiera, li converte secondo le specifiche di formattazione fornite dall'argomento format e memorizza i valori ottenuti negli argomenti seguenti in concordanza del tipo di dato richiesto. La funzione si ferma quando esaurisce la propria stringa di formattazione o quando alcuni dati in ingresso non soddisfano le specifiche di conversione. Il valore restituito è un numero intero che indica quanti valori sono stati estratti correttamente: negativo se si è verificato un errore, positivo se c'è stata una lettura e in particolare 0 (zero) se non è stata fatta alcuna assegnazione perché il primo carattere letto non è conforme alla prima specifica della stringa di formato.

Similarmente alla funzione printf, il ... sta ad indicare che si tratti di una funzione variadica (che può assumere un numero variabile di parametri).

Sintassi La sintassi generica da seguire per chiamare la funzione è:scanf (tipo, &arg);Da notare come si debba fornire l'indirizzo di memoria di arg (tramite l'operatore unario &) in cui verranno memorizzati i dati. A ciò fa però eccezione il definitore %s perché, in quanto array di caratteri, è già un puntatore: nella dichiarazione di un array infatti, viene memorizzato l'indirizzo di memoria del primo elemento che lo compone, pertanto, dato ad esempio un vettore strvet, le due espressioni *strvet e strvet sono equivalenti.

Qui di seguito è riportato un esempio in C

#include <stdio.h> /* Libreria standard per l'I/O */

int main() { int n; printf("Inserisci il valore di N: "); scanf("%d", &n); printf("N al quadrato è uguale a %d\n", n*n); return 0;

Nell'esempio proposto viene richiesto all'utente un numero intero e viene calcolato il quadrato di tale numero.

La funzione scanf ha lo scopo di rilevare quanto immesso dall'utente tramite la tastiera, convertirlo in un numero intero e memorizzarne il risultato nella variabile n.

La lettura si blocca appena incontra un carattere non conforme a quello definito dal definitore di formato.

Quindi, in questo esempio, fornendo un input del tipo 435 9483 9342 oppure 435ute, si otterrebbe in entrambi i casi 435*435 come output (a schermo), lasciando nel buffer di memoria il resto della stringa, che potrebbe essere letta da un'altra funzione o dalla stessa, se inserita in un ciclo apposito. Bisogna pertanto prestare attenzione a questo fattore perché potrebbe creare incongruenze con le altre funzioni che accederebbero successivamente al buffer.

L'argomento format L'argomento format è una stringa che specifica l'interpretazione dell'input e può contenere una o più di:

Spazi vuoti: vuoto, tabulazioni \t o nuova riga \n e \r e anche le rispettive traduzioni numeriche ASCII, compreso lo \0 (zero di fine stringa). Un carattere di spazio vuoto comporta che n legga, ma non memorizzi, tutti i caratteri di spazio vuoti consecutivi nell'input fino al successivo carattere diverso da uno spazio vuoto; Caratteri diversi da uno spazio vuoto, ad eccezione del segno di percentuale (%). Un carattere diverso da uno spazio vuoto comporta che scanf legga, ma non memorizzi, un carattere diverso da uno spazio vuoto corrispondente. Se il carattere successivo nel flusso di input non corrisponde, scanf termina; Specifiche di formato introdotte dal segno di percentuale (%). Una specifica di formato determina la lettura e la conversione dei caratteri nell'input in un valore di un tipo specificato. Il valore viene assegnato a un argomento nell'elenco degli argomenti.

I definitori di formato (format specifier) Una specifica di formato presenta la forma seguente: %[*][ampiezza][{h|l|L}]tipo Come accade anche nella funzione printf, gli argomenti tra parentesi possono essere omessi a seconda delle esigenze.

La ampiezza è un numero intero positivo che controlla il numero massimo di caratteri da leggere da stdin per quella specifica di formato.

Il carattere di soppressione dell'assegnazione (*) serve a leggere un valore dall'input e a ignorarlo, senza pertanto assegnarlo a una variabile.

Nella tabella seguente sono mostrati i tipi di dato da poter inserire: DescrizionecCarattere singolo ASCII (non solo quelli stampabili)iNumero interodNumero intero decimaleuNumero intero decimale senza segnooNumero intero ottale senza segnoxNumero intero esadecimale senza segnofNumero reale a singola precisione (float)aNumero reale (float) in notazione esadecimale (presente dal C99)eNumero reale in virgola mobile in notazione scientifica [-]d.ddde±ddgNumero reale in notazione estesa (f) e in notazione scientifica (e)sStringa (array di caratteri e, poiché già puntatore, nella scanf non ha bisogno di '&')pIndirizzo di memoria (puntatore)[set]Lista di caratteri (si blocca appena incontra un carattere non presente nella lista)nnessun input letto dal bufferlModificatore di lunghezza (long)LModificatore di lunghezza (long long)hModificatore di lunghezza (short)%Solo il carattere di percentuale Una differenza che si ritrova con la funzione printf sta nell'utilizzo dei definitori %i, %d, %u, %o, e %x, in particolare per %i e %d perché sono sinonimi per l'output, ma diversi se usati per l'input. Bisogna pertanto fare attenzione al tipo di numero intero fornito. Mentre %i è in grado di riconoscere una base decimale da una ottale e da una esadecimale (rispettivamente tramite l'uso del prefisso 0 e 0x), in tutti gli altri casi si sta definendo a prescindere una base specifica e un eventuale segno.

Il definitore %l (long, cioè lunghezza doppia) viene sempre seguito da altri definitori per indicare che lo spazio di memoria necessario da allocare (fa unica eccezione p perché, in quanto già indirizzo di memoria, non ha bisogno di una ulteriore specifica di formato). Pertanto, ad esempio, %lf indicherà un numero reale a doppia precisione (double), mentre %lu indicherà un numero intero decimale senza segno a 64 bit (invece degli usuali 32 bit).

Il definitore %h (short, cioè mezza lunghezza) si antepone solo per i definitori di numeri interi. Pertanto, ad esempio, %hi indicherà un numero intero a 16 bit.

Il definitore %L si antepone ai numeri reali in virgola mobile (es. %Lf) per indicare i formati long double.

Il definitore %g ha la proprietà di poter leggere i numeri in virgola mobile sia del formato %f, che del formato %e. Proprietà che nella funzione printf si traduce nel poter restituire il formato che si presenta più corto tra i due.

Il definitore %n punta a un tipo di dato int, in cui viene memorizzato il numero di caratteri letti correttamente dallo stream o dal buffer fino a quel punto nella chiamata a scanf().

Il definitore %p ha la particolarità di dover puntare a un puntatore che è stato dichiarato, o per lo meno convertito, come void.

Per l'uso degli insiemi di caratteri ([]), si può complementarizzare tramite l'insieme di caratteri scelti: se il primo carattere nell'insieme è un accento circonflesso (^), l'effetto viene invertito e il campo di input viene letto fino al primo carattere che appartiene nel resto dell'insieme di caratteri (operando a tutti gli effetti l'operazione XOR).

Il definitore %% corrisponde al solo carattere di percentuale (%).

Valore restituito La funzione scanf() restituisce il numero (int) di campi che sono stati convertiti e assegnati correttamente. Il valore di ritorno non comprende il numero di campi che sono stati letti, ma non assegnati.

Il valore di ritorno è negativo, EOF (end of file), per un tentativo di lettura alla fine del file, se non è stata eseguita alcuna conversione. Un valore di ritorno 0 (zero) indica che non sono stati assegnati campi.

Condizioni di errore Se il tipo di argomento a cui deve essere assegnato è diverso dalla specifica di formato, possono verificarsi risultati imprevedibili. Ad esempio, la lettura di un valore a virgola mobile, ma l'assegnazione in una variabile di tipo int, non è corretta e avrebbe risultati imprevedibili.

Se ci sono più argomenti che specifiche di formato, gli argomenti supplementari vengono ignorati. I risultati non sono definiti se non vi sono argomenti sufficienti per le specifiche di formato.

Se la stringa di formato contiene una specifica di formato non valida e vengono utilizzate specifiche di formato posizionali, errno verrà impostato su EILSEQ.

Se vengono utilizzate specifiche di formato posizionale e non vi sono argomenti sufficienti, errno verrà impostato su EINVAL.

Se si verifica un errore di conversione, errno può essere impostato su ECONVERT.

Overflow aritmetico Durante la conversione da stringa a numero (come con atoi, atol e atof) vi è il problema per cui la funzione scanf non riesce a determinare un overflow aritmetico (allo stesso modo di un underflow aritmetico nel caso dei numeri in virgola mobile). Perciò viene sconsigliato l'uso di questi convertitori per qualsiasi software applicativo che richieda controlli stringenti sull'input.

Come alternativa si indicano le funzioni strtol e strtod, che effettuano dei controlli aggiuntivi sull'overflow/underflow.

L'applicativo per l'analisi statica del codice in Clang (Clang-Tidy) sconsiglia dall'uso di scanf.

Funzioni derivate

fscanf La funzione fscanf legge i dati di input da un file, piuttosto che utilizzare l'input standard. Il suo funzionamento è sostanzialmente uguale a quello della sua primitiva e il suo prototipo (in C/C++) è:int fscanf (FILE *file, const char *format, ...); // fino a C99 int fscanf (FILE *restrict file, const char *restrict format, ...); //dal C99

sscanf La funzione sscanf legge i dati di input da un buffer, piuttosto che utilizzare l'input standard, restituendo i valori che si possono leggere, e il suo prototipo (in C/C++) è:int sscanf (char *buffer, const char *format, ...); // fino a C99 int sscanf (char *restrict buffer, const char *restrict format, ...); //dal C99

Altre funzioni derivate Dal C11 sono state introdotte ulteriori funzioni: scanf_s, fscanf_s, sscanf_s.

Esempi d'uso #include <stdio.h> int main(void) { int i; float fp; char c, s; printf("Inserire un numero intero, un numero reale," " un carattere e una stringa: \n"); if (scanf("%d %f %c %s", &i, &fp, &c, s) != 4) printf("Non tutti i campi sono stati compilati\n"); else

printf("numero intero = %d\n", i); printf("numero reale = %f\n", fp); printf("carattere = %c\n", c); printf("stringa = %s\n",s);

}Se l'input è 27 5.4 t si, allora l'uotput sarà simile a:Inserire un numero intero, un numero reale, un carattere e una stringa: numero intero = 27 numero reale = 5.400000 carattere = t stringa = si

Uso dell'indicatore d'ampiezza #include <stdio.h> int main() { int i; float x, y; char name; printf ("Inserire due stringhe numeriche che contengano 8 caratteri" " ognuna e che abbiano entrambe un punto al centro:\n"); scanf("%2d %f %6f %[0123456789]", &i, &x, &y, name); printf("numero intero = %d\n", i); printf("primo numero reale = %f\n", x); printf("secondo numero reale = %f\n", y); printf("il resto della stringa = %s\n",name);