Anubi_Phantom (Normal User)
Newbie
Messaggi: 3
Iscritto: 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++ |
#include <stdio.h> #include <ctype.h> int main(void) { int n; char carattere_rimosso; do { printf("Digita un anno (AAAA): "); scanf("%d", &n); /* Verifichiamo di aver inserito un numero e non altro */ if (ispunct(n) || isspace(n)) { printf("Input non accettabile!!"); do carattere_rimosso = getchar(); while (carattere_rimosso != '\n'); } } while (ispunct(n) || isspace(n)); /* Verifico che l'anno inserito sia bisestile */ /* Un anno è bisestile se è divisibile per 4 ma non per 100*/ if (n % 4 == 0 && n % 100 != 0){ printf("Hai digitato l'anno, %d, che è bisestile!!\n", n); } else { printf("L'anno inserito non è bisestile.\n"); } return (0); }
|
Grazie in anticipo a chi mi aiuterà
|
|
TheDarkJuster (Member)
Guru^2
Messaggi: 1620
Iscritto: 27/09/2013
|
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.
|
|
Anubi_Phantom (Normal User)
Newbie
Messaggi: 3
Iscritto: 21/11/2017
|
Quindi dovrei,se ho capito bene, rifare il programma da capo chiedendo in input l'anno in stringa?
|
|
AldoBaldo (Member)
Guru
Messaggi: 699
Iscritto: 08/01/2015
|
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++ |
#include <stdlib.h> #include <stdio.h> #include <string.h> #include <ctype.h> int chiedi_anno( void ); int anno_valido( const char *s ); int main() { int n = chiedi_anno(); /* Verifico che l'anno inserito sia bisestile ** ** Un anno è bisestile se è divisibile per 4 ma non per 100 */ if( n%4 == 0 && n%100 != 0 ) printf( "Hai digitato l'anno, %d, che e' bisestile!!\n", n ); else printf( "L'anno inserito non e' bisestile.\n" ); return (0); } /*============================================================================== Chiede insistentemente l'immissione di un anno a quattro cifre. Il valore restituito e' sicuramente un valore numerico riconducibile a quattro cifre espresse secondo una numerazione a base 10. ==============================================================================*/ int chiedi_anno( void ) { char buff[8]; do { /* finche' non viene inserito un dato accettabile */ printf( "Digita un anno (AAAA): " ); fgets( buff, 8, stdin ); /* prelevo l'input come stringa */ } while( !anno_valido(buff) ); /* verifico l'input come stringa */ /* ora che so che l'input e' certamente una stringa che rappresenta ** ** un numero a 4 cifre, converto l'anno in un vero valore numerico */ return strtol( buff, NULL, 10 ); } /*============================================================================== Controlla che la stringa s contenga quattro cifre numeriche. In caso affermativo restituisce 1, altrimenti restituisce 0. ==============================================================================*/ int anno_valido( const char *s ) { size_t l = strlen( s ); if( '\n' == s[l-1] ) { --l; /* elimina il new line dal conteggio dei caratteri */ if( 4 == l ) { int i; for( i=0; i<l; ++i ) if( !isdigit(s[i]) ) return 0; return 1; /* anno valido */ } else { return 0; /* anno non valido perche' non e' composto da 4 cifre */ } } else { /* se arriviamo qui, significa che le dimensioni del buffer ** ** erano insufficienti, per cui dobbiamo "svuotare" lo stream" */ while( getchar() != '\n' ); return 0; // anno non valido perche' composto da troppe cifre } }
|
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. |
|
Anubi_Phantom (Normal User)
Newbie
Messaggi: 3
Iscritto: 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
Difatti ho modificato la validazione mettendo una variabile chiamata "esito":
Codice sorgente - presumibilmente C/C++ |
do
{
printf("Digita un anno (AAAA): ");
scanf("%d", &n);
/* Verifichiamo di aver inserito un numero e non altro */
if ((esito == 0) || (n < 0))
{
printf("Input non accettabile!! \nb");
do carattere_rimosso = getchar();
while (carattere_rimosso != '\n');
}
}
while ((esito == 0) || (n < 0));
|
Ovviamente inizializzandola a intero all'inizio della main
|
|
TheDarkJuster (Member)
Guru^2
Messaggi: 1620
Iscritto: 27/09/2013
|
Codice sorgente - presumibilmente Plain Text |
No, è sbagliato. Tu vuoi ottenere una scringa, e POI convertirla in numero.
Codice sorgente - presumibilmente C++ |
char anno[50]; scanf("%s", &anno); bool annoValido = true; for (int i = 0; i < strlen((const char*)anno), i++) if ((anno[i] < 47) || (anno[i] > 57)) { annoValido = false; break; } //prendo provvedimenti se annoValido è false 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. |
|
lumo (Member)
Expert
Messaggi: 449
Iscritto: 18/04/2010
|
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 |
Quando scanf fallisce, esito è 0 e il loop si ripete.
Ultima modifica effettuata da lumo il 22/11/2017 alle 18:25 |
|
AldoBaldo (Member)
Guru
Messaggi: 699
Iscritto: 08/01/2015
|
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. |
|
TheDarkJuster (Member)
Guru^2
Messaggi: 1620
Iscritto: 27/09/2013
|
Non sapevo ritornasse 0 in caso di errore. perdono
|
|