Newsgroup: it.comp.lang.c
Titolo: Lo strano comportamento di getchar()

Come mai se metto una sequenza di getchar(), magari in un ciclo, ne vengono
saltate alcune?
Questa č una funzione che sembra igorare la getchar la prima volta(nel senso
che č come se accettasse automaticamente una risposta...):
void stampa_tutti(STUDENTE *start)
{
 putchar('\n');
 while(start!=NULL){
    stampa(*start); /* passata la struttura attuale, puntata da start */
    start=start->next;
    puts("\nPremere invio per continuare\n");
    getchar();
 }
}
STUDENTE č una stuttura. Accetta il punatore alla prima struttura e la
stampa richiamando stampa(), poi passa alla successiva struttura della
lista, puntata dal campo next della struttura...
Le due istruzioni alla fine servono per non far stampare tutto di fila. Il
problema e' che, per piů di un record nella lista, viene stampato il primo,
con il messaggio, ma viene stampato anche il secondo, con il messaggio. Da
qui in poi funziona come dovrebbe, fermandosi ad ogni stampa.
Ovviamente, se aggiongo una getchar() dopo la putchar all'inizio, funziona
normalmente. Come mai?
Sicuramente c'entra la bufferizzazione di stdin, come funziona?
Grazie
Marco Iannaccone

 saltate alcune?
Devi svuotare il buffer di lettura (c'è rimasto per lo meno il '\n') tra
una chiamata e l'altra:
while ( getchar() != '\n' );
EMG

Ma come mai dopo la prima volta funziona bene?
Non dovrebbe rimanere ogni volta '\n'?
Inoltre, come mai sia sotto Linux che sotto DOS il comportamento è
esattamente lo stessa, nonostante nel primo '\n' corrisponda a LF mentre nel
secondo a CR+LF?
Grazie
Marco Iannaccone

Ho appena provato il suggerimento, ma c'è un problema:
solo la prima volta il risultato è quello aspettato, dalla seconda (dalla
seconda il poi andava bene) inizia ad aspettare due invio...
Marco Iannaccone

Marco Iannaccone wrote:

  Perche' anche sotto dos la getchar interpreta '\n' come un byte solo codice
asci 10 come succede sotto "un vero sistema operativo",cosa che non accade
quando '\n' viene posto in un file.

Marco Iannaccone wrote:

 Per evitare il problema devi svuotare il buffer di input : fflush(stdin)
dopo la getchar.

 secondo a CR+LF?
Questo non ha importanza dato che per il C '\n' corrisponde comunque ad
un solo carattere indipendentemente da come č implementato nel sistema
su cui gira.
EMG

 seconda il poi andava bene) inizia ad aspettare due invio...
Devo assolutamente rivedere il codice. Ma semplificalo al massimo che
serve molto anche a te.
EMG

dopo la getchar.
NOOO!!! ma quante volte bisogna ripeterlo ???
fflush() e' definito solo per gli stream di output !!!
per cortesia, prestate un po' d'attenzione a quanto viene detto sul
ng.
Andrea Laforgia (andrea_...@XXXbigfoot.com)
------------------------------------------------
Il mio indirizzo di posta elettronica è inattivo 
per il momento.

 dopo la getchar.
fflush() è definita solo per output streams.
EMG

Cioč scrivendo '\n' in un file viene scritto CR(13)+LF(10) sotto DOS. E in
lettura? Una volta trovato CR, che succede con LF?
Comunque, in C, un file vero e proprio e la console o la tastiera non
dovrebbero essere trattati allo stesso modo?
Marco Iannaccone

