Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
C/C++ - [C]-Verifica validita' input da tastiera
Forum - C/C++ - [C]-Verifica validita' input da tastiera

Pagine: [ 1 2 3 ] Precedente | Prossimo
Avatar
Mikelius (Member)
Expert


Messaggi: 525
Iscritto: 14/04/2017

Segnala al moderatore
Postato alle 21:11
Martedì, 11/07/2017
Buonasera, come spesso accade, La maggior parte dei programmi richiedono degli input, spesso questi input posso essere dei semplici Si - No, intero positivo minore di 10 o complessi tipo equazioni.

Ho scritto delle funzioni, in teoria generiche, che hanno la funzione di verificare
se il dato immesso sia più o meno lecito
Nel caso di Si-No verificarli è molto semplice. Posto innanzitutto questa funzione (ne ho una per gli interi positivi <10 sulla stessa falsa riga di questa ed un'altra per verificare un range di interi di grandezza variabile (es. 56-9865)

Posto una alla volta per non fare confusione


func.c
Codice sorgente - presumibilmente C/C++

  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4. /* Verifica che l'immissione da tastiera sia tra 2 possibili caratteri
  5.    scelti dal chiamante. I caratteri possono essere minuscoli o MAIUSCOLI.
  6.    Es. [S/N]-[s/n] o [Y/N]-[y/n] */
  7.  
  8. /* Dato un input da tastiera lo esamino carattere per carattere.
  9.    Ritengo valido l'input composto SOLO ED ESCLUSIVAMENTE dai caratteri in input
  10.    vero e falso. Prendo il primo carattere immesso,
  11.    - se NON E' uno dei caratteri validi finisco la funzione con errore
  12.    - se LO E' , verifico il 2° .
  13.        - se è '\n' vuole dire che è stato immesso solo un carattere ed e' valido
  14.        - altrimenti l'input non è valido.
  15.  Si lascia al chiamante l'opportunità di ripetere la richiesta del carattere
  16. in caso di esito negativo della 1°  */
  17.  
  18. int selecTF( int vero, int falso, unsigned char *carattere ){
  19.  
  20.     int c = 0;         //Inizzializzo per sicurezza
  21.     *carattere = '\0'; //Inizzializzo per sicurezza
  22.  
  23.     // prelevo e testo dal buffer il 1° carattere
  24.     c = getchar();
  25.  
  26.     if( c == tolower( vero ) || c == toupper( vero )
  27.         ||
  28.         c == tolower( falso ) || c == toupper( falso ) ){
  29.  
  30. // Lo rendo minuscolo per evitare nella funzione chiamante 2 controlli ulteriori
  31. //  NON ESSENZIALE
  32.         *carattere =(unsigned char)tolower( c );
  33.  
  34.         // prelevo e testo dal buffer il 2° carattere
  35.         c = getchar();
  36.         if( (c == '\n') ){
  37.          //   printf( "VALORE CORRETTO\n" ); //utile o no?
  38.             return 0;
  39.         }
  40.     }
  41.     while( (getchar() != '\n') );
  42. //Svuoto il  buffer nel caso di richiesta di nuova immissione
  43.     return -1;
  44. }



main.c
Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2.  
  3. int selecTF( int ch1, int ch2, unsigned char *caracter );
  4.  
  5.  
  6. int main( int arcv, char *arcg[] ){
  7.  
  8.     int value = 0;
  9.     unsigned char letter=' ' ;
  10.  
  11.  
  12.     printf( "IMMETTERE [%c/%c] :", 'S', 'N' );
  13.     while(selecTF( 's', 'n',&letter ))
  14.     {
  15.             printf( "%s\n%s [%c/%c]:",
  16.                 "IL CARATTERE IMMESSO NON E'CORRETTO",
  17.                 "IMMETTERE",
  18.                 'S', 'N' );
  19.     }
  20.  
  21.     printf( "IL carattere scelto e' il: %c\n\n", letter );
  22.  
  23.  
  24.     return 0;
  25. }



Pareri? migliorie? meglio che mi do all'ippica XD??

P.S. (ma sono i commenti che rendono il 1° codice non colorato?)

Ultima modifica effettuata da Mikelius il 11/07/2017 alle 21:16
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 23:04
Martedì, 11/07/2017
Tempo fa per affrontare una volta per tutte la stessa situazione avevo escogitato una roba così (le righe che interessano sono 16-38):

Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4.  
  5. /*==============================================================================
  6. Presenta all'utente la stringa passata nel parametro "testo", seguita dai
  7. caratteri passati tramite i parametri vero e falso, tra parentesi e separati da
  8. una sbarra diagonale.
  9. Se l'utente digita il carattere corrispondente a vero, la funzione restituisce
  10. 1; se digita il carattere corrispondente a falso restituisce 0. Fintanto che
  11. l'utente non inserisce un carattere corrispondente a vero o a falso, la funzione
  12. richiede insistentemente una nuova immissione.
  13. La funzione non fa differenza tra caratteri minuscoli e maiuscoli.
  14. ==============================================================================*/
  15.  
  16. int chiedi_vero_falso (char *testo, char vero, char falso) {
  17.     int esito, primo_passaggio = 1;
  18.  
  19.     vero  = tolower( vero );  /* internamente, usa sempre lettere minuscole */
  20.     falso = tolower( falso ); /* internamente, usa sempre lettere minuscole */
  21.  
  22.     do {
  23.         int input; /* riceve il valore di ritorno di getchar() */
  24.  
  25.         if( !primo_passaggio) /* se e' il caso, riformula la domanda */
  26.             printf( "%s", "Immissione non valida, riprova.\n\n" );
  27.         else primo_passaggio = 0;
  28.  
  29.         /* pone la domanda coerentemente coi parametri */
  30.         printf( "%s (%c/%c) ", testo, vero, falso );
  31.         input = tolower( getchar() );
  32.         esito = ((input!=vero)&&(input!=falso)) ? -1 : (input==vero?1:0);
  33.  
  34.         while( '\n' != input ) input = getchar(); /* svuota stdin */
  35.     } while( -1 == esito );
  36.  
  37.     return esito;
  38. }
  39.  
  40. /*==============================================================================
  41. Semplice esempio d'uso.
  42. ==============================================================================*/
  43.  
  44. int main() {
  45.     int esito = chiedi_vero_falso( "Ti chiami AldoBaldo?", 's', 'n' );
  46.  
  47.     if( 1 == esito ) /* 1: vero (in questo caso, si') */
  48.         printf( "Ah, ti chiami AldoBaldo... allora sei figo!\n\n" );
  49.     else printf( "Lo sapevo, AldoBaldo e' piu' figo di te.\n\n" );
  50.  
  51.     printf( "Premi \"invio\" per lasciare il programma...\n\n" );
  52.     getchar();
  53.  
  54.     return 0;
  55. }


Ultima modifica effettuata da AldoBaldo il 11/07/2017 alle 23:05


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
Mikelius (Member)
Expert


Messaggi: 525
Iscritto: 14/04/2017

Segnala al moderatore
Postato alle 1:58
Mercoledì, 12/07/2017
Testo quotato

Postato originariamente da AldoBaldo:

Tempo fa per affrontare una volta per tutte la stessa situazione avevo escogitato una roba così (le righe che interessano sono 16-38):

Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <ctype.h>
  4.  
  5. /*==============================================================================
  6. Presenta all'utente la stringa passata nel parametro "testo", seguita dai
  7. caratteri passati tramite i parametri vero e falso, tra parentesi e separati da
  8. una sbarra diagonale.
  9. Se l'utente digita il carattere corrispondente a vero, la funzione restituisce
  10. 1; se digita il carattere corrispondente a falso restituisce 0. Fintanto che
  11. l'utente non inserisce un carattere corrispondente a vero o a falso, la funzione
  12. richiede insistentemente una nuova immissione.
  13. La funzione non fa differenza tra caratteri minuscoli e maiuscoli.
  14. ==============================================================================*/
  15.  
  16. int chiedi_vero_falso (char *testo, char vero, char falso) {
  17.     int esito, primo_passaggio = 1;
  18.  
  19.     vero  = tolower( vero );  /* internamente, usa sempre lettere minuscole */
  20.     falso = tolower( falso ); /* internamente, usa sempre lettere minuscole */
  21.  
  22.     do {
  23.         int input; /* riceve il valore di ritorno di getchar() */
  24.  
  25.         if( !primo_passaggio) /* se e' il caso, riformula la domanda */
  26.             printf( "%s", "Immissione non valida, riprova.\n\n" );
  27.         else primo_passaggio = 0;
  28.  
  29.         /* pone la domanda coerentemente coi parametri */
  30.         printf( "%s (%c/%c) ", testo, vero, falso );
  31.         input = tolower( getchar() );
  32.         esito = ((input!=vero)&&(input!=falso)) ? -1 : (input==vero?1:0);
  33.  
  34.         while( '\n' != input ) input = getchar(); /* svuota stdin */
  35.     } while( -1 == esito );
  36.  
  37.     return esito;
  38. }
  39.  
  40. /*==============================================================================
  41. Semplice esempio d'uso.
  42. ==============================================================================*/
  43.  
  44. int main() {
  45.     int esito = chiedi_vero_falso( "Ti chiami AldoBaldo?", 's', 'n' );
  46.  
  47.     if( 1 == esito ) /* 1: vero (in questo caso, si') */
  48.         printf( "Ah, ti chiami AldoBaldo... allora sei figo!\n\n" );
  49.     else printf( "Lo sapevo, AldoBaldo e' piu' figo di te.\n\n" );
  50.  
  51.     printf( "Premi \"invio\" per lasciare il programma...\n\n" );
  52.     getchar();
  53.  
  54.     return 0;
  55. }





Ho provato il codice. Riscontro un funzionamento che per me è un bug.. se immetto la stringa tipo
"sn" o "n5464:-???" accetta lo stesso l'input e va avanti

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 6:48
Mercoledì, 12/07/2017
Non è un malfunzionamento, è una caratteristica. L'unica cosa che verifico è il primo carattere dell'input. Secondo te sarebbe meglio inibire le immissioni che comprendano altri caratteri aggiuntivi rispetto a quello richiesto? In effetti la tua soluzione lo fa. Sai che ti dico? Accetto la tua correzione. Tra un po' mando la versione modificata.


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 7:12
Mercoledì, 12/07/2017
Fatto! La differenza rispetto a prima sta nelle righe dalla 32 alla 34.
Ora se è stato immesso più di un carattere la funzione non accetta l'input e replica la richiesta di immissione.

Giè che c'ero ho anche fatto in modo che nel proporre la richiesta di immissione vengano usati in console gli stessi caratteri passati come parametri, non le loro versioni minuscole. La differenza riguarda solo la visualizzazione, perché poi in effetti vengono accettati come risposta sia il maiuscolo, sia il minuscolo.

Edit: sempre per far l'esagerato, ho previsto anche il caso in cui il parametro testo fosse NULL.

Codice sorgente - presumibilmente C++

  1. /*==============================================================================
  2. Presenta all'utente la stringa passata nel parametro "testo", seguita dai
  3. caratteri passati tramite i parametri vero e falso, tra parentesi e separati da
  4. una sbarra diagonale.
  5. Se l'utente immette il carattere corrispondente a vero, la funzione restituisce
  6. 1; se immette il carattere corrispondente a falso restituisce 0. Fintanto che
  7. l'utente non inserisce uno e un solo carattere corrispondente a vero o a falso,
  8. la funzione richiede insistentemente una nuova immissione.
  9. La funzione non fa differenza tra caratteri minuscoli e maiuscoli.
  10. ==============================================================================*/
  11.  
  12. int chiedi_vero_falso (const char *testo, char vero, char falso) {
  13.     int esito, qCar, primo_passaggio = 1, t = NULL!=testo;
  14.     const char *spz[] = { "", " " }; /* spz: spazio */
  15.  
  16.     int vMin = tolower( vero );  /* internamente, usa solo lettere minuscole */
  17.     int fMin = tolower( falso ); /* internamente, usa solo lettere minuscole */
  18.  
  19.     do {
  20.         int input; /* riceve il valore di ritorno di getchar() */
  21.  
  22.         if( !primo_passaggio) /* se e' il caso, riformula la domanda */
  23.             printf( "%s", "Immissione non valida, riprova.\n\n" );
  24.         else primo_passaggio = 0;
  25.  
  26.         /* pone la domanda coerentemente coi parametri */
  27.         printf( "%s%s(%c/%c) ", t?testo:spz[0], spz[t], vero, falso );
  28.  
  29.         input = tolower( getchar() );
  30.         esito = ((input!=vMin)&&(input!=fMin)) ? -1 : (input==vMin?1:0);
  31.  
  32.         for( qCar=0; '\n' != input; ++qCar )
  33.             input = getchar(); /* svuota stdin e conta i caratteri immessi */
  34.         if( 1 != qCar ) esito = -1; /* accetta input con un solo carattere */
  35.     } while( -1 == esito );
  36.  
  37.     return esito;
  38. }


Ultima modifica effettuata da AldoBaldo il 12/07/2017 alle 7:37


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
Mikelius (Member)
Expert


Messaggi: 525
Iscritto: 14/04/2017

Segnala al moderatore
Postato alle 9:02
Mercoledì, 12/07/2017
Testo quotato

Postato originariamente da AldoBaldo:

Non è un malfunzionamento, è una caratteristica. L'unica cosa che verifico è il primo carattere dell'input. Secondo te sarebbe meglio inibire le immissioni che comprendano altri caratteri aggiuntivi rispetto a quello richiesto? In effetti la tua soluzione lo fa. Sai che ti dico? Accetto la tua correzione. Tra un po' mando la versione modificata.



Non era proprio una correzione, ma io non vorrei svegliarmi la notte ,e chiedermi se l'utente che avesse digitato "sn" era strabico o meno. Non è impensabile che sia la 's' ad essere di troppo XD.

Per quanto riguarda "testo". Io l'ho messo fuori la funzione per renderla minimale.
Chiedo a tutti, come buon stile e più opportuno dentro o fuori la funzione?

Chiedo a te (ed anche a tutti)
Codice sorgente - presumibilmente Plain Text

  1. /* pone la domanda coerentemente coi parametri */
  2.             printf( "%s%s(%c/%c) ", testo?testo:" ", "", vero, falso );



cosi eviti una variabile? cioe se testo è NULL può essere considerata 0 e se è con dei valori 1?

Codice sorgente - presumibilmente Plain Text

  1. esito = ((input!=vMin)&&(input!=fMin)) ? -1 : (input==vMin?1:0);
  2. //usando invece
  3.             esito = ((input!=tolower( vero ))&&(input!=tolower( falso ))) ? -1 : (input==tolower( vero )?1:0);


Cosi si hanno 2 variabili in meno ma una chiamata a tolower in più?
meglio usare le 2 variabili (utilizzare più memoria) o una chiamata a tolower? (aumentare il tempo di calcolo).


Ultima modifica effettuata da Mikelius il 12/07/2017 alle 9:03
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 9:47
Mercoledì, 12/07/2017
Il testo della richiesta l'ho inserito tra i parametri perché in quel modo se l'utente immette qualcosa di inaccettabile è possibile ripetere la richiesta completa e, in un certo senso, "sigillare" il procedimento assicurandosi che il valore ritornato sia per forza o 0 o 1 (eliminando così la necessità di ingombranti verifiche "esterne").

Sulla questione della variabile in più o in meno e del calo di prestazioni per la chiamata a tolower() in più direi che nel contesto di una funzione del genere è irrilevante. A me, lì per lì, è sembrato più chiaro avere due variabili distinte vMin e fMin, però non credo sia una cosa così importante.


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Avatar
Mikelius (Member)
Expert


Messaggi: 525
Iscritto: 14/04/2017

Segnala al moderatore
Postato alle 10:45
Mercoledì, 12/07/2017
Testo quotato

Postato originariamente da AldoBaldo:

Il testo della richiesta l'ho inserito tra i parametri perché in quel modo se l'utente immette qualcosa di inaccettabile è possibile ripetere la richiesta completa e, in un certo senso, "sigillare" il procedimento assicurandosi che il valore ritornato sia per forza o 0 o 1 (eliminando così la necessità di ingombranti verifiche "esterne").

Sulla questione della variabile in più o in meno e del calo di prestazioni per la chiamata a tolower() in più direi che nel contesto di una funzione del genere è irrilevante. A me, lì per lì, è sembrato più chiaro avere due variabili distinte vMin e fMin, però non credo sia una cosa così importante.




Dipende da  ciò che si vuole fare, nella mia si lascia libero il chiamante di decidere (ad esempio, si voglia concedere solo 3 tentativi di immissione)

Per il resto... in questo caso, con le attuali risorse dei moderni pc, non credo cambi molto. in ambienti con poca memoria meglio la chiamata in più, in ambienti per alte prestazioni meglio le 2 variabili.
La mia era una domanda generica: Essendo liberi, e con risorse illimitate, cosa sarebbe più opportuno? risparmio di memoria o alte prestazioni?  

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 11:18
Mercoledì, 12/07/2017
Ah, malefico! Mi butti lì un altro grattacapo (il limite alla quantità dei tentativi)? Roba per un ulteriore parametro, però rimarrebbe la necessità di verificare se l'immissione è stata un'immissione valida o un annullamento e, per come mi piace far le cose, meno controlli mi trovo a dover fare nelle parti dove si realizza la "ciccia" del programma e più son contento. Ma, sia ben chiaro, è solo una questione di gusti.

La differenza in prestazioni quando si interagisce passo passo con chi sta tra schermo e tastiera penso si misuri in nanosecondi (ammesso che sia abbastanza grande da poterla misurare). Per conto mio la considero irrilevante.

Ora te lo do io un grattacapo: e se l'utente volesse annullare per evitare la scelta? Ad esempio si potrebbe proporre un "Sei un campione del ciclismo? (s/n/a)" dove "a" potrebbe stare per "annulla". In caso d'annullamento la funzione potrebbe restituire -1, per cui 1:vero, 0:falso, -1:annullamento. Ma son certo che a pensarci e ripensarci ci viene in mente ancora qualche altro dettaglio.

Ultima modifica effettuata da AldoBaldo il 12/07/2017 alle 11:25


ATTENZIONE! Sono un hobbista e l'affidabilità delle mie conoscenze informatiche è molto limitata. Non prendere come esempio il codice che scrivo, perché non ho alcuna formazione accademica e rischieresti di apprendere pratiche controproducenti.
PM Quote
Pagine: [ 1 2 3 ] Precedente | Prossimo