Cos'è ElectroYou | Login Iscriviti

ElectroYou - la comunità dei professionisti del mondo elettrico

Programma in C: inserita una data, calcolare il giorno

Linguaggi e sistemi

Moderatori: Foto UtentePaolino, Foto Utentefairyvilje

0
voti

[1] Programma in C: inserita una data, calcolare il giorno

Messaggioda Foto UtenteLuigi97 » 7 nov 2017, 12:48

Salve, dovrei portare a termine un esercizio in linguaggio C dove viene richiesto di scrivere un programma che, inserita una data, calcoli a che giorno della settimana corrisponde.
Ciò che sono riuscito ad ideare è quanto segue:
Codice: Seleziona tutto
#include <stdio.h>

/*scrivere un programma che, inserita una data, calcoli il giorno della settimana*/

main() {
int k; /*variabile che serve per calcolare il giorno*/
int j; /*variabile che serve per calcolare se un anno è bistestile o no*/
int l; /*variabile che serve per calcolare se una data è valida o no*/
int scelta; /*varaibile che, una volta che il programma ha calcolato il giorno, permette all'utente di poter
continuare (dove per "continuare" si intede la possbilità di ricominciare con l'inserimento di una nuova data*/
int giorno_di_riferimento, mese_di_riferimento, anno_di_riferimento;
int giorno, mese, anno;

do {
/*data di riferimento*/   
giorno_di_riferimento=1; /*corrisponde a lunedì*/
mese_di_riferimento=1; /*corrisponde a gennaio*/
anno_di_riferimento=2017; /*corrisponde all'anno 2017*/
k=7; /*corrisponde a domenica*/
j=1; /*corrisponde al primo anno dopo l'anno bisestile del 2016*/
l=0; /*se tale variabile resta uguale a zero, allora significa che la data inserita è valida. Se tale variabile
risulta essere diversa da zero, allo significa che la data inserita non è valida*/

printf("Inserisci una data per sapere a quale giorno corrisponde\n");

do {
printf("Giorno: ");
scanf("%d", &giorno);
}while(giorno<1 || giorno>31);
do {
printf("Mese: ");
scanf("%d", &mese);
}while(mese<1 || mese>12);
do {
printf("Anno: ");
scanf("%d", &anno);
}while(anno<1);

if(giorno>29 && mese==2) {
l++;   
}

if(giorno==31) {
switch(mese) {
case 4: case 6: case 9: case 11:
l++;
break;

default:
break;   
}   
}

if(anno>=2017 && l==0) {
for( ; giorno_di_riferimento!=giorno || mese_di_riferimento!=mese || anno_di_riferimento!=anno; ) {
giorno_di_riferimento++;   
k++;
if(k>7) {
k=1;   
}
if(j>4) {
j=1;   
}

if(giorno_di_riferimento>28 && mese_di_riferimento==2 && j!=4) {
giorno_di_riferimento=1;
mese_di_riferimento++;
}
if(giorno_di_riferimento>29 && mese_di_riferimento==2 && j==4) {
giorno_di_riferimento=1;
mese_di_riferimento++;
}

if(giorno_di_riferimento>30) {
switch(mese_di_riferimento) {
case 4: case 6: case 9: case 11:   
giorno_di_riferimento=1;
mese_di_riferimento++;
break;

default:
break;   
}
}

if(giorno_di_riferimento>31) {
giorno_di_riferimento=1;
mese_di_riferimento++;
}

/*il ciclo if sottostante serve per calcolare gli anni*/
if(mese_di_riferimento==12 && giorno_di_riferimento==31 && giorno_di_riferimento!=giorno) {
mese_di_riferimento=0;   
anno_di_riferimento++;
j++;   
}

/*il ciclo if sottostante serve per capire se è stata inserita una data contente il 29 di febbraio in un anno non
bisestile. Se il ciclo if si attiva, allora "l" diventa diverso da zero, il ciclo for si interrompe e la data,
siccome "l" risulta essere diverso da zero, risulterà essere non valida*/
if(j==4 && giorno==29 && mese==2 && anno_di_riferimento>anno) {
l++;
break;   
}
}
}else if(anno<2017 && l==0) {   
for( ; giorno_di_riferimento!=giorno || mese_di_riferimento!=mese || anno_di_riferimento!=anno; ) {
giorno_di_riferimento--;   
k--;
if(k<1) {
k=7;   
}
if(j<1) {
j=4;   
}

if(giorno_di_riferimento<1 && mese_di_riferimento==3 && j!=4) {
giorno_di_riferimento=28;
mese_di_riferimento--;
}
if(giorno_di_riferimento<1 && mese_di_riferimento==3 && j==4) {
giorno_di_riferimento=29;
mese_di_riferimento--;
}

if(giorno_di_riferimento<1) {
switch(mese_di_riferimento) {
case 5: case 7: case 10: case 12:   
giorno_di_riferimento=30;
mese_di_riferimento--;
break;

default:
break;   
}
}

if(giorno_di_riferimento<1) {
giorno_di_riferimento=31;
mese_di_riferimento--;
}

if(mese_di_riferimento==0 && giorno_di_riferimento==31 && giorno_di_riferimento==giorno) {
mese_di_riferimento=12;   
anno_di_riferimento--;
j--;   
}
if(mese_di_riferimento==0 && giorno_di_riferimento==31 && giorno_di_riferimento!=giorno) {
mese_di_riferimento=12;   
anno_di_riferimento--;
j--;   
}

if(j==4 && giorno==29 && mese==2 && anno_di_riferimento<anno) {
l++;
break;   
}
}   
}

if(l==0) {
printf("\nLa data %d/%d/%d corrisponde a ", giorno, mese, anno);
switch(k) {
case 1:
printf("LUNEDI'");   
break;

case 2:
printf("MARTEDI'");   
break;

case 3:
printf("MERCOLEDI'");   
break;

case 4:
printf("GIOVEDI'");   
break;

case 5:
printf("VENERDI'");   
break;

case 6:
printf("SABATO");   
break;

case 7:
printf("DOMENICA");   
break;

default:
printf("\nERRORE\n");
break;   
}
}else {
printf("\nLa data inserita non e' valida.");   
}

printf("\n\n");

do {
printf("Digita 1 per continuare, 0 per finire: ");
scanf("%d", &scelta);
}while(scelta<0 || scelta>1);

printf("\n");

}while(scelta==1);

}

