Newsgroup: it.comp.lang.c
Titolo: fflush(stdin)  e  %c%Pc  con scanf (C)

Linguaggio C.
 
Ho scritto quasto semplice codice che
chiede di digitare due lettere.
Purtroppo mi da la possibilità di inserire solo il primo carattere...
A quanto pare, l'invio che do dopo l'inserimento del primo carattere, 
viene considerato come se fosse il secondo carattere.
 
Su internet ho trovato due soluzioni:
Ad ogni scanf aggiungere "%c%*c" oppure, subito
dopo ogni scanf, aggiungere l'istruzione
fflush(stdin);
 
Mi dite la differenza?
 
grazie anticipatamente
nero23
 
 
 
//CODICE INIZIALE
  char a;
  char b;
  printf("inserisci la prima lettera\n");
  scanf("%c",&a);
  printf("inserisci la seconda lettera\n");
  scanf("%c",&b);
  printf("hai inserito le lettere %c e %c\n",a,b);
 
 
 
 
 
 
 
 
 
//CODICE INIZIALE CON L'AGGIUNTA DI  %*c
  char a;
  char b;
  printf("inserisci la prima lettera\n");
  scanf("%c%*c",&a);
  printf("inserisci la seconda lettera\n");
  scanf("%c%*c",&b);
  printf("hai inserito le lettere %c e %c\n",a,b);
 
 
 
//CODICE INIZIALE CON L'AGGIUNTA DI  fflush(stdin);
  char a;
  char b;
  printf("inserisci la prima lettera\n");
  scanf("%c",&a);
  fflush(stdin);
  printf("inserisci la seconda lettera\n");
  scanf("%c",&b);
  printf("hai inserito le lettere %c e %c\n",a,b);
  fflush(stdin);

 
 
MAI e dico MAI fare il flush dello stream di input.
Va da se quale sia la versione "corretta" :D
 

 
 
Semplificando, il "*c" serve a dire alla scanf di ignorare il carattere 
che digiti in corrispondenza di quella specifica di formato.
 

 che digiti in corrispondenza di quella specifica di formato.
 
 
 
è la soluzione adottata dal prof. Marco Mezzalama (da un video scaricato 
dal sito del Politecnico di Torino).
 
ciao
 

 Va da se quale sia la versione "corretta" :D
 
 
per quale motivo?
 
nero23
 

 ha scritto:

Uno tra tutti: si hanno dei comportamenti non definibili a priori.
 
 

 Uno tra tutti: si hanno dei comportamenti non definibili a priori.
 
 
  La console di Eclipse da problemi (non visualizza la domanda e, dopo 
aver digitato il primo carattere e dato invio, compare qualcosa...).
Con Eclipse Funziona solo aggiungendo fflush(stdin)...
 
Sapresti dirmi se è possibile avviare il
programma dalla console di Windows come avviene con Codeblocks?
 
Ciao
 
nero23
 


 
Invece tu stesso hai detto di aver risolto con "fflush(stdout)"
(vedi il tuo post del 27/11). Cosa strana, questo bug esiste da anni:
https://bugs.eclipse.org/bugs/show_bug.cgi?id=173732
 
Leggendo un po' la discussione linkata qualcuno afferma che in realtï¿œ
la console di Eclipse non ï¿œ un vero "terminale" (nel senso unix-iano
del termine). Quando dicono "terminale" intendono che lo stdout sia
line-buffered, ovvero che il buffer venga svuotato automaticamente
quando viene inviato un carattere di new-line come '\n' (o quando
ovviamente il buffer sia pieno), cosa che in Eclipse non avviene.
Tuttavia in alcuni sistemi lo stdout puo' anche essere fully-buffered,
ovvero che il relativo buffer puo' svuotarsi automaticamente *solo*
dopo essersi riempito totalmente oppure unbuffered, nel qual caso
la scrittura avverrebbe direttamente a schermo senza passare dal buffer
(questo solitamente ï¿œ il caso di stderr nei sistemi unix-like).
Morale della favola: ï¿œ un peccato che un ide favoloso come Eclipse non
preveda il consueto comportamento, a cui siamo tutti abituati,
per lo standard output.
 
-- 
Vincenzo Mercuri


wrote:

io sono rimasto allo standard Linguaggio C c89
mi sembra che
 fflush(stdin);
non è definito dallo standard del linguaggio C
[anche se il compilatore potrebbe avere una fflush
 con le istruzioni giuste...]
inoltre penso che bisognerebbe controllare se 
l'elemento di conversione di scanf
ha preso l'input
quindi l'unico modo corretto dovrebbe essere:
 
#include <stdio.h>
 
