2012-12-21 8 views
19

Sappiamo che stdin è, per impostazione predefinita, un input bufferizzato; la prova che è in uso di uno qualsiasi dei meccanismi che "lasciano dati" a stdin, come scanf():C'è comunque da sbirciare al buffer stdin?

int main() 
{ 
    char c[10] = {'\0'}; 
    scanf("%9s", c); 
    printf("%s, and left is: %d\n", c, getchar()); 
    return 0; 
} 

./a.out
ciao
ciao e sinistra è 10

10 essendo a capo naturalmente ...

sono sempre stato curioso, c'è comunque di "sbirciare" al stdin buffer senza rimuovere ciò che può risiedere lì?

EDIT
Un esempio migliore potrebbe essere:

scanf("%9[^.]", c); 

Con un ingresso di "at.ct", ora mi sono "dati" (ct\n) a sinistra su stdin, non solo una nuova riga.

+1

È possibile 'ungetc()' dopo sbirciare. Abbastanza buono? –

+0

@DanielFischer - Immagino che non sia male ... E se fosse rimasto un intero gruppo di personaggi? Posso sapere la lunghezza dei dati rimasti su stdin? o potrei 'ungetc()' più di un carattere? – Mike

+0

"Un carattere di pushback è garantita. Se la funzione' ungetc' è chiamato troppe volte sullo stesso flusso senza un intervento operazione di lettura o il posizionamento di file su quel flusso, l'operazione potrebbe non riuscire." Solitamente puoi 'ungetc' più di uno, ma solo uno è garantito. –

risposta

11

Portabilmente, è possibile ottenere il carattere successivo nel flusso di input con getchar() e quindi reinserirlo con ungetc(), che restituisce uno stato come se il carattere non fosse stato rimosso dallo stream.

La funzione ungetc spinge il carattere specificato da c (convertito in un unsigned char) indietro sul flusso di input puntato da stream. I caratteri respinti verranno restituiti dalle letture successive su quel flusso nell'ordine inverso della loro spinta.Solo

un carattere di pushback è garantita dallo standard, ma di solito, si può spingere indietro di più.

Come accennato in altre risposte resp. i commenti lì, in pratica, si può quasi certamente sbirciare il buffer se si fornisce il proprio buffer con setvbuf, anche se non è senza problemi:

Se buf non è un puntatore nullo, la matrice a cui punta può essere utilizzato al posto di un buffer assegnato dalla funzione setvbuf

che lascia la possibilità che il buffer fornito non possa essere utilizzato affatto.

Il contenuto dell'array in qualsiasi momento è indeterminato.

significa che non si ha alcuna garanzia che il contenuto del buffer rifletta l'input effettivo (e rende utilizzabile il comportamento non definito del buffer se ha durata di archiviazione automatica, se siamo schizzinosi).

Tuttavia, in pratica, il problema principale sarebbe scoprendo dove nel tamponare la parte non ancora consumato dell'ingresso tamponata inizia e dove finisce.

+1

Non eseguirà 'getchar' quando il buffer di input è un blocco vuoto finché non c'è qualcosa da leggere? –

+0

Infatti, lo farebbe. Non sono a conoscenza di un modo portatile per verificare se il buffer è vuoto, tuttavia. –

5

È possibile impostare il proprio buffer con setvbuf su stdin e visualizzarlo quando lo si desidera.

+0

In che modo interagirebbe con 'ungetc'? Suppongo che il carattere 'ungetc'ed sia memorizzato in qualche altra variabile. Inoltre, come sapresti quale parte del buffer viene letta e cosa rimane? – Shahbaz

+0

'La funzione setvbuf() non ha effetto su stdout, stdin o stderr. È ciò che ho letto. Hai un esempio funzionante? – Mike

+0

@ Mike Sembra funzionare su Windows. 'ungetc' funziona come previsto. Non del tutto sicuro su come tenere traccia della posizione di lettura/sinistra. Ma se il buff è nuovo, allora sarebbe facile. – nullpotent

3

Se si vuole guardare il buffer di stdin senza cambiarla, si potrebbe dire che per utilizzare un altro buffer con setbuf, utilizzando una matrice è possibile accedere a:

char buffer[BUFSIZ]; 

if (setbuf(stdin, buffer) != 0) 
    // error 

getchar(); 

printf("%15s\n", buffer); 

Questo ti permette di vedere qualcosa di più di ungetc, ma non penso che tu possa andare oltre in un modo portabile.

realtà questo è legale, ma non è corretto per lo standard, citando da esso sul setvbuf (setbuf ha lo stesso comportamento):

I contenuti della matrice in qualsiasi momento sono indeterminato.

Quindi questo non è quello che ti serve se stai cercando la portabilità completa e la conformità agli standard, ma non riesco a immaginare perché il buffer non dovrebbe contenere ciò che è previsto. Tuttavia, sembra che funzioni sul mio computer.

Attenzione che è necessario fornire un array di almeno BUFSIZ caratteri a setbuf e non si deve eseguire alcuna operazione di I/O nello stream prima di esso. Se hai bisogno di maggiore flessibilità, dai un'occhiata a setvbuf.