Fflush(stdin): come si capisce dove metterlo?

di il
4 risposte

Fflush(stdin): come si capisce dove metterlo?

Ciao a tutti,
sono nuovo di questo forum e del C.
Iniziando a studiare il C mi è capitato di vedere che alcune gets venivano 'saltate'.
Per esempio quando erano dentro a un ciclo, ma anche in altre situazioni. Cercando in rete ho visto che bisognava svuotare il buffer input e ho cercato di capire come fare. Posto un esempio di una funzione che ho scritto
#include <stdio.h>
#include <string.h>
#define n 100
#define fflush(stdin) while ((getchar()) != '\n')

typedef struct studente
{
    char nome[20];
    char cognome[20];
    char corso_laurea[20];
    int voto;
    int lode;
    int anni_studio;
}studente;

void acquisisci(studente laureato_v[],int nlaureati_v)
{
    int i;
    char test_lode[3];
    for(i=0;i<nlaureati_v;i++)
    {
        printf("\nlaureato %d",i+1);
        printf("\ncognome: ");
        gets(laureato_v[i].cognome);
        printf("\nnome: ");
        gets(laureato_v[i].nome);
        printf("\ncorso di laurea: ");
        gets(laureato_v[i].corso_laurea);
        printf("\ninserisci il voto di laurea: ");
        scanf("%d",&laureato_v[i].voto);
        if(laureato_v[i].voto!=100)
            laureato_v[i].lode=0;
        else
        {
            printf("\nha preso pure la lode?");
            fflush(stdin);
            laureato_v[i].lode=(!strcmp(gets(test_lode),"sì"));
        }
        printf("\ninserisci gli anni di studio: ");
        scanf("%d",&laureato_v[i].anni_studio);
        fflush(stdin);
    }
    return;
}
in pratica faccio una
#define fflush(stdin) while ((getchar()) != '\n')
e poi metto i vari
fflush(stdin);
a tentativi e questo non mi piace!
Avevo letto che devo inserirli come prima azione nei cicli, ma nella mia esperienza ho verificato che non sempre va bene. Ho letto pure che si possono mettere ogni tot, e che al massimo non succede nulla, ma se li metto prima di ogni acquisizione, eseguendo il codice succede che si pianta in attesa di tanti invio oppure non fa niente.
Non vi nascondo che ho tanta confusione in merito.
Vorrei sapere in sintesi:

1. come e quando usare fflush(stdin) o altro per non avere problemi

2. problemi come questi affliggono solo gets e scanf?

Ve lo chiedo perché avevo scritto una funzione che compatta un vettore, ma in base al numero di volte che la chiamo si 'perde' un elemento dell'array. Poi per magia delle volte, a parità di input funziona perfettamente. Possibile sia un problema analogo?

ciao Igor

