这是多年前写的一个小程序(一个简单的日历),挺有意思的,当年就是靠这个小程序搞懂了top-down design和bottom-up implementation. 程序如下:
#include<stdio.h>
#include<windows.h>
// 用了windows.h就不要用自定义的BOOL(而用MY_BOOL)
// 否则冲突.
typedef enum{MY_FALSE, MY_TRUE} MY_BOOL;
// 提示用户
void remindUsers()
{
printf("This is a calendar!\n");
printf("Input a year(year >= 1990)!\n");
printf("Press the key Enter afterwards!\n");
}
// 获得年份(year >= 1990)
int getYear()
{
int year;
while(1)
{
scanf("%d", &year);
if(year >= 1990)
return year;
printf("The year should not be before 1990.\n");
}
}
// 闰年判断
MY_BOOL isLeapYear(int year)
{
if((0 == year % 400)||
(0 == year % 4 && 0 !=year % 100))
return MY_TRUE;
return MY_FALSE;
}
// 一个月的天数(其中2月跟年份有关)
int daysInMonth(int year, int month)
{
switch(month)
{
case 2: if(isLeapYear(year))
return 29;
return 28;
case 4:
case 6:
case 9:
case 11: return 30;
default: return 31;
}
}
// 返回第year年,第month天的第一天是星期几
int firstDayOfMonth(int year, int month)
{
int weekday = 1; // 1990年第一个月第一天刚好是:星期一
int i;
for(i = 1990; i < year; i++) // 不是i <= year
{
// 先把year作笼统处理
weekday = (weekday + 365) % 7;
// 如果是leap year,需要做特殊处理
if(isLeapYear(i))
weekday = (weekday + 1) % 7;
}
// 处理完year后,要处理month
for(i = 1; i < month; i++) // 不是 i <= month
weekday = (weekday + daysInMonth(year, i)) % 7;
return weekday;
}
// 缩进
void indentFirstLine(int weekday)
{
int i;
for(i = 0; i < weekday; i++)
printf(" ");
}
// 生成一个月的日历
void printCalendarMonth(int year, int month)
{
int weekday, days, i;
printf(" %d %d\n",year,month);
printf(" Su Mo Tu We Th Fr Sa\n");
days = daysInMonth(year, month);
weekday = firstDayOfMonth(year, month);
indentFirstLine(weekday); // 缩进
for(i = 1; i <= days; i++)
{
printf(" %2d", i);
if(6 == weekday)
printf("\n"); // 星期六后换行
weekday = (weekday + 1) % 7;
}
if(0 != weekday)
printf("\n");
}
// 生成一年的日历
void printCalendar(int year)
{
int month;
for(month = 1; month <= 12; month++)
{
printCalendarMonth(year, month);
printf("\n\n");
}
}
// top-down design and bottom-up implementation
int main()
{
int year;
remindUsers();
year = getYear();
printCalendar(year);
system("pause");
return 0;
}
输入: 2012,,按Enter, 结果为:(由于长度原因,只进行部分截图)
下面我们看看Windows系统自带的日历:(与上面程序结果符合)