2013-07-24 26 views
5

Sto cercando: - Rileggi il valore se l'utente immette un valore non valido. Ma il problema è che scanf() viene eseguito solo una volta e non verrà eseguito in nessun altro momento e i programmi si bloccheranno con un ciclo infinito.Scanf non verrà eseguito per la seconda volta

#include<stdio.h> 
#include<math.h> 
main() 
{ 
    unsigned int a; 
    unsigned int b = pow(2,M-1); 
    unsigned int c; 
    int x; 

    printf("b = %i",b); 

    input: 
    fflush(stdin); 
    fflush(stdout); 
    printf("\nEnter any integer: "); 
    x = scanf("%u",&a); 

    printf("%u",a); 
    if(x==0) 
     goto input; 

    printf("\na = %i",a); 

    c = a & b; 

    printf("\nc = %i",c); 

    if(c) 
     printf("\nthe bit %i is set",M); 
    else 
     printf("\nthe bit %i is not set",M); 
} 

Ho provato con l'aggiunta di spazio prima di %u e anche provato fflush(stdin) ma niente ha funzionato.

EDIT: So che l'uso di goto non è raccomandato ma devo farlo in questo modo. (L'uso del ciclo non è un'opzione). M è una macro che definisco usando la riga di comando gcc in fase di compilazione.

+0

in questo caso è possibile utilizzare il ciclo while. Per favore guarda il codice modificato sotto – stev

risposta

9

Attenzione: fflush(stdin); potrebbe essere un comportamento non definito. Leggi: Why fflush(stdin) is wrong?

int fflush(FILE *ostream);
I ostream indica un flusso di output o un flusso di aggiornamento in cui il ultima operazione non era ingresso, la funzione fflush provoca alcuna dati non scritti per quel flusso da consegnare all'ambiente ospite da scrivere nel file; in caso contrario, lo behavior è Undefined.

si può provare un ciclo e leggere fino EOF o \n dato this FAQ entry invece di fflush(stdin) come ho suggerito di seguito nella mia risposta.

Edit: grazie a @Jonathan Leffler:

Ci sono piattaforme in cui fflush(stdin) è completamente definito (come estensione non standard su quella piattaforma). L'esempio principale è una famiglia ben nota di sistemi noti collettivamente come Windows. Specifiche Microsoft di int fflush(FILE *stream);Se stream è aperto per l'immissione, fflush cancella il contenuto del buffer.

Ho ulteriori dubbi nel codice; cosa è M nell'espressione unsigned int b = pow(2,M-1);? Dovrebbe essere un errore se non lo definisci. Stai postando il codice completo?

voi per quanto riguarda la logica di rilevamento degli errori:

ri-leggere il valore se l'utente inserisce un invalido

No, scanf() non restituisce un codice di errore. Restituisce il numero di conversioni riuscite.

int scanf (const char * format, ...);
Return Value
In caso di successo, la funzione restituisce il numero di elementi della lista degli argomenti pieno successo.Questo conteggio può corrispondere a il numero previsto di articoli o essere inferiore (pari a zero) a causa di un errore corrispondente , un errore di lettura o la portata della fine del file.

Se un errore di lettura o verifica viene raggiunta la fine del file-mentre lettura, l'indicatore corretto è impostato (feof o ferror). E, se si verifica prima che i dati possano essere letti correttamente, viene restituito EOF.

Se un errore codifica avviene interpretazione caratteri estesi, la funzione imposta errno a EILSEQ.

Quindi in realtà a seconda dell'errore riscontrato il valore restituito può essere zero, EOF. È necessario utilizzare la macro int ferror (FILE * stream); e errno per il rilevamento degli errori (controllare l'esempio fornito al collegamento).

errori possibili a causa di input non valido può essere:

EILSEQ: sequenza di byte di ingresso non forma un carattere valido.
EINVAL: argomenti non sufficienti; o il formato è NULL.
ERANGE: una conversione intera supera la dimensione che può essere memorizzata nel tipo intero corrispondente.

Controllare scanf manual per l'elenco completo.

Motivo ciclo infinito:

Il sistema tiene traccia di quale ingresso è stato visto finora. Ogni chiamata a scanf riprende da dove l'ultimo ha interrotto l'input corrispondente. Ciò significa che se si è verificato un errore con il precedente scanf, l'input che non è riuscito a corrispondere è ancora lasciato non letto, come se l'utente digitato avanti. Se non si presta attenzione per scartare l'input dell'errore e viene utilizzato un loop per leggere l'input, il programma può rimanere intrappolato in un loop infinito.

