Exercise 5-8. There is no error checking in
day_of_yearormonth_day. Remedy this defect.
K&R’s Section 5.8 defines a 2D array daytab[2][13] for days per month and two functions that convert between day-of-year and (month, day). Neither validates its inputs. Bad values (year 0, month 13, day 367) cause silent wrong results or array overruns. The fix: add bounds checks at the top of each function and return a sentinel value (-1 or 0) on invalid input.
Solution
/* K&R Exercise 5-8 — day_of_year / month_day with error checking
* Compile: gcc -ansi -Wall ex5-8.c -o ex5-8 */
#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}
};
static int leap(int year) { return year%4==0 && (year%100!=0 || year%400==0); }
/* Returns day of year (1-366), or -1 on invalid input */
int day_of_year(int year, int month, int day)
{
int i, ly;
if (year < 1 || month < 1 || month > 12 || day < 1)
return -1;
ly = leap(year);
if (day > daytab[ly][month])
return -1;
for (i = 1; i < month; i++)
day += daytab[ly][i];
return day;
}
/* Sets *pmonth and *pday; returns 0 on success, -1 on invalid input */
int month_day(int year, int yearday, int *pmonth, int *pday)
{
int i, ly;
if (year < 1 || yearday < 1)
return -1;
ly = leap(year);
if (yearday > (ly ? 366 : 365))
return -1;
for (i = 1; yearday > daytab[ly][i]; i++)
yearday -= daytab[ly][i];
*pmonth = i;
*pday = yearday;
return 0;
}
int main(void)
{
int m, d;
printf("2024-03-01: day %d\n", day_of_year(2024,3,1)); /* 61 (leap) */
printf("2023-03-01: day %d\n", day_of_year(2023,3,1)); /* 60 */
printf("bad month: day %d\n", day_of_year(2024,13,1)); /* -1 */
printf("bad day: day %d\n", day_of_year(2024,2,30)); /* -1 */
if (month_day(2024, 61, &m, &d) == 0)
printf("day 61 of 2024: %d/%d\n", m, d); /* 3/1 */
if (month_day(2023, 367, &m, &d) != 0)
printf("day 367 of 2023: invalid\n"); /* -1 */
return 0;
}
Compile and Run
gcc -ansi -Wall ex5-8.c -o ex5-8
./ex5-8
Sample Output
2024-03-01: day 61 2023-03-01: day 60 bad month: day -1 bad day: day -1 day 61 of 2024: 3/1 day 367 of 2023: invalid
What This Exercise Teaches
- Input validation at function entry — check all preconditions before touching the data; return a sentinel value rather than silently producing garbage
- Array bounds and leap years —
daytab[leap(year)][month]gives the correct day count; validatingday > daytab[ly][month]catches Feb 30, Apr 31, etc. - Sentinel return vs assertion — returning -1 lets the caller handle the error gracefully;
assertwould abort; neither approach is wrong, but -1 is better for library functions
Set Up Your C Environment
← Exercise 5-7 |
Chapter 5 Solutions |
Exercise 5-9 →
Book: The C Programming Language, 2nd Ed — Kernighan & Ritchie