Spero che con i commenti si riesca a capire senza troppi sforzi. Il ciclo for che si attiva se l'anno inserito è minore di 2017 non l'ho commentato perché credo che quel ciclo for funzioni in modo corretto e che non influisca sull'errore che si verifica, quindi credo che non ci sia la necessità di analizzarlo.
Ho aperto questa discussione perché il programma non funziona e mi piacerebbe capire dov'è che ho sbagliato. Il problema è questo: quando inserisco una data contenente il 31 di dicembre con un anno maggiore di 2017, capita che il ciclo for è come se continuasse all'infinito... di conseguenza non viene fornito il giorno a cui tale data corrisponde. I giorni, con l'inserimento di date diverse dal 31 di dicembre con un anno maggiore di 2017, vengono calcoli correttamente (almeno quelli che ho testato io).
Dov'è che ho sbagliato?

Comunque, per risolvere tale esercizio, mi piacerebbe sapere anche se esistesse un metodo più semplice. Non chiedo di sapere qual è, vorrei solo sapere se esistesse.

P.S. se si attiva il ciclo if preceduto dal commento "il ciclo if sottostante serve per calcolare gli anni", la variabile mese_di_riferimento viene azzerata e non dichiarata al valore di 1 perché poi, la variabile giorno_di_riferimento, diventando maggiore di 31 al ciclo successivo del ciclo for, fa attivare il ciclo "if(giorno_di_riferimento>31)" e di conseguenza la variabile mese_di_riferimento viene incrementata, e siccome dopo l'incremento della variabile anno_di_riferimento la variabile mese_di_riferimento deve iniziare da 1, allora ecco che mese_di_riferimento, prima del ciclo "if(giorno_di_riferimento>31)" dopo che è stata incrementata la variabile anno_di_riferimento, deve valere zero.
Avatar utente
Foto UtenteLuigi97
40 4
 
Messaggi: 49
Iscritto il: 17 giu 2017, 16:35

0
voti

[2] Re: Programma in C: inserita una data, calcolare il giorno

Messaggioda Foto Utenteluxinterior » 7 nov 2017, 15:46

Sono calcoli piuttosoto insidiosi
Le mie prime ricerche in rete mi hanno portato a
http://www.geeksforgeeks.org/find-day-o ... iven-date/
e
https://en.wikipedia.org/wiki/Determina ... f_the_week
Avatar utente
Foto Utenteluxinterior
4.311 3 4 9
Master EY
Master EY
 
Messaggi: 2690
Iscritto il: 6 gen 2016, 17:48

0
voti

[3] Re: Programma in C: inserita una data, calcolare il giorno

Messaggioda Foto UtenteLuigi97 » 7 nov 2017, 15:55