Così, per esempio nel codice:

x = scanf("%u", &a); 
     // ^
     // need a number to be input 

Ma supponiamo che non viene inserito un numero, ma una stringa non valida viene inserito per esempio "name" (anziché un numero, come dici tu). Ciò causerà l'errore della funzione scanf() quando si tenta di associare un numero intero senza segno ("%u") e la parola "name" non viene letta. Quindi, la volta successiva, il ciclo scanf() non attende l'input dell'utente, ma prova a convertire nuovamente "nome".

Similmente se l'ingresso fosse 29.67, il "%u" restituisce i primi due soli caratteri (il 29), lasciando la .67 ingresso come da leggere per la chiamata successiva al scanf().

Anche se l'input è corretto, come 29, la fine riga che ha terminato l'input è ancora lasciata non letta.Normalmente questo non è un problema poiché la maggior parte delle conversioni salta automaticamente spazi bianchi iniziali come la nuova riga finale dalla riga precedente. Tuttavia, alcune conversioni ("%c" e "%[") non salteranno alcun spazio bianco iniziale, quindi è necessario farlo manualmente.

Per evitare questo infinito loop Un suggerimento:

(ricordate: come ho consigliato l'uso di ferror(), errore di valore è preferibile per rilevare input non valido Inoltre, è solo per l'apprendimento scopo e se. bisogno di attuare una seria applicazione si dovrebbe usare fgets(str) invece di scanf() seguita da quella analizzare str input per verificare se l'input è valido)

input: 
    //fflush(stdout); //use if needed, as \n used in printf no need of fflush-stdout 
    printf("\nEnter any integer: "); 
    x = scanf("%u", &a); // always wait for new symbols 
    printf("%u", a); 

    if(x == 0){ // x=0, if error occurred 
     // read all unread chars 
     while ((ch = getchar()) != '\n' && ch != EOF); 
     goto input; 
    } 

E 'solo un suggerimento che sarà p funziona in modo ossibile con il tuo codice (ha funzionato per me, il tuo codice + gcc). Ma se si utilizza questa tecnica in modo non corretto, può lasciare un bug nel codice:

Leggi How do I flush the input buffer?

Se si è certi che i dati indesiderato è nel flusso di input, è possibile utilizzare alcuni dei seguenti codici snippet per rimuoverli. Tuttavia, se si chiama quando non ci sono dati nel flusso di input, il programma sarà attendere fino a quando non lo è, il che dà risultati indesiderati.

+1

+1 per questo - * Puoi provare un ciclo e leggere fino a EOF o \ n *, chiaramente indica che OP dovrebbe bandire l'uso di 'goto' :) – 0decimal0

+2

Borbottare: anche questo forte! Ci sono piattaforme in cui 'fflush (stdin)' è completamente definito (come estensione non standard su quella piattaforma). L'esempio principale è una famiglia ben nota di sistemi noti collettivamente come Windows. Vedi le specifiche di Microsoft su ['fflush()'] (http://msdn.microsoft.com/en-us/library/9yky46tz.aspx): ** Se lo stream è aperto per l'input, 'fflush' cancella il contenuto di il buffer. ** –

+0

@JonathanLeffler Ok! ora posso ricordare In passato con il turbo-C sotto DOS in università ho usato 'fflush (stdin)'. E non era sbagliato! ~~ Grazie! –

1

Questa soluzione consente di evitare loop infiniti. Invece di goto si prega di utilizzare il ciclo while while:

do { 
    printf("\nEnter any integer: "); 
    x = scanf("%u",&a); 

    printf("%u",a); 
    if(x == 0) 
    { 
      char c; 
      printf("hit any key \n"); 
      c = getchar(); 
    } 

    } while(x==0); 
+1

** No ** .... che è corretto –

+0

stev, 'x' è assegnato un valore restituito da scanf(), scanf non scansiona un valore restituisce 0, leggi: http://www.cplusplus.com/ reference/cstdio/scanf/ –

+0

Grijesh, Sì, ho missread la sua domanda. scanf non restituirà EOF a meno che il flusso di input non sia chiuso, ovvero che la console si chiuda. Quindi va in loop infinito. – stev