How can I write a correct function for "month/day" instead what I wrote?

Viewed 1086

So, this is my problem:

Write enumerated types that supports dates—such as December 12. Then add a function that produces a next day. So nextday(date) of December 12 is December 13. Also write a function printdate(date) that prints a date legibly. The function can assume that February has 28 days and it most know how many days are in each month. Use struct with two members; one is the month and the second is the day of the month — an int (or short). Then print out the date January 1 and print the next day Jan 2. Do this for the following dates: February 28, March 14, October 31, and December 31.

And that's my solution

#include <stdio.h>
#include <ctype.h>

typedef enum month { jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec } month;
typedef struct date { enum month m; int d; } date;

void print_month(struct date date) { //simple function for displaying month and day
    switch (date.m) {
      case jan:
        printf("January day %d\n", date.d);
        break;
      case feb:
        printf("February day %d\n", date.d);
        break;
      case mar:
        printf("March day %d\n", date.d);
        break;
      case apr:
        printf("April day %d\n", date.d);
        break;
      case may:
        printf("May day %d\n", date.d);
        break;
      case jun:
        printf("June day %d\n", date.d);
        break;
      case jul:
        printf("July day %d\n", date.d);
        break;
      case aug:
        printf("August day %d\n", date.d);
        break;
      case sep:
        printf("September day %d\n", date.d);
        break;
      case oct:
        printf("October day %d\n", date.d);
        break;
      case nov:
        printf("November day %d\n", date.d);
        break;
      case dec:
        printf("December day %d\n", date.d);
        break;
      default:
        printf("Out of range!");
        break;
    }
}

enum month next_day(struct date next) { //next month|day function which is the problem.
    if (next.m == jan || mar || may || jul || aug || oct || dec) {
        next.d + 1 % 31;
    }
    else if (next.m == apr || jun || sep || nov) {
        next.d + 1 % 30;
    }
    else if (next.m == feb) {
        next.d + 1 % 28;
        if (next.d > 28)
            next.m = mar;
    }

    return (month)next.m;
}

int main(void) {
    struct date date_1 = { feb, 28 };
    struct date date_2 = { mar, 14 };
    struct date date_3 = { oct, 31 };
    struct date date_4 = { dec, 31 };

    print_month(date_1);
    print_month(date_2);
    print_month(date_3);
    print_month(date_4);
    printf("\n");

    print_month(next_day(date_1)); //err C2440 
    print_month(next_day(date_2)); //err C2440
    print_month(next_day(date_3)); //err C2440
    print_month(next_day(date_4)); //err C2440
    printf("\n\n");

    return 0;
}
2 Answers

I have some suggestions:

  • the date structure should contain the year to allow for leap year support.
  • You can simplify print_date() using an array of strings.
  • The function next_day() should return a date.

Here is a modified version:

#include <stdio.h>

typedef enum month { jan, feb, mar, apr, may, jun, jul, aug, sep, oct, nov, dec } month;
typedef struct date { enum month m; int d; int y; } date;

static const char * const month_name[] = {
    "January",  "February", "March",
    "April",    "May",      "June",
    "July",     "August",   "September",
    "October",  "November", "December",
};

void print_month(struct date date) { //simple function for displaying month and day
    switch (date.m) {
      case jan:
      case feb:
      case mar:
      case apr:
      case may:
      case jun:
      case jul:
      case aug:
      case sep:
      case oct:
      case nov:
      case dec:
        printf("%s %d, %d\n", month_name[date.m], date.d, date.y);
        break;
      default:
        printf("Out of range!\n");
        break;
    }
}

date next_day(struct date next) { //next month|day function which is the problem.
    int last_day;
    switch (next.m) {
      case jan:
      case mar:
      case may:
      case jul:
      case aug:
      case oct:
      case dec:
        last_day = 31;
        break;
      case apr:
      case jun:
      case sep:
      case nov:
        last_day = 30;
        break;
      case feb:
        // check for Gregorian leap years
        // see https://stackoverflow.com/questions/3220163/how-to-find-leap-year-programmatically-in-c
        if (next.y % 4 == 0 && (next.y % 100 != 0 || next.y % 400 == 0))
            last_day = 29;
        else
            last_day = 28;
        break;
      default:
        return next;
    }
    if (next.d++ == last_day) {
        next.d = 1;
        if (next.m++ == dec) {
            next.m = jan;
            next.y++;
        }
    }
    return next;
}

int main() {
    struct date date_1 = { feb, 28, 2020 };
    struct date date_2 = { mar, 14, 2020 };
    struct date date_3 = { oct, 31, 2020 };
    struct date date_4 = { dec, 31, 2020 };
    struct date date_5 = { feb, 28, 2021 };

    print_month(date_1);
    print_month(date_2);
    print_month(date_3);
    print_month(date_4);
    print_month(date_5);
    printf("\n");

    print_month(next_day(date_1));
    print_month(next_day(date_2));
    print_month(next_day(date_3));
    print_month(next_day(date_4));
    print_month(next_day(date_5));
    printf("\n\n");

    return 0;
}

Output:

February 28, 2020
March 14, 2020
October 31, 2020
December 31, 2020
February 28, 2021

February 29, 2020
March 15, 2020
November 1, 2020
January 1, 2021
March 1, 2021

First of all, I got to say that this is purely C. Tag it as so.

If you are interested in C++. First of all, let's overload the operator << for your struct.

std::ostream& operator<<(std::ostream &o, const date& d)
{
    std::string s = "Out of range"; 
    // your switch statement here to change the value of s.
    // or call a function to keep the operator code short.
    return o << s << date.d << std::endl;
}

Now we expect to display the date struct as follows:

date d{...}
std::cout << d; 

Solving your next_day function (idea). Let's return a date instead.

date next_day(date next) //next month|day function which is the problem.
{
    // make a map with months and their total days
    int total = totalDays[next.m]
    if (next.d + 1 > total) // Should go to next month
    {
       next.m = next.m + 1; // move on to next month 
       next.d = 1; 
    } else {
       next.d = next.d +1;
    }

    return next;
}

Edit: the next_day function will fail for Dec 31. Credits: @PaulMcKenzie

Related