luxinterior ha scritto:Sono calcoli piuttosoto insidiosi
Le mie prime ricerche in rete mi hanno portato a
http://www.geeksforgeeks.org/find-day-o ... iven-date/
e
https://en.wikipedia.org/wiki/Determina ... f_the_week

I link non li ho ancora aperti. Rispondo per riferire che nel programma precedente ho sbagliato a commentare la "data di riferimento"... posto sotto la versione corretta:
Codice: Seleziona tutto
/*data di riferimento che corrisponde a 1/1/2017*/   
giorno_di_riferimento=1;
mese_di_riferimento=1;
anno_di_riferimento=2017;

k=7; /*corrisponde a domenica*/
j=1; /*corrisponde al primo anno dopo l'anno bisestile del 2016*/
l=0; /*se tale variabile resta uguale a zero, allora significa che la data inserita è valida. Se tale variabile
risulta essere diversa da zero, allo significa che la data inserita non è valida*/

Chiedo scusa!
Avatar utente
Foto UtenteLuigi97
40 4
 
Messaggi: 49
Iscritto il: 17 giu 2017, 16:35

0
voti

[4] Re: Programma in C: inserita una data, calcolare il giorno

Messaggioda Foto UtenteGuidoB » 7 nov 2017, 17:06

Qualche mese fa avevo scritto una procedura che calcola il numero di giorni trascorsi dall'inizio del millennio (sabato 1/1/2000) fino alla data specificata in una stringa con formato "yyyymmdd", oppure fino alla data odierna se la stringa è NULL.

Una volta che si sanno i giorni trascorsi, dividendoli per 7 e tenendo il resto, si trova il giorno della settimana (0 = sabato, 1 = domenica, 2 = lunedì ecc.).

Fa' attenzione: la divisione tra numeri interi in C può dare un risultato diverso dalla divisione intera in altri linguaggi :roll: .

Contrariamente a quanto sarebbe più prevedibile e matematicamente comodo da utilizzare, i risultati vengono troncati verso lo zero, non arrotondati all'intero inferiore. Quindi certi risultati pari a 0 o negativi possono aver bisogno di essere diminuiti di 1 prima di essere utilizzati in calcoli successivi.
È un errore insidioso che potresti avere nel tuo programma, ed è meglio che controlli.

Ti lascio il mio codice, se può esserti utile:

Codice: Seleziona tutto
#include <time.h>
#include <string.h>

// ...

#define NOERROR                  0
#define ERROR_ILLEGAL_FORMAT    -1
#define ERROR_ILLEGAL_DATE      -2

// ...

/*******************************************************************************
Function:
int millenniumDays(char *yyyymmdd, long *days)

Parameters:
char *yyyymmdd       : date in yyyymmdd format
long *days           : to return elapsed days

Description:
gives the number of elapsed days from Saturday, January 1st, 2000 to the specified
date (not included), or until today (not included) if the yyyymmdd string is NULL.

Return values:
NOERROR              : correct execution
ERROR_ILLEGAL_FORMAT : the input string has an illegal format
ERROR_ILLEGAL_DATE   : the input date is out of bounds or incorrect

Notes:
works from 1900-03-01 to 2100-02-28.
Returns negative values for dates before 2000-01-01.
*******************************************************************************/

int millenniumDays(char *yyyymmdd, long *days)
{
    int bError = NOERROR;

    if (yyyymmdd == NULL)
    {
        // Calculate elapsed days from 2000-01-01 until today (not included):
        const int secondsInADay                  = 86400;
        const int daysFrom1970_01_01To2000_01_01 = 10957;

        // Works only for system dates from 1970 onward
        //(otherwise truncation toward 0 instead of floor in C99 integer division must be taken into account):
        *days = (time(NULL) / secondsInADay - daysFrom1970_01_01To2000_01_01);
    }
    else
    {
        // Calculate elapsed days from 2000-01-01 until yyyymmdd date (not included):
        const int monthDays              [12] = {31,  28,  31,  30,  31,  30,  31,  31,  30,  31,  30,  31};
        const int sumOfPreviousMonthsDays[12] = { 0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334};
        int       year, month, day;

        if ((strspn(yyyymmdd, "0123456789") == 8)
            &&
            (yyyymmdd[8] == '\0'))
        {
            year  = (yyyymmdd[0] - '0') * 1000 + (yyyymmdd[1] - '0') * 100 + (yyyymmdd[2] - '0') * 10 + (yyyymmdd[3] - '0');
            month = (yyyymmdd[4] - '0') *   10 + (yyyymmdd[5] - '0');
            day   = (yyyymmdd[6] - '0') *   10 + (yyyymmdd[7] - '0');

            // If it is an acceptable date:
            if ((((year > 1900) && (year < 2100)) || ((year == 1900) && (month >= 3)) || ((year == 2100) && (month <= 2)))
                &&
                ((month >= 1) && (month <= 12))
                &&
                ((day >= 1) && ((day <= monthDays[month - 1]) || ((day == 29) && ((year % 4) == 0) && (year != 2100)))))
            {
                // Calculate year and month days, withouth adjusting for leap years for the moment:
                *days  = (year - 2000) * 365 + sumOfPreviousMonthsDays[month - 1];

                // Adjust for leap years and add day-of-month days:
                // (*days - 32..58) / (365 * 4): anything works between 32 and 58 to distinguish between February and March,
                //                               to add one day every 4 years, but only from March onward.
                // - (*days < 32..58): is needed because C99 integer division does not floor the result, but truncates it toward 0.
                *days += (*days - 32) / (365 * 4) - (*days < 32) + day;
            }
            else
            {
                bError = ERROR_ILLEGAL_DATE;
            }
        }
        else
        {
            bError = ERROR_ILLEGAL_FORMAT;
        }
    }

    return bError;
}

