Esercizio sulle date

di il
15 risposte

Esercizio sulle date

Ciao a tutti!
Sono in difficoltà con questo esercizio in linguaggio C.
Ecco il testo dell'esercizio :

Nel file formato.c definire la funzione corrispondente alla seguente dichiarazione:

extern int is_date( const char *s);

La funzione accetta una stringa zero terminata e deve verificare se rispetta il formato di una data in cui il giorno e il mese sono rappresentati da due cifre, l'anno da quattro cifre e sono separati dal carattere '/'. La funzione ritorna 1 se il formato è corretto, 0 se il puntatore è NULL o se la stringa non rispetta il formato indicato.
Non tenere conto della non validità dei mesi e dei giorni.. Per esempio la data 87/56/2015 è corretta lo stesso, quindi deve ritornare 1 lo stesso.

Allora il codice che ho scritto è il seguente :

#include <string.h>

Int is_date (const char *s)
{
      Int i = 0;
      if( s == NULL) 
            return 0;

      if( strlen(s) != 10)
            return 0;

     for( i=0; s[i] != '\0'; i++)
     {
           if( s[i] == '/')
           {
                 if( s[i-3] == NULL || s[i-3] == '/')
                     return 1;
                 else
                     return 0;
          }
     }
}
Il compilatore mi da due errori :
1) perché is_date non ritorna un valore di ritorno per ogni condizione
2) perché '==' e 'int' differiscono da void nella riga che ritengo la più sbagliata, cioè

if( s[i-3] == NULL || s[i-3] == '/')
Dove è che sbaglio?

Inoltre vi volevo chiedere una cosa..
Se la mia stringa è aa/aa/aaaa il compilatore mi dovrebbe dare corretto (non ho provato..)
Come faccio a dire di guardare solo quelle stringhe formate da numeri e non da caratteri ??

Nell'attesa di una vostra cordiale risposta vi ringrazio anticipatamente .