4 Risposte

  • Re: Fflush(stdin): come si capisce dove metterlo?

    Il problema affligge solo la funzione scanf.
    Quindi sarà piu consono chiamare la define come flushscanf. e in definitiva potresti metterlo dietro ad ogni scanf solo per sicurezza.
    la gets non soffre di tali problematiche.
    Dopo la printf ci va la fflush(stdout) quando vuoi essere sicuro che venga vuotato il buffer di uscita.
    Sotto windows è praticamente inutile,mentre sotto linux te ne accorgi subito quando e dove va messo.
  • Re: Fflush(stdin): come si capisce dove metterlo?

    Ma fflush(stdin) non ha un "undefined behaviour" e quindi non dovrebbe essere sempre evitata?
  • Re: Fflush(stdin): come si capisce dove metterlo?

    Ma fflush(stdin) non ha un "undefined behaviour" e quindi non dovrebbe essere sempre evitata?
    #define fflush(stdin) while ((getchar()) != '\n')
    Assolutamente si ma se guardi il codice vedrai che è stata "bruttamente" ridefinita come macro.
    Anche per questo ho consigliato di cambiargli il nome
  • Re: Fflush(stdin): come si capisce dove metterlo?

    Ciao ragazzi,
    grazie mille intanto per le risposte!
    Vi specifico che sto lavorando su un O.S. GNU/Linux con l'ide qt creator, facendo dei progetti non grafici in c!
    Dico questo perché ho fatto la
    #define fflush(stdin) while ((getchar()) != '\n')
    in quanto altrimenti fflush(stdin) non da nessun errore ma nemmeno produce l'effetto voluto!

    domanda 1: fflush(stdin) funziona per sistemi GNU/Linux?

    vbextreme ha scritto:


    Il problema affligge solo la funzione scanf.
    Quindi sarà piu consono chiamare la define come flushscanf. e in definitiva potresti metterlo dietro ad ogni scanf solo per sicurezza.
    la gets non soffre di tali problematiche.
    Dopo la printf ci va la fflush(stdout) quando vuoi essere sicuro che venga vuotato il buffer di uscita.
    Sotto windows è praticamente inutile,mentre sotto linux te ne accorgi subito quando e dove va messo.
    Capito, infatti se non mettevo prima di gets o di scanf(%[^\n]s) la fflushscanf mi succedeva che lo saltasse! Ho capito che in pratica c'era un '\n' vagante e mettendo dopo ogni printf
    fflush(stdout);


    funziona tutto perché evidentemente dipendeva da quello!

    domanda 2: la scanf(%[^\n]s) si comporta come la gets e quindi non ho esigenza di fare fflushscanf?

    Invece della define per fflusf(stdin) posso usare anche una funzione definita appositamente come potete vedere dal codice in allegato alla fine: nel mio esempio il risultato è equivalente!

    domanda 3: nel caso effettivamente mi confermiate che fflush(stdin) non funzioni su sistemi GNU/Linux come mi consigliate ovviare, con la define o con la funzione?

    Posto il codice su cui ho fatto le prove in allegato!
    grazie mille
    Igor
    #include <stdio.h>
    #include <string.h>
    #define lungstrin 10
    #define fflushscanf while ((getchar()) != '\n')
    
    void clean_stdin(void)
    {
        int c;
        do {
            c = getchar();
        } while (c != '\n' && c != EOF);
    }
    
    void lettura_stringa(char stringa_v[])
    {
        int i;
        printf("[");
        fflush(stdout);
        for(i=0;i<=lungstrin-1;i++)
        {
            if(stringa_v[i]=='\0')
            {
                printf("\\0");
                fflush(stdout);
            }
            else if(stringa_v[i]=='\n')
            {
                printf("\\n");
                fflush(stdout);
            }
            else
            {
                printf("%c",stringa_v[i]);
                fflush(stdout);
            }
            if(i==lungstrin-1)
                continue;
            printf(",");
            fflush(stdout);
        }
        printf("]");
        fflush(stdout);
    }
    
    int main()
    {
        char scelta[30];
        char stringa[]="##########";
        char *stringa1;
        stringa1=stringa;
        printf("vediamo come riempiono le stringhe scanf e gets\n");
        fflush(stdout);
        scanf("%s",scelta);
        //fflushscanf;
        clean_stdin();
        if(!strcmp(scelta,"scanf1"))
        {
            printf("\immetti stringa!\n");
            fflush(stdout);
            scanf("%s",stringa);
            //fflushscanf;
            clean_stdin();
            lettura_stringa(stringa);
            printf("\n%s\n",stringa);
            fflush(stdout);
            puts(stringa);
        }
        else if(!strcmp(scelta,"scanf2"))
        {
            printf("\immetti stringa!\n");
            fflush(stdout);
            //clean_stdin();
            scanf("%[^\n]s",stringa);
            lettura_stringa(stringa);
            printf("\n%s\n",stringa);
            fflush(stdout);
            puts(stringa);
        }
        else if(!strcmp(scelta,"gets"))
        {
            printf("\immetti stringa!\n");
            fflush(stdout);
            //clean_stdin();
            gets(stringa);
            lettura_stringa(stringa);
            printf("\n%s\n",stringa);
            fflush(stdout);
            puts(stringa);
        }
        return 0;
Devi accedere o registrarti per scrivere nel forum
4 risposte