// ...
Big fan of ƎlectroYou!       Ausili per disabili e anziani su ƎlectroYou
Caratteri utili: À È É Ì Ò Ó Ù α β γ δ ε η θ λ μ π ρ σ τ φ ω Ω º ª ² ³ √ ∛ ∜ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ∃ ∄ ∆ ∈ ∉ ± ∓ ∾ ≃ ≈ ≠ ≤ ≥
Avatar utente
Foto UtenteGuidoB
17,8k 7 12 13
G.Master EY
G.Master EY
 
Messaggi: 2809
Iscritto il: 3 mar 2011, 16:48
Località: Madrid

0
voti

[5] Re: Programma in C: inserita una data, calcolare il giorno

Messaggioda Foto UtenteLuigi97 » 7 nov 2017, 23:57

GuidoB ha scritto:Una volta che si sanno i giorni trascorsi, dividendoli per 7 e tenendo il resto, si trova il giorno della settimana (0 = sabato, 1 = domenica, 2 = lunedì ecc.).

Fa' attenzione: la divisione tra numeri interi in C può dare un risultato diverso dalla divisione intera in altri linguaggi :roll: .

Contrariamente a quanto sarebbe più prevedibile e matematicamente comodo da utilizzare, i risultati vengono troncati verso lo zero, non arrotondati all'intero inferiore. Quindi certi risultati pari a 0 o negativi possono aver bisogno di essere diminuiti di 1 prima di essere utilizzati in calcoli successivi.
È un errore insidioso che potresti avere nel tuo programma, ed è meglio che controlli.

Grazie, non lo sapevo :-)

GuidoB ha scritto:Ti lascio il mio codice, se può esserti utile:

Codice: Seleziona tutto
#include <time.h>
#include <string.h>

// ...

#define NOERROR                  0
#define ERROR_ILLEGAL_FORMAT    -1
#define ERROR_ILLEGAL_DATE      -2

// ...

/*******************************************************************************
Function:
int millenniumDays(char *yyyymmdd, long *days)

Parameters:
char *yyyymmdd       : date in yyyymmdd format
long *days           : to return elapsed days

Description:
gives the number of elapsed days from Saturday, January 1st, 2000 to the specified
date (not included), or until today (not included) if the yyyymmdd string is NULL.

Return values:
NOERROR              : correct execution
ERROR_ILLEGAL_FORMAT : the input string has an illegal format
ERROR_ILLEGAL_DATE   : the input date is out of bounds or incorrect

Notes:
works from 1900-03-01 to 2100-02-28.
Returns negative values for dates before 2000-01-01.
*******************************************************************************/