15 Risposte

  • Re: Esercizio sulle date

    La verifica di condizione if (s[i-3]==NULL)...
    contiene un doppio errore: quando i assume valori da 0 a 2,
    la funzione va a leggere valori in memoria che precedono l'inizio
    della stringa puntata da s, cosa priva di senso;
    inoltre NULL di solito e' assegnato solo a variabili puntatore,
    non a caratteri di stringhe (infatti, il mio compilatore gcc
    segnala un warning).

    Forse con questa condizione volevi
    rappresentare il caso in cui il carattere s si trova al terzo posto
    della stringa; se e' cosi', la condizione dovrebbe essere
    if (i==2)...; la funzione sarebbe comunque errata, perche'
    al verificarsi della condizione suddetta renderebbe in uscita 1,
    senza verificare se e dove si trova la seconda barra /.

    Inoltre la funzione non verifica quante cifre e quante barre ci sono
    e la presenza di caratteri estranei.

    Io risolverei cosi':

    se il puntatore s e' NULL rendi in uscita 0;

    se il numero di caratteri della stringa puntata da s
    e' diverso da 10 rendi in uscita 0;

    conta (con un ciclo) quante cifre e quante barre / ci sono;
    per verificare se un carattere e' una cifra si usa isdigit();

    le cifre devono essere 8 e le barre 2; in caso contrario
    rendi in uscita 0;

    con un altro ciclo, verifica se le 2 barre si trovano al terzo e sesto posto;
    in caso contrario rendi in uscita 0;

    se arrivi fin qui, rendi in uscita 1.

    Il tipo di dato numero intero deve essere indicato con int (non Int).
  • Re: Esercizio sulle date

    Ciao! Innanzitutto grazie per la risposta !
    Allora ho capito un po' i miei errori ed ho cercato di sistemare il codice come mi hai detto tu..
    Ecco il codice sistemato:
    
    #include <string.h>
    #include <ctype.h>
    
    Int is_date (const char *s)
    {
          int i = 0;
          int j = 0;
          int z = 0;
          if( s == NULL) 
                return 0;
    
          if( strlen(s) != 10)
                return 0;
    
         for( i=0; s[i] != '\0'; i++)
         {
               if( isdigit(s[i]))
                  z++;
    
               if( s[i] == '/')
                 j++;   
         }
    
         if( z != 8 && i != 5)
              return 0;
    
          for ( i = 0; s[i] != '\0'; i++)
          {
                  if( s[i] == '/')
                  {
                       if(i != 2 && i != 5)
                            return 0;
                   }
           }
           return 1;
    }
    
    Come vedi ho usato la libreria ctype.h per poter usare la funzione " isdigit" .. Però questa libreria non è stata fatta durante il corso che ho frequentato.. E non vorrei che durante l'esame il prof non la volesse .. C'è un altro metodo per guardare solo le stringhe formate da numeri e non da caratteri?

    Adesso il compilatore non mi da nessun problema..
    Però se inserisco la stringa "aa/aa/aaaaa" mi da 1, cioè che la stringa è una data corretta..
    Mi potresti dire dove sbaglio nuovamente ?
    Scusa il disturbo!
  • Re: Esercizio sulle date

    Salve

    Main(void)95 ha scritto:


    se inserisco la stringa "aa/aa/aaaaa" mi da 1, cioè che la stringa è una data corretta..
    Ne sei sicuro? La lunghezza della stringa è diversa da 10 quindi dovrebbe ritornare 0. Che compilatore usi?
    
    if( z != 8 && i != 5)
              return 0;
    
    Poi non capisco perché appena fuori dal primo ciclo for controlli i, sarà sicuramente diversa da 5 appena uscita dal ciclo.
    Se posso darti un consiglio potresti controllare con un solo ciclo for quanti numeri e slash sono presenti nella stringa.
  • Re: Esercizio sulle date

    Ciao! Grazie della risposta!

    Ne sei sicuro? La lunghezza della stringa è diversa da 10 quindi dovrebbe ritornare 0. Che compilatore usi?
    Scusami tanto! Ma ho messo una a di troppo .. La stringa è aa/aa/aaaa.

    Ho seguito i tuoi consigli e ho corretto il mio codice. Adesso sembra ( e dico sembra..) che funzioni
    Ecco il codice.
    
    
    #include <string.h>
    #include <ctype.h>
    
    Int is_date (const char *s)
    {
          int i = 0;
          int j = 0;
          int z = 0;
          if( s == NULL) 
                return 0;
    
          if( strlen(s) != 10)
                return 0;
    
         for( i=0; s[i] != '\0'; i++)
         {
               if( isdigit(s[i]))
                  z++;
    
               if( s[i] == '/')
               {
                     if( i != 2 && i != 5)
                           return 0;
                  j++;  
                } 
         }
    
         if( z != 8 || i != 5)
              return 0;
    
          return 1;
    }
    
    È giusto?
    Ho provato ad inserire le seguenti date e mi da corretto:
    - 23/07/2015 ritorna 1
    - 27/07/abcd ritorna 0
    - 2013/78/34 ritorna 0
    - 27-07-2015 ritorna 0
    - 89/34/1993 ritorna 1

    Spero che il codice sia corretto..
    Grazie mille a tutti! E se qualcuno sa qualcosa del mio dubbio di prima..
    Cioè se esiste un altro metodo invece di usare la funzione "isdigit" ...
    Grazie ancora!
  • Re: Esercizio sulle date

    Puoi migliorarlo ancora: rimuovi le variabili j e z.
    Riguardo al discorso della isdigit puoi controllare anche così:
    
    if(stringa[i] < '0' || stringa[i] > '9')
    {
    	return 0;
    }
    
  • Re: Esercizio sulle date

    Scusa @Main, ma controllare se e' una data NON BASTA che abbia il formato

    dd/dd/dddd

    dove d e' un digit, cioe' una cifra tra 0 e 9.

    E, si, puoi sostituire isdigit con una tua funzione che fa ESATTAMENTE la stessa cosa !!!!

    Ma il problema NON E' LI!!!!!

    Secondo la tua logica 89/34/9999 risulta essere una data VALIDA
    Mentre l'anno 9999 e' un po' in la da venire, ma e' un anno plausibile, il giorno 89 ed il mese 34 DECISAMENTE NON SONO VALIDI.

    Quindi:

    1) devi controllare se la striga passata ha un FORMATO VALIDO , e cioe', appunto:

    dd/dd/dddd

    2) a questo punto devi controllare se e' una DATA VALIDA, e cioe':

    gg/mm/aaaa

    dove

    2.1) aaaa e' un anno valido,
    2.2) mm e' un mese valido cioe' un numero tra 1 e 12
    2.3) gg e' un giorno valido che dipende dal MESE:

    trenta di conta novembre con april, giugno e settembre, ...

    E DALL'ANNO perche' ci sono anche gli anni bisestili !!!!

    3) se vuoi fare le cose fighe allora, la tua data e' valida SOLO dal 15 ottobre 1582

    15/10/1582


    inizio del calendario Gregoriano che e' il calendario che utilizziamo in questo momento!!!
  • Re: Esercizio sulle date

    Main(void)95 ha scritto:


    Non tenere conto della non validità dei mesi e dei giorni.. Per esempio la data 87/56/2015 è corretta lo stesso, quindi deve ritornare 1 lo stesso.
    Il suo docente non ha richiesto il controllo sulla validità effettiva delle date.
  • Re: Esercizio sulle date

    Wolt ha scritto:


    Puoi migliorarlo ancora: rimuovi le variabili j e z.
    Riguardo al discorso della isdigit puoi controllare anche così:
    
    if(stringa[i] < '0' || stringa[i] > '9')
    {
    	return 0;
    }
    
    Ho capito grazie mille! Molto gentile!

    migliorabile ha scritto:


    Scusa @Main, ma controllare se e' una data NON BASTA che abbia il formato

    dd/dd/dddd

    dove d e' un digit, cioe' una cifra tra 0 e 9.

    E, si, puoi sostituire isdigit con una tua funzione che fa ESATTAMENTE la stessa cosa !!!!

    Ma il problema NON E' LI!!!!!

    Secondo la tua logica <a href="tel:89/34/9999">89/34/9999</a> risulta essere una data VALIDA
    Mentre l'anno 9999 e' un po' in la da venire, ma e' un anno plausibile, il giorno 89 ed il mese 34 DECISAMENTE NON SONO VALIDI.

    Quindi:

    1) devi controllare se la striga passata ha un FORMATO VALIDO , e cioe', appunto:

    dd/dd/dddd

    2) a questo punto devi controllare se e' una DATA VALIDA, e cioe':

    gg/mm/aaaa

    dove

    2.1) aaaa e' un anno valido,
    2.2) mm e' un mese valido cioe' un numero tra 1 e 12
    2.3) gg e' un giorno valido che dipende dal MESE:

    trenta di conta novembre con april, giugno e settembre, ...

    E DALL'ANNO perche' ci sono anche gli anni bisestili !!!!

    3) se vuoi fare le cose fighe allora, la tua data e' valida SOLO dal 15 ottobre 1582

    15/10/1582


    inizio del calendario Gregoriano che e' il calendario che utilizziamo in questo momento!!!

    Wolt ha scritto:


    Main(void)95 ha scritto:


    Non tenere conto della non validità dei mesi e dei giorni.. Per esempio la data <a href="tel:87/56/2015">87/56/2015</a> è corretta lo stesso, quindi deve ritornare 1 lo stesso.
    Il suo docente non ha richiesto il controllo sulla validità effettiva delle date.
    Si scusate ma l'ho menzionato solo all'inizio del post, quando ho scritto il testo dell'esercizio..
    Il mio prof ha esplicitato di tenere conto tutte le date (anche quelle con mesi e giorni non validi) basta che siano nel formato aa/aa/aaaa.
    Grazie a tutti!
  • Re: Esercizio sulle date

    Allora non si dovrebbe parlare di date

    Ma se completi l'esercizio in modo corretto, verrai giustiziato?

    Se si, dimmi quando e dove, e vengo alla tua esecuzione
  • Re: Esercizio sulle date

    migliorabile ha scritto:


    Allora non si dovrebbe parlare di date

    Ma se completi l'esercizio in modo corretto, verrai giustiziato?

    Se si, dimmi quando e dove, e vengo alla tua esecuzione
    Nono non vengo giustiziato ahah
    Però il testo l'ha inventato il prof mica io. Se lui l'ha reso un po' più semplice un motivo ci sarà. Altrimenti, come hai detto giustamente te, bisognerebbe tenere conto degli anni bisestili, dell'inizio dell'anno Gregoriano, eccetera.. Eh per me sarebbe complicato.. Visto che sono alle basi del linguaggio C.
    Se ti va puoi farlo. Io mi fermo qui.
    Grazie ancora a tutti! Mi rifarò vivo con nuovi esercizi..
  • Re: Esercizio sulle date

    Mi riferisco alla seconda versione della funzione (post delle 10,09).

    La terzultima riga "if (z!=8 || i!=5)"
    contiene il confronto "i!=5" che ha sempre valore vero (1),
    infatti dopo l'esecuzione del ciclo i vale 10
    (a meno che il ciclo non sia stato interrotto in anticipo
    per il "return 0" interno al ciclo, ma in questo caso il confronto
    in oggetto non viene fatto).

    La funzione cosi' formulata rende sempre in uscita il valore 0.

    Quindi bisogna togliere il confronto "i!=5",
    ottenendo "if (z!=8) return 0", che verifica che le cifre siano 8.

    Ma non basta.

    La verifica della condizione "if(i!=2 && i!=5)"
    segnala - giustamente - la presenza di una barra fuori posto,
    cosi' la funzione rende in uscita 0.

    Pero' non viene rilevata l'assenza di una o di entrambe le barre;
    il contatore di barre j viene correttamente incrementato,
    ma non viene poi utilizzato.

    Cosi' la funzione rende in uscita 1 anche in caso di stringhe-non-data,
    come 24y07/2015, 24z07/2015, 24u07e2015, 12345678aa; le cifre sono sempre 8,
    ma le barre non sono 2.

    Per eliminare l'inconveniente, bisogna aggiungere il confronto "j!=2"
    nella terzultima riga: "if (z!=8 || j!=2)"; cosi' viene verificato
    che ci siano 8 cifre e 2 barre.

    Se non puoi usare isdigit(), puoi creare tu una funzione analoga,
    come questa:
    
    int cifra(char carattere)
     {
      if (carattere=='0') return 1;
      if (carattere=='1') return 1;
      if (carattere=='2') return 1;
      if (carattere=='3') return 1;
      if (carattere=='4') return 1;
      if (carattere=='5') return 1;
      if (carattere=='6') return 1;
      if (carattere=='7') return 1;
      if (carattere=='8') return 1;
      if (carattere=='9') return 1;
      return 0;
     } 
    
    Se il professore non consente di creare una funzione simile,
    puoi inserire le verifiche nella funzione is_date().

    Il metodo di Wolt va bene, ma ipotizzo che potrebbe ridurre la portabilita'
    della funzione in ambienti che non usano il codice ASCII.

    Secondo me, e' meglio usare per le variabili dei nomi esplicativi,
    che ne illustrino l'impiego. Ad es., il contatore di cifre invece di z
    potrebbe chiamarsi n_cifre, num_cifre e simili.
    In questo modo i programmi diventano piu' leggibili e questo facilita
    le cose sia all'autore che agli altri.
  • Re: Esercizio sulle date

    Credevo avesse rimosso quell' if e quindi non ci ho fatto caso.... Comunque se ha seguito il mio consiglio di rimuovere z e j non dovrebbero esserci più problemi.

    Korr ha scritto:


    Il metodo di Wolt va bene, ma ipotizzo che potrebbe ridurre la portabilita'
    della funzione in ambienti che non usano il codice ASCII.
    Ad esempio?
  • Re: Esercizio sulle date

    Korr ha scritto:


    Mi riferisco alla seconda versione della funzione (post delle 10,09).

    La terzultima riga "if (z!=8 || i!=5)"
    contiene il confronto "i!=5" che ha sempre valore vero (1),
    infatti dopo l'esecuzione del ciclo i vale 10
    (a meno che il ciclo non sia stato interrotto in anticipo
    per il "return 0" interno al ciclo, ma in questo caso il confronto
    in oggetto non viene fatto).

    La funzione cosi' formulata rende sempre in uscita il valore 0.

    Quindi bisogna togliere il confronto "i!=5",
    ottenendo "if (z!=8) return 0", che verifica che le cifre siano 8.

    Ma non basta.

    La verifica della condizione "if(i!=2 && i!=5)"
    segnala - giustamente - la presenza di una barra fuori posto,
    cosi' la funzione rende in uscita 0.

    Pero' non viene rilevata l'assenza di una o di entrambe le barre;
    il contatore di barre j viene correttamente incrementato,
    ma non viene poi utilizzato.

    Cosi' la funzione rende in uscita 1 anche in caso di stringhe-non-data,
    come 24y07/2015, 24z07/2015, 24u07e2015, 12345678aa; le cifre sono sempre 8,
    ma le barre non sono 2.

    Per eliminare l'inconveniente, bisogna aggiungere il confronto "j!=2"
    nella terzultima riga: "if (z!=8 || j!=2)"; cosi' viene verificato
    che ci siano 8 cifre e 2 barre.
    Ops si in effetti hai ragione... Il confronto con i non c'entra niente.
    Grazie mille Korr! Adesso speriamo che funzioni per tutte le date possibili! Ahah
    Stupido esercizio.. Eh per fortuna che vale SOLO 5 punti..

    Korr ha scritto:


    Se non puoi usare isdigit(), puoi creare tu una funzione analoga,
    come questa:
    
    int cifra(char carattere)
     {
      if (carattere=='0') return 1;
      if (carattere=='1') return 1;
      if (carattere=='2') return 1;
      if (carattere=='3') return 1;
      if (carattere=='4') return 1;
      if (carattere=='5') return 1;
      if (carattere=='6') return 1;
      if (carattere=='7') return 1;
      if (carattere=='8') return 1;
      if (carattere=='9') return 1;
      return 0;
     } 
    
    Grazie ! Preferisco questo metodo invece di usare la funzione isdigit.. Anche se però a dire il vero è molto più comoda .. Però non l'abbiamo fatta..
    Riguardo le variabili si hai ragione.. Dovrei chiamarle con un nome più significativo e specifico della loro funzione..
    Grazie mille di tutto!
  • Re: Esercizio sulle date

    Korr ha scritto:


    ...
    Il metodo di Wolt va bene, ma ipotizzo che potrebbe ridurre la portabilita'
    della funzione in ambienti che non usano il codice ASCII.
    ...
    @Korr, ti sconsiglio di dare consigli se non hai ben chiaro di cosa stai parlando.
    L'encoding e' un argomento abbastanza compresso, e non si limita all'ASCII.

    Ma non solo, a meno di non scrivere applicazioni per piattaformte IBM in EBCDIC (sistemi degli anni '50-'60), praticamente qualunque sistema di encoding con cui avrai a che fare supporta nativamente l'ASCII.

    E nei sistemi IBM, non usi il C, ma COBOL, RPG, JCL, ...!!!

    Quindi, il problema non si pone!

    Inoltre, poiche' usi l'ASCII, per controllare su un carattere e' una cifra, il codice che hai proposto e' abbondantemente inefficiente.

    Basta scrivere:
    
    int isdigit(int ch)
    {
        return '0' <= ch && ch <= '9';
    }
    
    Il tuo codice fa un minimo di 1 ed un massimo di 9 test, con una media di 5 test, per controllare se un carattere e' una cifra.
    Il codice postato qui, fa SOLO 2 test, cioe' mediamente 2.5 volte piu' efficiente.

    Ora, ovviamente in un esercizio per la scuola, non ha nessun impatto pratico. Ma se scrivi un'applicazione che deve processare milioni o miliardi di dati, la tua implementazione rallenterebbe inutilmente l'applicazione.
Devi accedere o registrarti per scrivere nel forum
15 risposte