Ecco una semplificazione del codice. In pratica nella main c'era un menu,
usato per chiamare varie funzioni:
#include<stdio.h>
void funzione(void);
int main(void)
{
int c;
 /* Nel mio programma questo era un menu che richaimava la
  * funzione appropriata */
 printf("Inserire un numero per entrare nella funzione: ");
 scanf("%d",&c);
 funzione();
return 0;
}
void funzione(void)
{
int c=10;
 while(c){
     printf("STAMPA\n"); /* qui si stampava una struttura */
     /* qui serviva a chidere conferma */
     printf("Premere invio per continuare\n");
     getchar();
     c--; /* serve solo a far avviere il ciclo ad una fine */
 }
}
Dopo aver chiamato la funzione (la scanf serve ad accettare la "scelta")
viene stampato due volte il messaggio in funzione(). Se poi da questa premo
solo invio non ho problemi, dato che la domanda mi viene posta regolarmente,
fermandosi, se perň inserisco una o piů lettere, rimandendo queste nel
buffer, vengono lette dalla successiva getchar( in pratica inserendo 4 e
invio, 4 viene restituito e 10 rimane nel buffer, no?)...
Come devo fare per svuotare il buffer di stdin prima di ogni getchar(), per
essere sicuri che venga effettivamente letto un carattere da tastiera e non
uno nel buffer?
Grazie
Marco Iannaccone

 ng.
In questo NG  si parla di standard c, o di standard c djgpp?
Non e' categoricamente accettato da tutti i compilatori c, che la funzione
fflush() non possa svuotare il buffer di uno stream  di input, vedere borland
c++(almeno fino alla versione 2.00,quella da me usata),Visual c++(Ver 5.0).
Ecco uno spaccato della pagina dell'help di visual c++ 5.0 riguardo fflush():
fflush
Flushes a stream.
int fflush( FILE *stream );
The fflush function flushes a stream.
If the file associated with stream is open for output,
fflush writes to that file the contents of the buffer associated with the
stream.
---->If the stream is open for input, fflush clears the contents of the
buffer. <-------
fflush negates the effect of any prior call to ungetc against stream.
Also, fflush(NULL) flushes all streams opened for output.
The stream remains open after the call. fflush has no effect on an unbuffered
stream.
Buffers are normally maintained by the operating system,
which determines the optimal time to write the data automatically to disk:
when a buffer is full, when a stream is closed,
or when a program terminates normally without closing the stream.
The commit-to-disk feature of the run-time library lets you ensure
that critical data is written directly to disk rather than to the
operating-system buffers. Without rewriting an existing program,
you can enable this feature by linking the program's object files
with COMMODE.OBJ. In the resulting executable file, calls to _flushall write
the contents of all buffers to disk.
Only _flushall and fflush are affected by COMMODE.OBJ.
Example
/* FFLUSH.C */
#include <stdio.h>
#include <conio.h>
void main( void )
{
   int integer;
   char string[81];
   /* Read each word as a string. */
   printf( "Enter a sentence of four words with scanf: " );
   for( integer = 0; integer < 4; integer++ )
   {
      scanf( "%s", string );
      printf( "%s\n", string );
   }
   /* You must flush the input buffer before using gets. */
------>   fflush( stdin );<---------
   printf( "Enter the same sentence with gets: " );
   gets( string );
   printf( "%s\n", string );
}
Output
Enter a sentence of four words with scanf: This is a test
This
is
a
test
Enter the same sentence with gets: This is a test
This is a test
Stream I/O Routines
Ivan Molella

 dovrebbero essere trattati allo stesso modo?
Infatti č cosě.
EMG

 }
Questo perché tra una lettura e l'altra con getchar() il buffer è già
vuoto.
EMG

c++(almeno fino alla versione 2.00,quella da me usata),Visual c++(Ver 5.0).
Cerca di stare piu' attento a cio' che viene detto : Io non ho detto
che fflush() NON PUO' svuotare il buffer di input. Lo ripeto per
l'ennesima volta : fflush() e' DEFINITA SOLO per gli stream di output.
Questo non significa che sia sbagliato usarla per gli stream di input,
ma che potrebbe non funzionare per gli scopi che ci si prefigge e
quindi non e' una tecnica che va consigliata.
Lo standard C (non esiste uno standard C djgpp) specifica che per gli
stream di input il comportamento e' indefinito. 
fflush( stdin ) ha quindi valore solo per quei compilatori che la
supportano. Ti ricordo che nel ng bisogna cercare di essere il piu'
generali possibile, perche' se tu adoperi il VC++, altri potrebbero
non farlo.
--
Andrea Laforgia (
andrea_...@bigfoot.com
)
---------------------------------------------