int millenniumDays(char *yyyymmdd, long *days)
{
    int bError = NOERROR;

    if (yyyymmdd == NULL)
    {
        // Calculate elapsed days from 2000-01-01 until today (not included):
        const int secondsInADay                  = 86400;
        const int daysFrom1970_01_01To2000_01_01 = 10957;

        // Works only for system dates from 1970 onward
        //(otherwise truncation toward 0 instead of floor in C99 integer division must be taken into account):
        *days = (time(NULL) / secondsInADay - daysFrom1970_01_01To2000_01_01);
    }
    else
    {
        // Calculate elapsed days from 2000-01-01 until yyyymmdd date (not included):
        const int monthDays              [12] = {31,  28,  31,  30,  31,  30,  31,  31,  30,  31,  30,  31};
        const int sumOfPreviousMonthsDays[12] = { 0,  31,  59,  90, 120, 151, 181, 212, 243, 273, 304, 334};
        int       year, month, day;

        if ((strspn(yyyymmdd, "0123456789") == 8)
            &&
            (yyyymmdd[8] == '\0'))
        {
            year  = (yyyymmdd[0] - '0') * 1000 + (yyyymmdd[1] - '0') * 100 + (yyyymmdd[2] - '0') * 10 + (yyyymmdd[3] - '0');
            month = (yyyymmdd[4] - '0') *   10 + (yyyymmdd[5] - '0');
            day   = (yyyymmdd[6] - '0') *   10 + (yyyymmdd[7] - '0');

            // If it is an acceptable date:
            if ((((year > 1900) && (year < 2100)) || ((year == 1900) && (month >= 3)) || ((year == 2100) && (month <= 2)))
                &&
                ((month >= 1) && (month <= 12))
                &&
                ((day >= 1) && ((day <= monthDays[month - 1]) || ((day == 29) && ((year % 4) == 0) && (year != 2100)))))
            {
                // Calculate year and month days, withouth adjusting for leap years for the moment:
                *days  = (year - 2000) * 365 + sumOfPreviousMonthsDays[month - 1];

                // Adjust for leap years and add day-of-month days:
                // (*days - 32..58) / (365 * 4): anything works between 32 and 58 to distinguish between February and March,
                //                               to add one day every 4 years, but only from March onward.
                // - (*days < 32..58): is needed because C99 integer division does not floor the result, but truncates it toward 0.
                *days += (*days - 32) / (365 * 4) - (*days < 32) + day;
            }
            else
            {
                bError = ERROR_ILLEGAL_DATE;
            }
        }
        else
        {
            bError = ERROR_ILLEGAL_FORMAT;
        }
    }

    return bError;
}

// ...

Al momento alcune cose non le capisco (devo rivedermi un po' le stringhe e le funzioni). Comunque quando vado a compilare il programma che avete postato, esso mi dà un errore. Capita anche a voi?
Avatar utente
Foto UtenteLuigi97
40 4
 
Messaggi: 49
Iscritto il: 17 giu 2017, 16:35

2
voti

[6] Re: Programma in C: inserita una data, calcolare il giorno

Messaggioda Foto UtenteIlGuru » 8 nov 2017, 0:13

Vi hanno mai parlato dell'indentazione?
\Gamma\nu\tilde{\omega}\theta\i\ \sigma\epsilon\alpha\upsilon\tau\acute{o}\nu
Avatar utente
Foto UtenteIlGuru
5.482 2 10 13
G.Master EY
G.Master EY
 
Messaggi: 1924
Iscritto il: 31 lug 2015, 23:32

0
voti

[7] Re: Programma in C: inserita una data, calcolare il giorno

Messaggioda Foto UtenteGuidoB » 8 nov 2017, 0:58

Luigi97 ha scritto:Comunque quando vado a compilare il programma che avete postato, esso mi dà un errore. Capita anche a voi?

Ho postato solo la funzione. Bisogna scrivere il main() che la chiama (e che le passa parametri fissi o letti dall'utente, come hai fatto nel tuo programma).
Big fan of ƎlectroYou!       Ausili per disabili e anziani su ƎlectroYou
Caratteri utili: À È É Ì Ò Ó Ù α β γ δ ε η θ λ μ π ρ σ τ φ ω Ω º ª ² ³ √ ∛ ∜ ₀ ₁ ₂ ₃ ₄ ₅ ₆ ∃ ∄ ∆ ∈ ∉ ± ∓ ∾ ≃ ≈ ≠ ≤ ≥
Avatar utente
Foto UtenteGuidoB
17,8k 7 12 13
G.Master EY
G.Master EY
 
Messaggi: 2809
Iscritto il: 3 mar 2011, 16:48
Località: Madrid

0
voti

[8] Re: Programma in C: inserita una data, calcolare il giorno

Messaggioda Foto UtenteLuigi97 » 8 nov 2017, 9:42

GuidoB ha scritto:Ho postato solo la funzione. Bisogna scrivere il main() che la chiama (e che le passa parametri fissi o letti dall'utente, come hai fatto nel tuo programma).

Ho capito.
Grazie ancora :-)
Avatar utente
Foto UtenteLuigi97
40 4
 
Messaggi: 49
Iscritto il: 17 giu 2017, 16:35


Torna a PC e informatica

Chi c’è in linea

Visitano il forum: Nessuno e 24 ospiti