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);
|