int main(void) 
{int   v, m;
 char  a, b;
 
 printf("inserisci la prima lettera\n");
 v=scanf("%c",&a);
 if(v!=1) return 0;
 if(b!='\n') 
    while( (m=getchar())!='\n' && m!=EOF);   
 printf("inserisci la seconda lettera\n");
 v=scanf("%c",&b);
 if(v!=1) return 0;
 if(b!='\n')
    while( (m=getchar())!='\n' && m!=EOF);  
 printf("hai inserito le lettere %c e %c\n",a,b);
 return 0;
}
 
 

 (vedi il tuo post del 27/11). Cosa strana, questo bug esiste da anni:
 
Il problema di Eclipse
è che senza fflush(stdout) la console non visualizza neppure l'inizio 
del programma (nel mio caso la domanda inserisci un numero).
Con altri programmi, ad esempio CodeBlocks, la console visualizza la 
domanda iniziale del programma per poi presentare il problema se manca 
fflush(stdout)
 
 
ciao
 

 per lo standard output.
 
Per questo motivo ho deciso di passare a CodeBlocks.
Di Eclipse mi piace molto la segnalazione di un errore mentre digiti il 
codice.
Con CodeBlocks devi prima compilare, e molte volte la bandierina 
dell'errore non compare accanto alla riga che ha generato l'errore...
 
ciao
 
 


wrote:

ma almeno quando il programma finisce ci dovrebbe esser un flush..
secondo me il problema che dici non è un problema
è sbagliato lo standard C ad ammettere che '\n' crea un fluhs(stdout)
poiche' molte volte è utile avere uno stream che non flush 
se non esplicitamente
 

 se non esplicitamente
 
 
Intendevo dire con CodeBlocks la console visualizza la domanda iniziale 
del programma. Con Eclipse, la console rimane bianca.
 
In poche parole, con Eclipse non capisci subito se il programma si è 
avviato oppure no...
 
 


 
per i sistemi che non flush stdout, se non esplicitamente
 
#include <stdio.h>
 
int main(void) 
{int   v, m;
 char  a, b;
 
 printf("inserisci la prima lettera\n");  fflush(stdout);
 /* prende il primo carattere della linea
    tralascia tutti gli altri */
 v=scanf("%c",&a);
 if(v!=1) return 0;
 if(b!='\n') 
    while( (m=getchar())!='\n' && m!=EOF);   
 printf("inserisci la seconda lettera\n"); fflush(stdout);
 v=scanf("%c",&b);
 if(v!=1) return 0;
 if(b!='\n')
    while( (m=getchar())!='\n' && m!=EOF);  
 printf("hai inserito le lettere %c[%u] e %c[%u]\n", a,a, b,b);  
 fflush(stdout);
 return 0;
}
 


wrote:

la soluzione che funziona in entrambi dovrebbe essere, scrivere
fflush(stdout);
dopo ciascuna printf() [o istruzione che scrive in stdout] che scriva
o no '\n'...
 


E' esattamente quello che ho detto, ed è registrato fra i "bug" di
Eclipse. Tuttavia non è stato risolto e il parere di alcuni è che non
sia veramente un bug. Il C non assume che stdout sia line-buffered,
come ho detto esistono diversi tipi di buffering per gli stream standard.
Dico solo che il comportamento della console di Eclipse non è come
quello dei terminali a cui siamo abituati. In teoria dovremmo svuotare
il buffer (con fflush(stdout)) ogni qualvolta desideriamo che l'output
venga scritto.
 
-- 
Vincenzo Mercuri

>
[CUT]
Il C non assume che stdout sia line-buffered
 
Per la precisione, l' implementazione della libreria standard sui flussi 
non assume che l' output stream sia line buffered
Il C non conosce i flussi
 
Lo standard dice che stdout dovrebbe essere implementato cosi:
 
if stdout is a terminal then buffering is automatically set to line 
buffered, else it is set to buffered
 
cioè alla grandezza del buffer interno, grandezza che dipende dalla 
implementazione
 
Comunque è consentito uno user buffer (definito dall' utente) oppure il 
cambio della modalità (line buffered,buffered,unbuffered)
 
 
 
 
 


 
Esatto.
 
-- 
Vincenzo Mercuri


Esatto, il nostro amico potrebbe tentare di impostare nel suo programma 
la modalità unbuffered per il flusso che gli interessa e incrociare le dita
 


Si, questa è una possibile via, facendo uso della funzione "setvbuf()",
soluzione proposta anche nel bug report linkato in un post più sopra.
 
-- 
Vincenzo Mercuri


A Ok, non l' avevo letto
Chiedo scusa
 
 


 
Ma no, non volevo ottenere delle scuse, hai fatto bene a farlo
presente, non tutti credo abbiano la pazienza di leggere quella
pagina. E' la soluzione migliore, senza dover "flushare" ogni volta.
 
-- 
Vincenzo Mercuri

 if(b!='\n')
^^^^^^^^^^^^^^^^
no
if(a!='\n')