lettura? Una volta trovato CR, che succede con LF?
Non e' difficile :
 INPUT 
<CR><LF> ----> '\n'
 OUTPUT
   '\n'  ----> <CR><LF>


uno nel buffer?
Non devi svuotarlo __prima__ del getchar(), ma __dopo__.
E comunque questa cosa e' stata detta mille e mille volte :
while ( getchar() != '\n' ) ;
--
Andrea Laforgia (
andrea_...@bigfoot.com
)
---------------------------------------------

 In questo NG  si parla di standard c, o di standard c djgpp?
Di C _standard_. E lo standard dice che fflush() è definita SOLO per gli
output stream.
EMG

 vuoto.
Non è vero: se ad ogni stop del programma invece di inserire solo invio,
batto prima qualcosa, verrà restituito solo il primo carattere, mentre gli
altri rimaranno nel buffer, per fare i soliti danni.
Se invece nel ciclo sostituisco la getchar con while ( getchar() != '\n' );
elimino i caratteri di troppo dal buffer, solo che se nel caso batto solo
invio, lo devo premere ancora per andare avanti....
Marco Iannaccone

 while ( getchar() != '\n' ) ;
Sia se sostituisco la getchar() con questo, sia che lo metto dopo, il
risultato č che non ho problemi inserendo uno o piů caratteri, ma se premo
solo invio, dovrň premerlo ancora per continuare....
Marco Iannaccone

 quindi non e' una tecnica che va consigliata.
fflush() e' una funzione che ritorna un valore intero relativo all'esito dell'
esecuzione.
E' stato domandato come svuotare uno stream di input,e io ho risposto alla
domanda.Il fatto che fflush() sia definito solo per gli stream di output nella
programmazione standard c
lascia un po il tempo che trova visto che diversi compilatori hanno
implementazioni diverse della stessa funzione.Se la funzione non dovesse
raggiungere lo scopo prefisso,ogni compilatore prevede codici di errori impostati
adeguatamente, ed il programmatore e' libero di scegliere strade alternative per
gestire la cosa a seconda dell'implementazione del compilatore a cui la funzione
e' sottoposta.
Certe volte occorre lasciare un po da parte la teoria e dare più spazio alla
pratica.
Ivan Molella

 E comunque questa cosa e' stata detta mille e mille volte :
Calma. Il problema (o la fortuna) di un newsgroup è che non è formato da
un gruppo chiuso di persone e quindi è normale che la stessa domanda
venga ripetuta continuamente da gente sempre diversa (sarebbe strano,
invece, se fosse sempre la stessa persona a porla, ma non mi pare il
nostro caso). La soluzione a questo si chiama FAQ. Nel newsgroup
it.comp.lang.c++ ne abbiamo creata una che ora si trova a disposizione
di tutti al sito 
www.programmatori.it
. Che ne dite di fare la stessa
cosa qui? Qualcuno si prende l'impegno di organizzarla?
EMG

Il problema è che non funziona né sotto DOS col DJGPP che sotto Linux col
GCC....
Marco Iannaccone

 invio, lo devo premere ancora per andare avanti....
Allora, semplicemente, togli la chiamata a getchar() da sola e
sostituiscila con il loop di cui sopra.
EMG

 solo invio, dovrň premerlo ancora per continuare....
Credo che sia un problema del tuo compilatore. Io ho fatto la prova e ha
funzionato regolarmente.
EMG

 implementazioni diverse della stessa funzione.
Evidentemente tu non riesci a capire il motivo per cui l'organismo
internazionale si è dato da fare per standardizzare il C. Hanno dunque
perso tempo?
EMG

 GCC....
