Input con e senza buffer


In C, l'acquisizione di caratteri immessi mediante tastiera (ovvero tramite lo standard input) avviene in generale in questo modo (trattiamo il caso semplice dei caratteri, ma il ragionamento rimarrà valido anche per la gestione di tipi di dati più complessi):

char carattere;
carattere = funzione_di_input(parametri);

ovvero, tramite una generica funzione (qui chiamata funzione_di_input(), ma che potrebbe essere getche(), ad esempio) il valore del carattere digitato sulla tastiera viene assegnato alla variabile carattere, in modo tale che tale valore possa essere gestito dall'interno del programma.

In che modo il valore di tale carattere (ovvero, il suo codice ASCII), valore che viene generato dalla tastiera, cioè da un dispositivo esterno al programma, viene assegnato alla variabile, che è un elemento interno al programma ? Esistono due modalità per effettuare questa operazione, la modalità senza buffer e la modalità con buffer.

Prima di descriverle nel dettaglio, vediamo cosa si intende con buffer. Tale termine indica, in generale, un'area di memoria temporanea. Nel caso specifico, per buffer si intende un'area di memoria temporanea in cui vengono momentaneamente salvati i valori dei caratteri prima che questi ultimi siano passati al programma.


unbuffered input

Nel caso in cui l'input sia gestito in modalità senza buffer i valori dei caratteri vengono passati direttamente al programma non appena il tasto corrispondente viene premuto (questo è ad esempio il caso di getch() e getche()), ovvero il programma non si aspetta che l'utente prema un tasto speciale per far capire che è terminata l'immissione dei caratteri (tale tasto, di norma, è il tasto ENTER).
In questa modalità, quindi, nell'istante in cui l'utente preme un tasto il valore del carattere corrispondente viene passato alla variabile, dichiarata all'interno del programma, che è preposta alla memorizzazione di tale valore.

NOTA: le funzioni getche() e getch() sono disponibili all’interno della libreria del compilatore solo su sistemi windows. Per sistemi linux esistono degli analoghi (v. qui) ma non fanno parte della libreria standard. In seguito, quindi, faremo uso solamente di getchar()


buffered input

Nel caso in cui l'input venga gestito mediante un buffer, tutti i valori (=codice ASCII) dei caratteri inseriti mediante la tastiera (a prescindere da quanti la funzione inserita nel programma ne preveda) vengono salvati temporaneamente nel buffer e rimangono lì fino a quando l'utente non preme il tasto ENTER. A questo punto, dal buffer vengono prelevati tanti caratteri quanti la funzione richiamata all'interno del programma ne può accettare; ad esempio, se uso una funzione che prevede l'immissione di un solo carattere, dal buffer viene prelevato solo il primo carattere. Gli altri rimangono disponibili per successive chiamate alla funzione. Funzioni che appartengono a questa categoria sono getchar() e scanf().

NOTA: anche il codice ASCII corrispondente al tasto ENTER viene inserito nel buffer.




Facciamo un esempio: supponiamo di voler utilizzare una funzione che legga dalla tastiera due caratteri. Proviamo ad ottenere questo risultato usando due funzioni, una che gestisce l'input senza buffer, getche(), ed una che gestisce l'input con buffer, getchar().

Le istruzioni rilevanti saranno:

senza buffer

con buffer


int car1,car2;
printf("inserisci un carattere :");
car1 = getche();
printf("inserisci ancora un carattere :");
car2 = getche();


int car1,car2;
printf("inserisci un carattere :");
car1 = getchar();
printf("inserisci ancora un carattere :");
car2 = getchar();



Mentre nel primo caso, appena il tasto viene premuto, il valore del corrispondente carattere viene assegnato alla variabile car1 e quindi il controllo passa alla seconda istruzione printf(), nel secondo caso il valore del carattere premuto viene lasciato all'interno del buffer ed tale valore non viene utilizzato fino a quando l'utente non preme il tasto ENTER. In questo secondo caso, quindi, in totale nel buffer sono presenti i valori di due caratteri: quello del tasto premuto inizialmente e quello del tasto ENTER. Di conseguenza il valore del primo tasto viene passato alla prima chiamata a getchar(), e quindi viene memorizzato nella variabile car1, mentre il secondo valore rimane disponibile per la seconda chiamata a getchar(); perciò in questo caso il programma non si aspetta che l'utente inserisca un nuovo carattere da tastiera, in quanto ce ne era uno ancora disponibile nel buffer temporaneo.

Per evitare questo problema sono possibili diverse soluzioni, ad esempio:

Inserire più chiamate alla funzione getchar() ed ingnorare quelle che restituiscono il valore del carattere ENTER. Questa soluzione, però, prevede che il numero totale di caratteri inseriti sia noto a priori (per poter inserire un numero sufficiente di chiamate a getchar() per poter eliminare dal buffer i caratteri in eccesso eventualmente inseriti dall'utente per errore). In generale, però, con l’output buffed è possibile cancellare i caratteri inseriti per errore, quindi possiamo sempre assumere che, ogni volta che si passa il controllo all’utente, esso inserisca al massimo due caratteri (quello digitato + quello corrispondente al tasto ENTER).

Effettuare una chiamata alla funzione fflush(stdin), dichiarata in stdio.h, per ripulire il buffer e quindi evitare che dei caratteri indesiderati vi rimangano. Tale funzione va chiamata subito dopo la chiamata a getchar().


int car1,car2;
printf("inserisci un carattere :");
car1 = getchar();
fflush(stdin);
printf("inserisci ancora un carattere :");
car2 = getchar();
fflush(stdin);