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++ - ANSI C: Difficoltà con validazione stretta in un programma per stabilire se un anno è bisestile
Forum - C/C++ - ANSI C: Difficoltà con validazione stretta in un programma per stabilire se un anno è bisestile

Pagine: [ 1 2 ] Precedente | Prossimo
Avatar
Anubi_Phantom (Normal User)
Newbie


Messaggi: 3
Iscritto: 21/11/2017

Segnala al moderatore
Postato alle 18:32
Martedì, 21/11/2017
Buonasera a tutti,
premetto che non sono esperta di programmazione.
Il testo dell'esercizio è il seguente: Scrivere un programma che, richiesto il numero AA rappresentante un anno, verifichi se questo è bisestile.
[Suggerimento: un anno è bisestile se è divisibile per 4 ma non per 100 (cioè si escludono gli anni-secolo).

Avendo studiato da poco la validazione stretta con do-while,ho deciso di arricchire questo semplice programmino usandola; il risultato è che,finché inserisco un anno normale (es. 2019 o 2012) funziona, ma se inserisco dei caratteri non succede nulla.. cosa posso aver sbagliato?

Di seguito posto il codice:
Codice sorgente - presumibilmente C++

  1. #include <stdio.h>
  2. #include <ctype.h>
  3.  
  4. int main(void)
  5. {
  6.     int n;
  7.     char carattere_rimosso;
  8.  
  9.     do
  10.     {
  11.  
  12.         printf("Digita un anno (AAAA): ");
  13.         scanf("%d", &n);
  14.  
  15.         /* Verifichiamo di aver inserito un numero e non altro */
  16.         if (ispunct(n) || isspace(n))
  17.         {
  18.             printf("Input non accettabile!!");
  19.            
  20.              do carattere_rimosso = getchar();
  21.  
  22.             while (carattere_rimosso != '\n');
  23.         }
  24.     }
  25.     while (ispunct(n) || isspace(n));
  26.  
  27.     /* Verifico che l'anno inserito sia bisestile */
  28.     /* Un anno è bisestile se è divisibile per 4 ma non per 100*/
  29.  
  30.     if (n % 4 == 0 && n % 100 != 0){
  31.  
  32.         printf("Hai digitato l'anno, %d, che è bisestile!!\n", n);
  33.     }
  34.  
  35.     else {
  36.         printf("L'anno inserito non è bisestile.\n");
  37.     }
  38.  
  39.     return (0);
  40. }



Grazie in anticipo a chi mi aiuterà :hail:

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 18:58
Martedì, 21/11/2017
Una scanf "%d" popola 4 byte, ovvero un intero con la rappresentazione in complemento a due del numero inserito.

Se si inserisce un carattere non so cosa accada, quello che ti posso dire è che il tuo è un approccio sbagliato.

Quello corretto è chiedere una serie di caratteri, controllare che siano una serie di numeri e convertirli in un intero, magari usando una funzione di libreria.

PM Quote
Avatar
Anubi_Phantom (Normal User)
Newbie


Messaggi: 3
Iscritto: 21/11/2017

Segnala al moderatore
Postato alle 19:03
Martedì, 21/11/2017
Quindi dovrei,se ho capito bene, rifare il programma da capo chiedendo in input l'anno in stringa?:-?

PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 19:42
Martedì, 21/11/2017
Quello che ricevi in input dalla console è sempre una stringa. Tutto sta a verificare che quella stringa corrisponda alle tue necessità PRIMA di convertirla in un valore numerico. A me viene in mente una cosa del genere, forse un po' "dispersiva" ma, credo, ragionevolmente sicura:

Codice sorgente - presumibilmente C++

  1. #include <stdlib.h>
  2. #include <stdio.h>
  3. #include <string.h>
  4. #include <ctype.h>
  5.  
  6. int chiedi_anno( void );
  7. int anno_valido( const char *s );
  8.  
  9. int main() {
  10.     int n = chiedi_anno();
  11.  
  12.     /* Verifico che l'anno inserito sia bisestile               **
  13.     ** Un anno è bisestile se è divisibile per 4 ma non per 100 */
  14.  
  15.     if( n%4 == 0 && n%100 != 0 )
  16.         printf( "Hai digitato l'anno, %d, che e' bisestile!!\n", n );
  17.     else printf( "L'anno inserito non e' bisestile.\n" );
  18.  
  19.     return (0);
  20. }
  21.  
  22. /*==============================================================================
  23. Chiede insistentemente l'immissione di un anno a quattro cifre. Il valore
  24. restituito e' sicuramente un valore numerico riconducibile a quattro cifre
  25. espresse secondo una numerazione a base 10.
  26. ==============================================================================*/
  27.  
  28. int chiedi_anno( void ) {
  29.     char buff[8];
  30.  
  31.     do { /* finche' non viene inserito un dato accettabile */
  32.         printf( "Digita un anno (AAAA): " );
  33.         fgets( buff, 8, stdin ); /* prelevo l'input come stringa */
  34.     } while( !anno_valido(buff) ); /* verifico l'input come stringa */
  35.  
  36.     /* ora che so che l'input e' certamente una stringa che rappresenta **
  37.     ** un numero a 4 cifre, converto l'anno in un vero valore numerico  */
  38.     return strtol( buff, NULL, 10 );
  39. }
  40.  
  41. /*==============================================================================
  42. Controlla che la stringa s contenga quattro cifre numeriche.
  43. In caso affermativo restituisce 1, altrimenti restituisce 0.
  44. ==============================================================================*/
  45.  
  46. int anno_valido( const char *s ) {
  47.     size_t l = strlen( s );
  48.  
  49.     if( '\n' == s[l-1] ) {
  50.         --l; /* elimina il new line dal conteggio dei caratteri */
  51.  
  52.         if( 4 == l ) {
  53.             int i;
  54.  
  55.             for( i=0; i<l; ++i )
  56.                 if( !isdigit(s[i]) )
  57.                     return 0;
  58.  
  59.             return 1; /* anno valido */
  60.         }
  61.         else {
  62.             return 0; /* anno non valido perche' non e' composto da 4 cifre */
  63.         }
  64.     }
  65.     else {
  66.         /* se arriviamo qui, significa che le dimensioni del buffer    **
  67.         ** erano insufficienti, per cui dobbiamo "svuotare" lo stream" */
  68.         while( getchar() != '\n' );
  69.         return 0; // anno non valido perche' composto da troppe cifre
  70.     }
  71. }



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
Anubi_Phantom (Normal User)
Newbie


Messaggi: 3
Iscritto: 21/11/2017

Segnala al moderatore
Postato alle 19:51
Martedì, 21/11/2017
Grazie mille!
Tra vari tentativi e ragionamenti, alla fine sono riuscita a eseguire il programma senza più problemi.

Molte delle funzioni di libreria che hai usato ancora non le abbiamo studiate purtroppo :d

Difatti ho modificato la validazione mettendo una variabile chiamata "esito":

Codice sorgente - presumibilmente C/C++

  1. do
  2.     {
  3.  
  4.         printf("Digita un anno (AAAA): ");
  5.         scanf("%d", &n);
  6.  
  7.         /* Verifichiamo di aver inserito un numero e non altro */
  8.         if ((esito == 0) || (n < 0))
  9.         {
  10.             printf("Input non accettabile!! \nb");
  11.            
  12.              do carattere_rimosso = getchar();
  13.  
  14.             while (carattere_rimosso != '\n');
  15.         }
  16.     }
  17.     while ((esito == 0) || (n < 0));



Ovviamente inizializzandola a intero all'inizio della main :D

PM Quote
Avatar
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 22:21
Martedì, 21/11/2017
Codice sorgente - presumibilmente Plain Text

  1. scanf("%d", &n);



No, è sbagliato. Tu vuoi ottenere una scringa, e POI convertirla in numero.

Codice sorgente - presumibilmente C++

  1. char anno[50];
  2. scanf("%s", &anno);
  3.  
  4.  
  5. bool annoValido = true;
  6. for (int i = 0; i < strlen((const char*)anno), i++)
  7.     if ((anno[i] < 47) || (anno[i] > 57)) {
  8.         annoValido = false;
  9.         break;
  10.     }
  11.  
  12. //prendo provvedimenti se annoValido è false
  13.  
  14. unsigned int n = atoi(anno);



Tu non puoi leggere un intero e poi controllare se è valido. Quel controllo devi farlo prima di avere il tuo intero.

PM Quote
Avatar
lumo (Member)
Expert


Messaggi: 449
Iscritto: 18/04/2010

Segnala al moderatore
Postato alle 18:24
Mercoledì, 22/11/2017
Ma che dici TheDarkJuster? La soluzione è corretta, anzi la tua ha un bel buffer overflow.
L'unica cosa che manca mi pare che sia
Codice sorgente - presumibilmente Plain Text

  1. esito = scanf("%d", &n);



Quando scanf fallisce, esito è 0 e il loop si ripete.

Ultima modifica effettuata da lumo il 22/11/2017 alle 18:25
PM Quote
Avatar
AldoBaldo (Member)
Guru


Messaggi: 699
Iscritto: 08/01/2015

Segnala al moderatore
Postato alle 19:28
Mercoledì, 22/11/2017
In effetti scanf( "%s", &anno ); con anno che è un array di char non ci sta proprio.

Però credo che a parte questo "dettaglio" (che tanto dettaglio non è, ma queste sviste possono scappare) nella sostanza abbia ragione Dark, perché Anubi voleva controllare che l'anno venisse immesso a quattro cifre, mentre la tua soluzione accetta anche numeri a una o a otto cifre senza segnalare errori. Anzi, penso che non segnali errori neppure se il numero è seguito da caratteri "spuri", dei quali credo che invece Anubi volesse evitare la presenza.

Io continuo a preferire fgets(), anche se richiede un po' di "macchinazioni" -- passa TUTTO quello che trova, poi sta a chi programma vedere che farne.


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
TheDarkJuster (Member)
Guru^2


Messaggi: 1620
Iscritto: 27/09/2013

Segnala al moderatore
Postato alle 19:30
Mercoledì, 22/11/2017
Non sapevo ritornasse 0 in caso di errore.:rofl: perdono

PM Quote
Pagine: [ 1 2 ] Precedente | Prossimo