Invece, compilato con il DJGPP, il seguente (tuo) programma funziona
perfettamente:
#include<stdio.h>
void funzione(void);
int main(void)
{
int c;
 /* Nel mio programma questo era un menu che richaimava la
  * funzione appropriata */
 printf("Inserire un numero per entrare nella funzione: ");
 scanf("%d",&c);
 funzione();
return 0;
}
void funzione(void)
{
int c=10;
 while ( getchar() != '\n' );
 while(c){
     printf("STAMPA\n"); /* qui si stampava una struttura */
     /* qui serviva a chidere conferma */
     printf("Premere invio per continuare\n");
/*   getchar(); */
     while ( getchar() != '\n' );
     c--; /* serve solo a far avviere il ciclo ad una fine */
 }
}
EMG

cosa qui? Qualcuno si prende l'impegno di organizzarla?
Non se ne era gia' discusso qualche mese fa ? 
BTW, bozze di domande sull'I/O :
Q 1 : posso svuotare il buffer di input con fflush( stdin ) ?
 
A   : Non sempre. Questa tecnica non e' portabile, in quanto
      lo standard non prevede un comportamento preciso per
      questa funzione su stream di input (infatti ne assegna
      un comportamento indefinito).
Q 2 : qual e' allora il metodo da utilizzare per svuotare il 
      buffer di input ?
 
A   : non esiste un metodo portabile, in ogni caso la tecnica
      while ( getchar() != '\n' ) ; dopo ogni chiamata di 
      funzione ad alto livello funziona la maggiorparte delle
      volte.


pratica.
Ti consiglio di leggere la documentazione ufficiale dello standard.
Uno degli intenti del comitato ANSI e' stato quello di tenere in gran
conto la pratica di stesura del codice esistente tra i programmatori
C, la quale non prevede, evidentemente, una tecnica del genere.


Enrico Maria Giordano wrote:
  Ivan Molella wrote:
  >
  > E' stato domandato come svuotare uno stream di input,e io ho risposto
alla
  > domanda.Il fatto che fflush() sia definito solo per gli stream di
output nella
  > programmazione standard c
  > lascia un po il tempo che trova visto che diversi compilatori hanno
  > implementazioni diverse della stessa funzione.
  Evidentemente tu non riesci a capire il motivo per cui l'organismo
  internazionale si è dato da fare per standardizzare il C. Hanno dunque
  perso tempo?
  EMG
Non credo propio che sia una perdita standardizzare il C,pero' so anche
che spesso ci 
sono dei limiti a questo processo di standardizzazione,dettati dalla
molteplicita' delle 
relata' in cui il linguaggio C  e' intercalato: Limiti di piattaforma,di
sistema operativo ecc... 
per cui ogni compilatore puo includere altri standard per integrare e
sfruttare al massimo il 
sistema operativo e la piattaforma vedere posix.1
posix.1b.posix.2,xpg4,xpg4-unix ecc...
In questo NG viene sempre ripetuto che fflush() non e' definita per stream
di output,ed 
essendo una funzione standard C chi legge capisce che in ogni
implementazione di un 
compilatore standard C e' vero cio', mentre non e' cosi' ,cambia da
compilatore a 
compilatore,quindi non capisco perche' se il compilatore supporta la
funzionalita' non si 
debba sfruttarla,visto che 1) non e' detto che un programma scritto in
c,sempre deve 
essere "portato" da tutte le parti, e 2) anche una funzione standard come
la malloc(molto 
usata in questo NG).potrebbe creare situazioni di incompatibilita',da
un'ambiente all'altro, 
dovuti alla diversita' dell'allinamento dell'area di memoria allocata da
parte del SO.
E' vero, e' una buona cosa attenersi il piu' possibile allo standard per
rendere il codice piu' 
portabile possibile,ma e' praticamente impossibile scrivere applicazioni
di una certa "mole"
portabili al 100% senza allonatanarsi di un passo dallo standard e questo
NG il cui nome 
e': " it.comp.lang.c" e non "it.comp.lang.c.standard" dovrebbe essere piu'
aperto ai vari 
aspetti della programmazione c e non relegarsi "tra le mura dello
standard",tacciando in 
assoluto errata una fflush(stdin),dicendo che l'effetto e' indefinito,come
se fosse una 
funzione di tipo void che non sai di preciso cosa possa avere fatto,ma che
invece torna 
tanto di return code che puo essere testatato dal programma, e se il
compilatore la 
supporta ce ne si puo' avvalere tranquillamente migliorando le presatzioni
del programma 
stesso.
Quindi se la prossima volta si vuole precisare le cose,lo  si faccia
completemante non ci si 
limiti a dire "lo standard dice che....." visto che molte persone che
postano sul NG sono 
piu' interessate a risolvere i loro particlorari problemi di
programmazione piu' che allo 
standard,senza alterarsi troppo quando viene detta una cosa non conforme(
ma non 
errata) a cio' che dicono i GURU del NG,senza fare nomi visto che il N.G
e' di tutti e 
ognuno e' libero di dire la sua.
Scusatese se sono stato prolisso.
Ivan Molella
--
Posted from 
mta03-acc.tin.it
 [212.216.176.34]
