Having trouble with a function in C

70 views Asked by At

In my program, I am asking the user to input a date (in just integers such as 12 31 2019 367) and the number of days they add to it. In one of my functions, this is precisely what I am doing.

The user inputs 12 31 2019 367, and the program is meant to print 1 1 2021, but instead prints 1 1 2020 (a year behind)...

What I did (sorry for a lot of code, I tried to keep it simple and clean):

int days_in_month[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
                      
void add_days_to_date(int *mm, int *dd, int *yy, int days_left_to_add)
{
  int days_left_in_month;
  while(days_left_in_month > 0)
  {
    days_left_in_month = days_in_month[*mm] - *dd;
 //   days_left_in_month = days_in_month[*mm] - *dd;
    if (days_in_month[2] && is_leap_year(*yy) == true)
    {
      days_left_in_month++;
    }
   } // end while
   printf("after while\n");
    if(days_left_to_add > days_left_in_month)
    {
      days_left_to_add -= days_left_in_month;
      *dd = 1;
      if(*mm == 12)
      {
        *mm = 1;
        (*yy)++;
      }
      else
      {
        (*mm)++;
      }
    }
    else
    {
      *dd += days_left_to_add;
      days_left_to_add = 0;
    }
}
int main()
{
  int mm, dd, yy, days_left_to_add;
  printf("Please enter a date between the years 1800 and 10000 in the format mm dd yy and provide the number of days to add to this date:\n");
  scanf("%d %d %d %d", &mm, &dd, &yy, &days_left_to_add);
 // printf("\nREAD\n");
  //These are pointers, so they have to be at certain location i.e. int* mm = &mm
  add_days_to_date(&mm, &dd, &yy, days_left_to_add);
  printf("%d %d %d\n", mm, dd, yy);
}

What I got after inputs:

Inputs: 12 31 2019 367

Output: 1 1 2020 (meant to be 1 1 2021)

1

There are 1 answers

0
Jonathan Leffler On

Your loop in the function needs to be while (days_left_to_add > 0), and should cover the whole of the function (and then needs some minor adjustments). As it is, you add just one month, which given that your input is 2019-12-31 lands you on 2020-01-01.

Your code should validate the input date.

This code works, at least for a number of test cases similar to your example.

/* SO 74925-5084 */
#include <stdio.h>
#include <stdbool.h>

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

static bool is_leap_year(int year)
{
    if (year % 4 != 0)
        return false;
    if (year % 100 != 0)
        return true;
    if (year % 400 != 0)
        return false;
    return true;
}

static void add_days_to_date(int *mm, int *dd, int *yy, int days)
{
    while (days > 0)
    {
        int days_left_in_month = days_in_month[*mm] - *dd + 1;
        if (*mm == 2 && is_leap_year(*yy))
            days_left_in_month++;
        //printf("DAYS = %2d, DLIM = %2d, leap(%4d) = %s\n",
        //       days, days_left_in_month, *yy, is_leap_year(*yy) ? "true" : "false");
        if (days >= days_left_in_month)
        {
            days -= days_left_in_month;
            *dd = 1;
            if (*mm == 12)
            {
                *mm = 1;
                (*yy)++;
            }
            else
            {
                (*mm)++;
            }
        }
        else
        {
            *dd += days;
            days = 0;
        }
        // This is informative while debugging
        printf("%.4d-%.2d-%.2d + %d\n", *yy, *mm, *dd, days);
    }
}

int main(void)
{
    int mm, dd, yy, days_left_to_add;
    printf("Please enter a date between the years 1800 and 10000 in the format mm dd yyyy\n"
           "and provide the positive number of days to add to this date:\n");
    if (scanf("%d %d %d %d", &mm, &dd, &yy, &days_left_to_add) != 4)
    {
        fprintf(stderr, "Failed to read 4 numbers\n");
        return 1;
    }
    printf("Input: %.4d-%.2d-%.2d + %d\n", yy, mm, dd, days_left_to_add);

    /* Data validation */
    if (days_left_to_add <= 0)
    {
        fprintf(stderr, "The number of days to add must be a positive number (unlike %d)\n",
                days_left_to_add);
        return 1;
    }
    if (yy < 1800 || yy > 10000)
    {
        fprintf(stderr, "Year %d is outside the range 1800..10000\n", yy);
        return 1;
    }
    if (mm < 1 || mm > 12)
    {
        fprintf(stderr, "Month %d is outside the range 1..12\n", mm);
        return 1;
    }
    int dim = days_in_month[mm];
    if (mm == 2 && is_leap_year(yy))
        dim++;
    if (dd < 1 || dd > dim)
    {
        fprintf(stderr, "Day %d is outside the range 1..%d\n", dd, dim);
        return 1;
    }

    add_days_to_date(&mm, &dd, &yy, days_left_to_add);
    printf("%d %d %d\n", mm, dd, yy);
    return 0;
}

Sample runs (program ad41 created from ad41.c):

$ ad41
Please enter a date between the years 1800 and 10000 in the format mm dd yyyy
and provide the positive number of days to add to this date:
12 31 2019 367
Input: 2019-12-31 + 367
2020-01-01 + 366
2020-02-01 + 335
2020-03-01 + 306
2020-04-01 + 275
2020-05-01 + 245
2020-06-01 + 214
2020-07-01 + 184
2020-08-01 + 153
2020-09-01 + 122
2020-10-01 + 92
2020-11-01 + 61
2020-12-01 + 31
2021-01-01 + 0
1 1 2021
$ ad41
Please enter a date between the years 1800 and 10000 in the format mm dd yyyy
and provide the positive number of days to add to this date:
12 31 2018 60
Input: 2018-12-31 + 60
2019-01-01 + 59
2019-02-01 + 28
2019-03-01 + 0
3 1 2019
$ ad41
Please enter a date between the years 1800 and 10000 in the format mm dd yyyy
and provide the positive number of days to add to this date:
12 31 2019 60
Input: 2019-12-31 + 60
2020-01-01 + 59
2020-02-01 + 28
2020-02-29 + 0
2 29 2020
$