3
\$\begingroup\$

This program is supposed to determine the day of the week for 2015. Could someone tell me how I could shorten my code?

#include <stdio.h>
#include <conio.h>


void findDay(int , int);


int main(void)
{
int jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec;


for(jan=1; jan<=31; ++jan)
{
    printf(" 01/%d/2015 is", jan);
    findDay(jan, 0);
}
for(feb=1; feb<=28; ++feb)
{
    printf("02/%d/2015 is", feb);
    findDay(feb, 3);
}
for(mar=1; mar<=31; ++mar)
{
    printf("03/%d/2015 is", mar);
    findDay(mar, 3);
}
for(apr=1; apr<=30; ++apr)
{
    printf("04/%d/2015 is", apr);
    findDay(apr, 6);
}
for(may=1; may<=31; ++may)
{
    printf("05/%d/2015 is", may);
    findDay(may, 1);
}
for(jun=1; jun<=30; ++jun)
{
    printf("06/%d/2015 is", jun);
    findDay(jun, 4);
}
for(jul=1; jul<=31; ++jul)
{
    printf("07/%d/2015 is", jul);
    findDay(jul, 6);
}
for(aug=1; aug<=31; ++aug)
{
    printf("08/%d/2015 is", aug);
    findDay(aug, 2);
}
for(sep=1; sep<=30; ++sep)
{
    printf("09/%d/2015 is", sep);
    findDay(sep, 5);
}
for(oct=1; oct<=31; ++oct)
{
    printf("10/%d/2015 is", oct);
    findDay(oct, 0);
}
for(nov=1; nov<=30; ++nov)
{
    printf("11/%d/2015 is", nov);
    findDay(nov, 3);
}
for(dec=1; dec<=31; ++dec)
{
    printf("12/%d/2015 is", dec);
    findDay(dec, 5);
}

getch();
return 0;
}
void findDay(int dow, int num)
{
int x;
x=(6+15+3+dow+num)%7;//a formula to calculate the day of the week


switch (x)
{
case 0:
printf(" Sunday\n");
break;
case 1:
printf(" Monday\n");
break;
case 2:
printf(" Tuesday\n");
break;
case 3:
printf(" Wednesday\n");
break;
case 4:
printf(" Thursday\n");
break;
case 5:
printf(" Friday\n");
break;
case 6:
printf(" Saturday\n");
break;
default:
printf("Invalid Input");

}

}
\$\endgroup\$
0

3 Answers 3

2
\$\begingroup\$

Critique

The way to generalize your for-loops is to determine what varies — namely, the number of days in each month and the day of the week that each month starts on. Then, you want to extract the magic numbers into arrays so that your code is data-directed.

The second argument to findDay() does not make obvious sense. Considering that January 2015 starts on a Thursday, why would you call findDay(jan, 0)? I would expect something like findDay(jan, 4), give or take 1 depending on your numbering convention. Better yet, make your numbering convention clearer by defining an enum.

Similarly, findDay() would be better implemented using a lookup table instead of a switch.

findDay() is misnamed and poorly designed. It doesn't just return the result: it also prints it (with a leading space and a trailing newline!). Printing the result limits your ability to ever reuse that function for anything else in the future. (Normally, returning a string from a C function could be a tricky proposition. In this case, you'll be returning constant strings, which is fine.)

Suggested solution

#include <stdio.h>

typedef enum {
    SUN, MON, TUE, WED, THU, FRI, SAT
} Weekday;

static const char *DAY_NAMES[] = {
    "Sunday",
    "Monday",
    "Tuesday",
    "Wednesday",
    "Thursday",
    "Friday",
    "Saturday",
};

static const int MONTH_LENGTHS_NON_LEAP_YEAR[] = {
    31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
};

const char *dayOfWeekIn2015(int month, int dayOfMonth) {
    static const Weekday DAY0[] = {
        WED,    // 2014-12-31
        SAT,    // 2015-01-31
        SAT,    // 2015-02-28
        TUE,    // 2015-03-31
        THU,    // 2015-04-30
        SUN,    // 2015-05-31
        TUE,    // 2015-06-30
        FRI,    // 2015-07-31
        MON,    // 2015-08-31
        WED,    // 2015-09-30
        SAT,    // 2015-10-31
        MON     // 2015-11-30
    };
    return DAY_NAMES[(DAY0[month - 1] + dayOfMonth) % 7];
}

int main(void) {
    for (int month = 1; month <= 12; month++) {
        for (int dayOfMonth = 1; dayOfMonth <= MONTH_LENGTHS_NON_LEAP_YEAR[month - 1]; dayOfMonth++) {
            printf("%02d/%02d/2015 is a %s\n",
                   month, dayOfMonth, dayOfWeekIn2015(month, dayOfMonth));
        }
    }
}
\$\endgroup\$
0
\$\begingroup\$

Instead of having 12 for loops , just have an array with the months numbers in , then loop thru that once , then for each day in month, 2 for loops. I havent done c for a while so just some pseudo code.

var daysOfMonth:Array = [31,28,...];

for(days=0;days<daysOfMonth.length;days++) {
   for(day=1; day<=daysOfMonth[days]; ++day)
   {
     printf("%d/%d/2015 is", daysOfMonth[days], day);
     findDay(day, 6);
   }
}
\$\endgroup\$
0
\$\begingroup\$

Avoiding your own implementation

You are, of course, doing this as a beginner's exercise. I'd like to note, though, that you would not want to deploy this kind of code into production, since it hard-codes many magic numbers that make it work only for 2015.

When dealing with issues, you'll always want to use a library, since the computations are always tedious and tricky to get right. Here is a way to do it using the standard C library functions. The part that actually performs the day-of-the-week lookup is the %A format specification in the call to strftime(). You need go back-and-forth between two representations of time: a struct tm (a structure which stores the year, month, day, day of the week, etc.) and a time_t (a count of seconds since 1970).

#include <stdio.h>
#include <time.h>

int main(void) {
    struct tm start = (struct tm){ 0 };
    start.tm_year = 2015 - 1900;
    start.tm_mday = 1;

    const int DAY_SECS = 24 * 60 * 60;

    for (time_t t = mktime(&start); gmtime(&t)->tm_year == start.tm_year; t += DAY_SECS) {
        char buf[80];
        if (!strftime(buf, sizeof buf, "%m/%d/%Y is a %A", gmtime(&t))) {
            return 1;   // Unexpected failure
        }
        puts(buf);
    }
}
\$\endgroup\$
2
  • \$\begingroup\$ 1) start.tm_isdst = -1; should be applied before mktime() else code forces standard time for Jan 1, 0:00:00 locat ime (often DST in southern hemisphere). 24 * 60 * 60, a magic number that depends on time_t being a count of seconds-something not defined in standard C. Better: start.tm_mday++; start.tm_isdst = -1; and call mktime(&start) again. time_t not needed. 3) A curiously call mktime() (local to time_t), then calls gmtime(&t) (time_t to UTC, not local). I'd expect localtime(&t) 4) Agree "...since the (datetime) computations are always tedious and tricky to get right" \$\endgroup\$ Sep 9, 2015 at 18:37
  • \$\begingroup\$ @chux Thanks! Follow-up question here.. \$\endgroup\$ Sep 10, 2015 at 3:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.