via Mailgate.ORG Server - 
http://www.mailgate.org

 ognuno e' libero di dire la sua.
E di tessere la corda per impiccarsi come meglio crede.
-- 
Maurizio Loreti                         
http://www.pd.infn.it/~loreti/mlo.html
Univ. of Padova, Dept. of Physics - Padova, Italy            
lor...@pd.infn.it

Va bene nel caso in cui si debba premere solo invio, ma il problema č che
cosě il valore restituito č 0...
Marco Iannaccone

Come ho detto sopra, mettendo il loop al posto della getchar(), non posso
restituire alcun valore, ma si comporta come dovrebbe.
Se invece metto la getchar e poi il loop, va bene inserendo uno o più
caratteri (dei quali viene restiruito solo il primo), ma premendo solo invio
la getchar() se ne aspetta un altro...
Comunque usao DJGPP
Marco Iannaccone

Non sono d'accordo:, più che dire cose tipo "lo standard dice...",
bisognerebbe dire "se usi questo compilatore puoi...., ma non è standard".
Bisognerebbe specificare se una tecnica non è standard, non il contrario.
Comunque, fflush(stdin) non funziona né sul DJGPP sotto DOS che sul GCC
sotto Linux, quindi non mi sembra neanche che sia una grande soluzione...
Marco Iannaccone

       volte.
Uhm... sembra proprio quella tradotta. Comunque tienila da parte. Quando
ne avremo raccolte un numero sufficiente si procederà a sistemarle e a
mandarle a Marco Abis, ok?
EMG

Usa getch() dalla libreria <conio.h> e vedrai che funziona
Augusto Pucci
Webmaster di Prospektiva On-line
http://go.to/Prospektiva

mandarle a Marco Abis, ok?
No, scusami, ma se mi dici che anche questo ti sembra tradotto, allora
dobbiamo inventarci delle parole nuove e degli argomenti nuovi,
altrimenti tutto cio' che scriviamo appare come una scopiazzatura...


 sotto Linux, quindi non mi sembra neanche che sia una grande soluzione...
Per questo lo considero un errore.
EMG
PS. C'è chi esagera con il quoting ma tu esageri nel senso opposto. :-)

 altrimenti tutto cio' che scriviamo appare come una scopiazzatura...
No, no, mi sembrava paro paro quello che avevamo già tradotto ma se mi
dici che non è così ok.
EMG

e' di tutti e ognuno e' libero di dire la sua.
Non vedo che motivo ci sia di prendersela tanto !
Io credo che TUTTE (non molte) le persone che scrivono in un ng siano
interessate a risolvere i propri problemi di programmazione, ma
ignorare lo standard non e' corretto.


you wrote:

Eh... purtroppo le risposte ai quesiti sono quelle !! ;))


