The C Programming Language

Chapter 5 - Pointers and Arrays 8

mmresult 2009. 3. 27. 14:08


There is no error-checking in day_of_year or month_day. Remedy this defect.

Solution by Lars Wirzenius


/*
 * A solution to exercise 5-8 in K&R2, page 112:
 *
 * There is no error checking in day_of_year or month_day. Remedy
 * this defect.
 *
 * The error to check for is invalid argument values. That is simple, what's
 * hard is deciding what to do in case of error. In the real world, I would
 * use the assert macro from assert.h, but in this solution I take the
 * approach of returning -1 instead. This is more work for the caller, of
 * course.
 *
 * I have selected the year 1752 as the lowest allowed year, because that
 * is when Great Britain switched to the Gregorian calendar, and the leap
 * year validation is valid only for the Gregorian calendar.
 *
 * Lars Wirzenius <liw@iki.fi>
 */

#include <stdio.h>

static char daytab[2][13] =  {
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
};

/* day_of_year: set day of year from month & day */
int day_of_year(int year, int month, int day)
{
 int i, leap;
 
 if (year < 1752 || month < 1 || month > 12 || day < 1)
  return -1;

 leap = (year%4 == 0 && year%100 != 0) || year%400 == 0;
 if (day > daytab[leap][month])
  return -1;

 for (i = 1; i < month; i++)
  day += daytab[leap][i];
 return day;
}

/* month_day: set month, day from day of year */
int month_day(int year, int yearday, int *pmonth, int *pday)
{
 int i, leap;
 
 if (year < 1752 || yearday < 1)
  return -1;

 leap = (year%4 == 0 && year%100 != 0) || year%400 == 0;
 if ((leap && yearday > 366) || (!leap && yearday > 365))
  return -1;

 for (i = 1; yearday > daytab[leap][i]; i++)
  yearday -= daytab[leap][i];
 *pmonth = i;
 *pday = yearday;
 
 return 0;
}


/* main: test day_of_year and month_day */
int main(void)
{
 int year, month, day, yearday;
 
 for (year = 1970; year <= 2000; ++year) {
  for (yearday = 1; yearday < 366; ++yearday) {
   if (month_day(year, yearday, &month, &day) == -1) {
    printf("month_day failed: %d %d\n",
     year, yearday);
   } else if (day_of_year(year, month, day) != yearday) {
    printf("bad result: %d %d\n", year, yearday);
    printf("month = %d, day = %d\n", month, day);
   }
  }
 }
 
 return 0;
}

 

 menonsahab's
#include <stdio.h>
#include <stdlib.h>

static char daytab[2][13] =
{
 {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31},
 {0, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31}
};

int day_of_year(int year, int month, int day)
{
 if( year < 1752 )
  return -1;

 int i, leap;
 leap = (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);

 if( !((month >= 1 && month <= 12) && (day >= 1 && day <= daytab[leap][month])) )
  return -1;

 for(i = 1; i < month; i++)
 {
  day += daytab[leap][i];
 }
 return day;
}

void month_day(int year, int yearday, int *pmonth, int *pday)
{
 if( year < 1752 )
 {
  *pmonth = *pday = -1;
  return;
 }

 int i, leap;
 leap = (year % 400 == 0) || (year % 4 == 0 && year % 100 != 0);

 if( !(yearday >= 1 && yearday <= (leap ? 366 : 365)))
 {
  *pmonth = *pday = -1;
  return;
 }

 for(i = 1; yearday > daytab[leap][i]; i++)
  yearday -= daytab[leap][i];
 *pmonth = i;
 *pday = yearday;
}

int main()
{
 int month, day, year, yearday, retval;

 /******************************* Case 1 *****************************/
 printf("Case 1:\n");
 year = -2017;
 month = 11;
 day = 22;
 yearday = 326;

 retval = day_of_year(year, month, day);
 if(retval == -1)
  printf("Incorrect input\n");
 else
  printf("%d %d %d <---> %d %d\n", year, month, day, year, retval);

 month_day(year, yearday, &month, &day);
 if(month == -1 && day == -1)
  printf("Incorrect input\n");
 else
  printf("%d %d <---> %d %d %d\n", year, yearday, year, month, day);
 printf("\n");
 /*********************************************************************/

 /******************************* Case 2 *****************************/
 printf("Case 2:\n");
 year = 2017;
 month = -11;
 day = 22;
 yearday = 326;

 retval = day_of_year(year, month, day);
 if(retval == -1)
  printf("Incorrect input\n");
 else
  printf("%d %d %d <---> %d %d\n", year, month, day, year, retval);

 month_day(year, yearday, &month, &day);
 if(month == -1 && day == -1)
  printf("Incorrect input\n");
 else
  printf("%d %d <---> %d %d %d\n", year, yearday, year, month, day);
 printf("\n");
 /*********************************************************************/

 /******************************* Case 3 *****************************/
 printf("Case 3:\n");
 year = 2017;
 month = 11;
 day = -22;
 yearday = 326;

 retval = day_of_year(year, month, day);
 if(retval == -1)
  printf("Incorrect input\n");
 else
  printf("%d %d %d <---> %d %d\n", year, month, day, year, retval);

 month_day(year, yearday, &month, &day);
 if(month == -1 && day == -1)
  printf("Incorrect input\n");
 else
  printf("%d %d <---> %d %d %d\n", year, yearday, year, month, day);
 printf("\n");
 /*********************************************************************/

 /******************************* Case 4 *****************************/
 printf("Case 4:\n");
 year = 2017;
 month = 11;
 day = 22;
 yearday = -326;

 retval = day_of_year(year, month, day);
 if(retval == -1)
  printf("Incorrect input\n");
 else
  printf("%d %d %d <---> %d %d\n", year, month, day, year, retval);

 month_day(year, yearday, &month, &day);
 if(month == -1 && day == -1)
  printf("Incorrect input\n");
 else
  printf("%d %d <---> %d %d %d\n", year, yearday, year, month, day);
 printf("\n");
 /*********************************************************************/

 /******************************* Case 5 *****************************/
 printf("Case 5:\n");
 year = 2017;
 month = 11;
 day = 22;
 yearday = 326;

 retval = day_of_year(year, month, day);
 if(retval == -1)
  printf("Incorrect input\n");
 else
  printf("%d %d %d <---> %d %d\n", year, month, day, year, retval);

 month_day(year, yearday, &month, &day);
 if(month == -1 && day == -1)
  printf("Incorrect input\n");
 else
  printf("%d %d <---> %d %d %d\n", year, yearday, year, month, day);
 printf("\n");
 /*********************************************************************/

 return 0;
}

/*
The output of the above program is:
Case 1:
Incorrect input
Incorrect input

Case 2:
Incorrect input
2017 326 <---> 2017 11 22

Case 3:
Incorrect input
2017 326 <---> 2017 11 22

Case 4:
2017 11 22 <---> 2017 326
Incorrect input

Case 5:
2017 11 22 <---> 2017 326
2017 326 <---> 2017 11 22
*/