Exercise 5-7. Rewrite readlines() to store lines in an array supplied by main(), rather than calling alloc() to maintain storage. How much faster is the program?
#include <stdio.h> // for getchar(), printf(), EOF, NULL, FILE, fopen(), fclose()
#include <string.h> // for strcpy(), strcmp()
#include <time.h> // for clock_t, clock(), CLOCKS_PER_SEC
#define MAXLINES 20000 // max no of lines to be sorted
#define MAXLEN 100 // max line length
int readlines (char *lineptr[], int nlines);
void writelines (char *lineptr[], int nlines, char *filename);
void qSort(char *lineptr[], int left, int right); // qsort() is declared by stdlib.h
int main()
{
char *lineptr[MAXLINES];
int nlines; // no of input lines read
clock_t start, end;
double time;
start = clock();
if ((nlines = readlines(lineptr, MAXLINES)) >= 0)
{
qSort(lineptr, 0, nlines-1);
writelines(lineptr, nlines, "sorted1.txt");
}
else
{
printf("Error: input too big to sort\n");
return 1; // exit program, signalling error
}
end = clock();
time = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("(1) Execution time: %f\n", time);
return 0;
}
int getLine(char *, int); // getline() is declared in stdio.h
char* alloc(int); // allocate storage
int readlines (char *lineptr[], int maxlines) // read input lines
{
int len, nlines;
char *p, line[MAXLEN];
nlines = 0;
while ((len = getLine(line, MAXLEN)) > 0)
{
if(nlines >= maxlines || (p = alloc(len+1)) == NULL)
{return -1;} // len+1 for ending '\0'
else
{
strcpy(p, line);
lineptr[nlines++] = p;
}
}
return nlines;
}
int getLine(char *s, int lim)
{
int c = EOF; // initialize
char *p;
// getchar() is only executed if ((p-s) < (lim-1)):
for (p = s; (p-s) < (lim-1) && (c = getchar()) != EOF && c != '\n'; p++)
{ // from 0 to lim-2; s[lim-2]='\n', s[lim-1]='\0'
*p = c;
}
if (c == '\n')
{*p++ = c;}
*p = '\0'; // the null character ends a string
return p-s; // max(p-s) == (lim-1)
}
#define ALLOCSIZE (MAXLINES * MAXLEN)
static char allocbuf[ALLOCSIZE]; // storage for alloc()
static char *allocp = allocbuf; // next free position
char* alloc(int n) // return pointer to n chars
{
if (allocbuf + ALLOCSIZE - allocp >= n) // it fits
{
allocp += n;
return allocp-n; // old pointer
}
else {return 0;} // null pointer
}
void afree(char *p) // free storage pointed to by p
{
if (p >= allocbuf && p < allocbuf + ALLOCSIZE)
{allocp = p;}
}
void writelines (char *lineptr[], int nlines, char *filename) // write output lines
{
FILE *f = fopen(filename, "w"); // open for writing
while (nlines-- > 0)
{fprintf(f, "%s", *lineptr++);}
fclose(f);
}
void swap(char *v[], int i, int j); // interchange v[i], v[j]
// sort v[left] ... v[right] into increasing order
void qSort(char *v[], int left, int right) // qsort() in declared in stdlib.h
{
int i, last;
if (left >= right) // do nothing if array contains fewer than 2 elements
{return;} // stopping condition for recursion
swap(v, left, (left + right) / 2); // move partition element to v[left]
last = left; // start moving elements to last position
for (i = left + 1; i <= right; i++)
{
if (strcmp(v[i], v[left]) < 0) // v[i] < v[left]
{swap(v, ++last, i);} // smaller to the left, bigger to the right
}
swap(v, left, last); // return partition element to the middle position
qSort(v, left, last-1); // sort smaller elements
qSort(v, last+1, right); // sort bigger elements
}
void swap(char *v[], int i, int j) // interchange v[i], v[j]
{
char *temp;
temp = v[i]; // swap pointers
v[i] = v[j];
v[j] = temp;
}
/*
gcc lines1.c -o lines1
./lines1 < me.txt
(1) Execution time: 0.055364
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <stdio.h> // for getchar(), printf(), EOF, NULL, FILE, fopen(), fclose()
#include <string.h> // for strcpy(), strcmp()
#include <time.h> // for clock_t, clock(), CLOCKS_PER_SEC
#define MAXLINES 20000 // max no of lines to be sorted
#define MAXLEN 100 // max line length
int readlines (char lines[][MAXLEN], int nlines);
void writelines (char *lineptr[], int nlines, char *filename);
void qSort(char *lineptr[], int left, int right); // qsort() is declared by stdlib.h
int main()
{
char *lineptr[MAXLINES];
char lines[MAXLINES][MAXLEN];
int i, nlines; // no of input lines read
clock_t start, end;
double time;
start = clock();
if ((nlines = readlines(lines, MAXLINES)) >= 0)
{
for (i = 0; i < nlines; i++)
{lineptr[i] = lines[i];}
qSort(lineptr, 0, nlines-1);
writelines(lineptr, nlines, "sorted2.txt");
}
else
{
printf("Error: input too big to sort\n");
return 1; // exit program, signalling error
}
end = clock();
time = ((double) (end - start)) / CLOCKS_PER_SEC;
printf("(2) Execution time: %f\n", time);
return 0;
}
int getLine(char *, int); // getline() is declared in stdio.h
int readlines (char lines[][MAXLEN], int maxlines) // read input lines
{
int nlines = 0;
while (getLine(lines[nlines], MAXLEN) > 0)
{
nlines++;
if(nlines >= maxlines)
{return -1;}
}
return nlines;
}
int getLine(char *s, int lim)
{
int c = EOF; // initialize
char *p;
// getchar() is only executed if ((p-s) < (lim-1)):
for (p = s; (p-s) < (lim-1) && (c = getchar()) != EOF && c != '\n'; p++)
{ // from 0 to lim-2; s[lim-2]='\n', s[lim-1]='\0'
*p = c;
}
if (c == '\n')
{*p++ = c;}
*p = '\0'; // the null character ends a string
return p-s; // max(p-s) == (lim-1)
}
void writelines (char *lineptr[], int nlines, char *filename) // write output lines
{
FILE *f = fopen(filename, "w"); // ope for writing
while (nlines-- > 0)
{fprintf(f, "%s", *lineptr++);}
fclose(f);
}
void swap(char *v[], int i, int j); // interchange v[i], v[j]
// sort v[left] ... v[right] into increasing order
void qSort(char *v[], int left, int right) // qsort() in declared in stdlib.h
{
int i, last;
if (left >= right) // do nothing if array contains fewer than 2 elements
{return;} // stopping condition for recursion
swap(v, left, (left + right) / 2); // move partition element to v[left]
last = left; // start moving elements to last position
for (i = left + 1; i <= right; i++)
{
if (strcmp(v[i], v[left]) < 0) // v[i] < v[left]
{swap(v, ++last, i);} // smaller to the left, bigger to the right
}
swap(v, left, last); // return partition element to the middle position
qSort(v, left, last-1); // sort smaller elements
qSort(v, last+1, right); // sort bigger elements
}
void swap(char *v[], int i, int j) // interchange v[i], v[j]
{
char *temp;
temp = v[i]; // swap pointers
v[i] = v[j];
v[j] = temp;
}
/*
gcc lines2.c -o lines2
./lines2 < me.txt
(2) Execution time: 0.043825
diff -s sorted1.txt sorted2.txt
Files sorted1.txt and sorted2.txt are identical
meld sorted1.txt sorted2.txt // Files are identical
rm sorted* // clean
*/
Redefine MAXLINES and MAXLEN if you use other input file.
getLine() should return after reading '\n' or upon reaching the end of file, otherwise it may need ungetch(), see Section ch4-Calculator in Chapter_4.
I changed the quotation marks in me.txt to their corresponding ASCII equivalents, ', ".
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 5-8. There is no error checking in day_of_year() or month_day(). Remedy this defect.
#include <stdio.h> // for printf(), scanf()
static char daytab[2][13] = // daytab[][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}
}; // don't forget semicolon
static char *monthtab[13] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; // don't forget semicolon
// get day of year from year (leap or not), month, day of month
int day_of_year(int year, int month, int day);
// set month and day of month from year (leap or not) and day of that year
int month_day(int year, int yearday, int *pmonth, int *pday); // return error code
int main()
{
int year, month, day, yearday, error;
printf("Year: ");
scanf("%d", &year);
printf("Yearday (1 ... 365 / 366): "); // for leap years
scanf("%d", &yearday);
error = month_day(year, yearday, &month, &day);
if (error) {return 1;} // signal error
printf("year %d, yearday %d: month %d (%s), day %d\n",
year, yearday, month, monthtab[month], day);
printf("Year: ");
scanf("%d", &year);
printf("Month (1 ... 12): ");
scanf("%d", &month);
printf("Day (1 ... 28 / 29 / 30 / 31): ");
scanf("%d", &day);
yearday = day_of_year(year, month, day);
if (yearday == 0) // error
{return 1;} // signal error
printf("year %d, yearday %d: month %d (%s), day %d\n",
year, yearday, month, monthtab[month], day);
return 0;
}
int leap_year (int year); // leap year?
// get day of year from year (leap or not), month, day of month
int day_of_year(int year, int month, int day)
{
if (month <= 0 || day <= 0)
{
printf("Month and Day of month > 0\n");
return 0; // signal error
}
if (month > 12)
{
printf("1 <= month <= 12\n");
return 0; // signal error
}
if (day > 31)
{
printf("1 <= day of month <= 28 / 29 / 30 / 31\n");
return 0; // signal error
}
int i, leap = leap_year(year);
if (day > daytab[leap][month])
{
if (month == 2 && day == 29)
{
printf("1 <= day of month <= %d for month %d (%s), year %d\n",
daytab[leap][month], month, monthtab[month], year);
}
else if (month == 2 && day > 29)
{
printf("1 <= day of month <= 28 / 29 for month %d (%s)\n",
month, monthtab[month]);
}
else
{
printf("1 <= day of month <= %d for month %d (%s)\n",
daytab[leap][month], month, monthtab[month]);
}
return 0; // signal error
}
for (i = 1; i < month; i++)
{
day += daytab[leap][i];
}
return day;
}
// set month and day of month from year (leap or not) and day of that year
int month_day(int year, int yearday, int *pmonth, int *pday) // return error code
{
if (yearday <= 0)
{
printf("Day of the year > 0\n");
return 1; // signal error
}
if (yearday > 366)
{
printf("Day of the year <= 365 or 366 for leap years\n");
return 1; // signal error
}
int i, leap = leap_year(year);
if (!leap && yearday == 366)
{
printf("Day of the year == 366 only for leap years\n");
return 1; // signal error
}
for (i = 1; yearday > daytab[leap][i]; i++)
{
yearday -= daytab[leap][i];
}
*pmonth = i;
*pday = yearday;
return 0; // no error
}
int leap_year (int year) // leap year?
{
return (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
}
/*
gcc days.c -o days
./days
Year: 2013
Yearday (1 ... 365 / 366): 0
Day of the year > 0
./days
Year: 2013
Yearday (1 ... 365 / 366): 367
Day of the year <= 365 or 366 for leap years
./days
Year: 2013
Yearday (1 ... 365 / 366): 366
Day of the year == 366 only for leap years
./days
Year: 2013
Yearday (1 ... 365 / 366): 365
year 2013, year-day 365: month 12 (Dec), day 31
Year: 2013
Month (1 ... 12): 0
Day (1 ... 28 / 29 / 30 / 31): 1
Month and Day of month > 0
./days
Year: 2014
Yearday (1 ... 365 / 366): 365
year 2014, year-day 365: month 12 (Dec), day 31
Year: 2015
Month (1 ... 12): 31
Day (1 ... 28 / 29 / 30 / 31): 1
1 <= month <= 12
./days
Year: 2012
Yearday (1 ... 365 / 366): 366
year 2012, yearday 366: month 12 (Dec), day 31
Year: 2012
Month (1 ... 12): 12
Day (1 ... 28 / 29 / 30 / 31): 31
year 2012, yearday 366: month 12 (Dec), day 31
./days
Year: 2015
Yearday (1 ... 365 / 366): 1
year 2015, year-day 1: month 1 (Jan), day 1
Year: 2012
Month (1 ... 12): 12
Day (1 ... 28 / 29 / 30 / 31): 0
Month and Day of month > 0
./days
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, year-day 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 10
Day (1 ... 28 / 29 / 30 / 31): 32
1 <= day of month <= 28 / 29 / 30 / 31
./days
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, yearday 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 10
Day (1 ... 28 / 29 / 30 / 31): 31
year 2012, yearday 305: month 10 (Oct), day 31
./days
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, yearday 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 9
Day (1 ... 28 / 29 / 30 / 31): 31
1 <= day of month <= 30 for month 9 (Sep)
./days
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, yearday 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 9
Day (1 ... 28 / 29 / 30 / 31): 30
year 2012, yearday 274: month 9 (Sep), day 30
./days
Year: 2011
Yearday (1 ... 365 / 366): 60
year 2011, yearday 60: month 3 (Mar), day 1
Year: 2011
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 30
1 <= day of month <= 28 / 29 for month 2 (Feb)
./days
Year: 2011
Yearday (1 ... 365 / 366): 60
year 2011, yearday 60: month 3 (Mar), day 1
Year: 2011
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 29
1 <= day of month <= 28 for month 2 (Feb), year 2011
./days
Year: 2011
Yearday (1 ... 365 / 366): 60
year 2011, yearday 60: month 3 (Mar), day 1
Year: 2011
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 28
year 2011, yearday 59: month 2 (Feb), day 28
./days
Year: 1988
Yearday (1 ... 365 / 366): 60
year 1988, yearday 60: month 2 (Feb), day 29
Year: 1988
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 29
year 1988, yearday 60: month 2 (Feb), day 29
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
Exercise 5-9. Rewrite the routines day_of_year() and month_day() with pointers instead of indexing.
#include <stdio.h> // for printf(), scanf()
static char daytab[][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}
}; // don't forget semicolon
static char *monthtab[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; // don't forget semicolon
// get day of year from year (leap or not), month, day of month
int day_of_year(int year, int month, int day);
// set month and day of month from year (leap or not) and day of that year
int month_day(int year, int yearday, int *pmonth, int *pday); // return error code
int main()
{
int year, month, day, yearday, error;
printf("Year: ");
scanf("%d", &year);
printf("Yearday (1 ... 365 / 366): "); // for leap years
scanf("%d", &yearday);
error = month_day(year, yearday, &month, &day);
if (error) {return 1;} // signal error
printf("year %d, yearday %d: month %d (%s), day %d\n",
year, yearday, month, monthtab[month], day);
printf("Year: ");
scanf("%d", &year);
printf("Month (1 ... 12): ");
scanf("%d", &month);
printf("Day (1 ... 28 / 29 / 30 / 31): ");
scanf("%d", &day);
yearday = day_of_year(year, month, day);
if (yearday == 0) // error
{return 1;} // signal error
printf("year %d, yearday %d: month %d (%s), day %d\n",
year, yearday, month, monthtab[month], day);
return 0;
}
int leap_year (int year); // leap year?
// get day of year from year (leap or not), month, day of month
int day_of_year(int year, int month, int day)
{
if (month <= 0 || day <= 0)
{
printf("Month and Day of month > 0\n");
return 0; // signal error
}
if (month > 12)
{
printf("1 <= month <= 12\n");
return 0; // signal error
}
if (day > 31)
{
printf("1 <= day of month <= 28 / 29 / 30 / 31\n");
return 0; // signal error
}
int i, leap = leap_year(year);
char *d = daytab[leap];
if (day > *(d+month))
{
if (month == 2 && day == 29)
{
printf("1 <= day of month <= %d for month %d (%s), year %d\n",
*(d+month), month, *(monthtab+month), year);
}
else if (month == 2 && day > 29)
{
printf("1 <= day of month <= 28 / 29 for month %d (%s)\n",
month, *(monthtab+month));
}
else
{
printf("1 <= day of month <= %d for month %d (%s)\n",
*(d+month), month, *(monthtab+month));
}
return 0; // signal error
}
d++; // point to first month, Jan
while (--month) // while (month-- > 1)
{
day += *d++;
}
return day;
}
// set month and day of month from year (leap or not) and day of that year
int month_day(int year, int yearday, int *pmonth, int *pday) // return error code
{
if (yearday <= 0)
{
printf("Day of the year > 0\n");
return 1; // signal error
}
if (yearday > 366)
{
printf("Day of the year <= 365 or 366 for leap years\n");
return 1; // signal error
}
int leap = leap_year(year);
if (!leap && yearday == 366)
{
printf("Day of the year == 366 only for leap years\n");
return 1; // signal error
}
char *d = daytab[leap];
d++; // point to first month, Jan
while (yearday > *d)
{
yearday -= *d++;
}
*pmonth = d-daytab[leap];
*pday = yearday;
return 0; // no error
}
int leap_year (int year) // leap year?
{
return (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
}
/*
gcc daysp.c -o daysp
./daysp
Year: 2013
Yearday (1 ... 365 / 366): 0
Day of the year > 0
./daysp
Year: 2013
Yearday (1 ... 365 / 366): 367
Day of the year <= 365 or 366 for leap years
./daysp
Year: 2013
Yearday (1 ... 365 / 366): 366
Day of the year == 366 only for leap years
./daysp
Year: 2013
Yearday (1 ... 365 / 366): 365
year 2013, year-day 365: month 12 (Dec), day 31
Year: 2013
Month (1 ... 12): 0
Day (1 ... 28 / 29 / 30 / 31): 1
Month and Day of month > 0
./daysp
Year: 2012
Yearday (1 ... 365 / 366): 366
year 2012, yearday 366: month 12 (Dec), day 31
Year: 2012
Month (1 ... 12): 12
Day (1 ... 28 / 29 / 30 / 31): 31
year 2012, yearday 366: month 12 (Dec), day 31
./daysp
Year: 2014
Yearday (1 ... 365 / 366): 365
year 2014, year-day 365: month 12 (Dec), day 31
Year: 2015
Month (1 ... 12): 31
Day (1 ... 28 / 29 / 30 / 31): 1
1 <= month <= 12
./daysp
Year: 2015
Yearday (1 ... 365 / 366): 1
year 2015, year-day 1: month 1 (Jan), day 1
Year: 2012
Month (1 ... 12): 12
Day (1 ... 28 / 29 / 30 / 31): 0
Month and Day of month > 0
./daysp
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, year-day 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 10
Day (1 ... 28 / 29 / 30 / 31): 32
1 <= day of month <= 28 / 29 / 30 / 31
./daysp
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, yearday 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 10
Day (1 ... 28 / 29 / 30 / 31): 31
year 2012, yearday 305: month 10 (Oct), day 31
./daysp
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, yearday 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 9
Day (1 ... 28 / 29 / 30 / 31): 31
1 <= day of month <= 30 for month 9 (Sep)
./daysp
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, yearday 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 9
Day (1 ... 28 / 29 / 30 / 31): 30
year 2012, yearday 274: month 9 (Sep), day 30
./daysp
Year: 2011
Yearday (1 ... 365 / 366): 60
year 2011, yearday 60: month 3 (Mar), day 1
Year: 2011
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 30
1 <= day of month <= 28 / 29 for month 2 (Feb)
./daysp
Year: 2011
Yearday (1 ... 365 / 366): 60
year 2011, yearday 60: month 3 (Mar), day 1
Year: 2011
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 29
1 <= day of month <= 28 for month 2 (Feb), year 2011
./daysp
Year: 2011
Yearday (1 ... 365 / 366): 60
year 2011, yearday 60: month 3 (Mar), day 1
Year: 2011
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 28
year 2011, yearday 59: month 2 (Feb), day 28
./daysp
Year: 1988
Yearday (1 ... 365 / 366): 60
year 1988, yearday 60: month 2 (Feb), day 29
Year: 1988
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 29
year 1988, yearday 60: month 2 (Feb), day 29
*/
*****************************************************************************************
*****************************************************************************************
*****************************************************************************************
#include <stdio.h> // for printf(), scanf()
// complicated pointers
static char daytab[][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}
}; // don't forget semicolon
static char *monthtab[] = {"", "Jan", "Feb", "Mar", "Apr", "May", "Jun",
"Jul", "Aug", "Sep", "Oct", "Nov", "Dec"}; // don't forget semicolon
// get day of year from year (leap or not), month, day of month
int day_of_year(int year, int month, int day);
// set month and day of month from year (leap or not) and day of that year
int month_day(int year, int yearday, int *pmonth, int *pday); // return error code
int main()
{
int year, month, day, yearday, error;
printf("Year: ");
scanf("%d", &year);
printf("Yearday (1 ... 365 / 366): "); // for leap years
scanf("%d", &yearday);
error = month_day(year, yearday, &month, &day);
if (error) {return 1;} // signal error
printf("year %d, yearday %d: month %d (%s), day %d\n",
year, yearday, month, monthtab[month], day);
printf("Year: ");
scanf("%d", &year);
printf("Month (1 ... 12): ");
scanf("%d", &month);
printf("Day (1 ... 28 / 29 / 30 / 31): ");
scanf("%d", &day);
yearday = day_of_year(year, month, day);
if (yearday == 0) // error
{return 1;} // signal error
printf("year %d, yearday %d: month %d (%s), day %d\n",
year, yearday, month, monthtab[month], day);
return 0;
}
int leap_year (int year); // leap year?
// get day of year from year (leap or not), month, day of month
int day_of_year(int year, int month, int day)
{
if (month <= 0 || day <= 0)
{
printf("Month and Day of month > 0\n");
return 0; // signal error
}
if (month > 12)
{
printf("1 <= month <= 12\n");
return 0; // signal error
}
if (day > 31)
{
printf("1 <= day of month <= 28 / 29 / 30 / 31\n");
return 0; // signal error
}
int i, leap = leap_year(year);
// complicated pointers:
char *dt[] = {*daytab, *(daytab+1)}; // daytab[0], daytab[1]
char **d = dt;
if(leap) {d++;} // point to daytab[leap]
if (day > *((*d)+month))
{
if (month == 2 && day == 29)
{
printf("1 <= day of month <= %d for month %d (%s), year %d\n",
*((*d)+month), month, *(monthtab+month), year);
}
else if (month == 2 && day > 29)
{
printf("1 <= day of month <= 28 / 29 for month %d (%s)\n",
month, *(monthtab+month));
}
else
{
printf("1 <= day of month <= %d for month %d (%s)\n",
*((*d)+month), month, *(monthtab+month));
}
return 0; // signal error
}
(*d)++; // point to first month, Jan
while (--month) // while (month-- > 1)
{
day += *(*d)++;
}
return day;
}
// set month and day of month from year (leap or not) and day of that year
int month_day(int year, int yearday, int *pmonth, int *pday) // return error code
{
if (yearday <= 0)
{
printf("Day of the year > 0\n");
return 1; // signal error
}
if (yearday > 366)
{
printf("Day of the year <= 365 or 366 for leap years\n");
return 1; // signal error
}
int leap = leap_year(year);
if (!leap && yearday == 366)
{
printf("Day of the year == 366 only for leap years\n");
return 1; // signal error
}
// complicated pointers:
char *dt[] = {*daytab, *(daytab+1)}; // daytab[0], daytab[1]
char **d = dt;
if(leap) {d++;} // point to daytab[leap]
(*d)++; // point to first month, Jan
while (yearday > **d)
{
yearday -= *(*d)++;
}
*pmonth = (*d)-daytab[leap];
*pday = yearday;
return 0; // no error
}
int leap_year (int year) // leap year?
{
return (year % 4 == 0) && (year % 100 != 0) || (year % 400 == 0);
}
/*
gcc dayscp.c -o dayscp
./dayscp
Year: 2013
Yearday (1 ... 365 / 366): 0
Day of the year > 0
./dayscp
Year: 2013
Yearday (1 ... 365 / 366): 367
Day of the year <= 365 or 366 for leap years
./dayscp
Year: 2013
Yearday (1 ... 365 / 366): 366
Day of the year == 366 only for leap years
./dayscp
Year: 2013
Yearday (1 ... 365 / 366): 365
year 2013, year-day 365: month 12 (Dec), day 31
Year: 2013
Month (1 ... 12): 0
Day (1 ... 28 / 29 / 30 / 31): 1
Month and Day of month > 0
./dayscp
Year: 2012
Yearday (1 ... 365 / 366): 366
year 2012, yearday 366: month 12 (Dec), day 31
Year: 2012
Month (1 ... 12): 12
Day (1 ... 28 / 29 / 30 / 31): 31
year 2012, yearday 366: month 12 (Dec), day 31
./dayscp
Year: 2014
Yearday (1 ... 365 / 366): 365
year 2014, year-day 365: month 12 (Dec), day 31
Year: 2015
Month (1 ... 12): 31
Day (1 ... 28 / 29 / 30 / 31): 1
1 <= month <= 12
./dayscp
Year: 2015
Yearday (1 ... 365 / 366): 1
year 2015, year-day 1: month 1 (Jan), day 1
Year: 2012
Month (1 ... 12): 12
Day (1 ... 28 / 29 / 30 / 31): 0
Month and Day of month > 0
./dayscp
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, year-day 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 10
Day (1 ... 28 / 29 / 30 / 31): 32
1 <= day of month <= 28 / 29 / 30 / 31
./dayscp
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, yearday 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 10
Day (1 ... 28 / 29 / 30 / 31): 31
year 2012, yearday 305: month 10 (Oct), day 31
./dayscp
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, yearday 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 9
Day (1 ... 28 / 29 / 30 / 31): 31
1 <= day of month <= 30 for month 9 (Sep)
./dayscp
Year: 2012
Yearday (1 ... 365 / 366): 60
year 2012, yearday 60: month 2 (Feb), day 29
Year: 2012
Month (1 ... 12): 9
Day (1 ... 28 / 29 / 30 / 31): 30
year 2012, yearday 274: month 9 (Sep), day 30
./dayscp
Year: 2011
Yearday (1 ... 365 / 366): 60
year 2011, yearday 60: month 3 (Mar), day 1
Year: 2011
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 30
1 <= day of month <= 28 / 29 for month 2 (Feb)
./dayscp
Year: 2011
Yearday (1 ... 365 / 366): 60
year 2011, yearday 60: month 3 (Mar), day 1
Year: 2011
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 29
1 <= day of month <= 28 for month 2 (Feb), year 2011
./dayscp
Year: 2011
Yearday (1 ... 365 / 366): 60
year 2011, yearday 60: month 3 (Mar), day 1
Year: 2011
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 28
year 2011, yearday 59: month 2 (Feb), day 28
./dayscp
Year: 1988
Yearday (1 ... 365 / 366): 60
year 1988, yearday 60: month 2 (Feb), day 29
Year: 1988
Month (1 ... 12): 2
Day (1 ... 28 / 29 / 30 / 31): 29
year 1988, yearday 60: month 2 (Feb), day 29
*/