Maurizio Loreti wrote:
  (Che maniera balorda di formattare il testo :-(
  Nessun altro standard puo' limitare quello del linguaggio; POSIX stesso,
  di cui tu parli, comprende estensioni e non ridefinizioni.
Il testo forse era formattato male, ma tu non ci hai messo nemmeno un po di
impegno per capirlo,visto che la tua affermazione e' propio quello che
intendevo io,e comunque ricordo che il nome dell' NG e' "it.comp.lang.c" e
non "it.comp.lang.c.standard" quindi possono essere discussi tutti i vari
aspetti del c e le varie differenze che si possono trovare tra
compilatore/piattaforma, se si vuloe si fa notare cosa e' ANSI C,cosa solo
POSIX......e cosa potrebbe e non potrebbe funzionare per un dato
compilatore,ma non arrogarsi il diritto di dire che una cosa non deve essere
usata perche' non standard anche se l'uso e' 
limitato a determinate implementazioni,poiche' allora non dovrebbero essere
trattati neppure argomenti come la gestione degli interrupt sulla versione
xxxx del compilatore yyyyyyy visto che questo riguarderebbe un sottoinsieme
di casi e non lo standard c,e sarebbe una cosa sbagliate perche' anche
quello e' c.
Ivan Molella
--
Posted from 
mta02-acc.tin.it
 [212.216.176.33]


 E' quello che faccio di solito
...
Veramente avevo risposto ad Ivan Molella....
Per il quoting, dato che con newsreader grafici i messaggi vengono
ramificati....    :)
Marco Iannaccone

Certo che funziona, dato che non usa stdin! E comunque non è standard...
A me interessa sapere come svuotare efficacemente il buffer dello standard
input....
Marco Iannaccone

Vabbeh, ma allora si ritorna a prima della definizione dello standard
ANSI...
Sarà servito a qualcosa(anche se alcune cose avrebbero potuto essere fatte
meglio.....), no?! :)
Marco Iannaccone

 quello e' c.
Hai una versione assai ristretta del mondo: la macchina che ti invia
questo messaggio e' una alphastation sotto OS Digital Unix 4.0
rev. 878, e non ha alcun concetto di "interrupt".  Quando comincerai a
capire che nell'universo ci sono persone per cui il TUO ambiente non
ha alcun significato, capirai anche che messaggi come quello che
ipotizzi sono off-topic su questo newsgroup e vanno indirizzati a un
gruppo specifico per DOS o Windows, ad esempio alt.sex.bondage .


quello e' c.
Io credo che questa discussione sia andata avanti sin troppo.
Ti sbagli quando dici che "anche quello e' c", "quello" non e' C,
"quello" e' trattare argomenti che riguardano l'interfacciamento a
basso livello del sistema ed e' una cosa che non riguarda il
linguaggio in se'. Questo e', tra l'altro, uno dei motivi per cui e'
nato it.comp.lang.win32. Qui dentro, lo dico, ma prima di entrare in
un gruppo del genere occorrerebbe informarsi, ci sono molte persone a
cui parlare di interrupt non interessa proprio ed io, personalmente,
ringrazio i programmatori del Forteinc Agent, per aver fornito il loro
programma del comando "Ignore Thread", perche' io sono uno di quelli a
cui parlare di interrupt non interessa. Se poi ci si ostina a non
voler capire che quando si dice che qualcosa per lo standard ha un
comportamento indefinito si intende che non e' assicurato che tutte le
piattaforme provvedano a una definizione, e che quindi il metodo che
si consiglia come universale (non vedo nessun indirizzamento a
piattaforme specifiche nel tuo messaggio) potrebbe non funzionare,
allora e' un altro discorso.


 nato it.comp.lang.win32.
it.comp.programmare.win32.
EMG

A proposito di Digital Unix, li mi pare che fflush(stdin) sia definito....
--
Marco Iannaccone
"Questa è una nave moderna, ma ha un nome antico e glorioso...
Trattala come una signora e ti riporterà sempre a casa"

it.comp.programmare.win32.
ops... ;) 
