3.实现printf日历

#include <stdio.h>

// 检测当前年分是闰年还是平年
// Input:  int year: 判断年份
// Output: 1:闰年  0:平年
int IsLeapYear(int year)
{
	int ret = 0;

	// 检测当前输入参数是否合法
	// 支持公元1 - 2100年
	if(year <= 0 || year > 2100){
		ret = -1; // 年 参数错误
	}	
	
	// 普通闰年:能被4整除但不能被100整除的年份为普通闰年
	// 世纪闰年:能被400整除的为世纪闰。
	if(((year%4 == 0) && (year%100 != 0)) || // 普通闰年
	   (year%400 == 0)){ // 世纪闰年
		ret = 1; // 闰年
	}
	
	return ret;
}

// 检测当前年月最大日期
// 判断该月一共有几天?
// input: int year: 当前年份
//        int month: 当前月份
// output: -1: 年份输入错误
//         -2: 月份输入错误
//         其他:正确结果
int FindDate(int year, int month)
{
	int ret = 0;

	// 检测年份参数是否合法
	// 并判断年份是闰年还是平年
	ret = IsLeapYear(year);
	if(ret < 0){ // 参数错误
		goto err;
	}
	
	// 此处检测月份参数是否合法
	if(month <= 0 || month >12){
		ret = -2; // 年与月参数错误
		goto err;
	}
	
	// 月份检测
	switch(month){
		case 2: // 2月
			if(ret == 1){ // 闰年是29天
				ret = 29;
			}else{
				ret = 28; // 平年是28天
			}
			break;
			
		case 4:
		case 6:
		case 9:
		case 11: // 4月 6月 9月 11月 固定30天
			ret = 30;
			break;
			
		default: ret = 31; // 1月 3月 5月 7月 8月 10月 12月固定31天
	}
	
err:
	return ret;
}

// 实现输入日期,计算当前是周几
// input : int year 当前查询的年份
//         int month 当前查询的月份
//         int day 查询的日期
// output: 0-周一 1-周二 ... 6-周日
int CalendarConvertWeek(int year, int month, int day)
{
	int week;
	
	// 由于日期已经检测是否合法,这里不做检测
	// 基姆拉尔森计算公式
    // W= (d+2*m+3*(m+1)/5+y+y/4-y/100+y/400)%7
	// 基本思想:把1月和2月看成是上一年的13月和14月	
	if((month == 1) || (month == 2)){
		year--;
		month += 12;
	}
	
	// %7: 不用做参数范围判断
	week = (day + 2*month + 3*(month+1)/5 + \
	        year + year/4 - year/100 + year/400)%7;

	return week;
}

// 实现:2.Print a month's calendar
// input : int year 当前查询的年份
//         int month 当前查询的月份
//         int maxday 当月最大有多少天
void PrintfCalendarAMonth(int year, int month, int maxday)
{
	int i, j;
	int week;
	int day = 1;
	printf("%04d-%02d\n", year, month); // 打印测试
	
	// 检测当前打印日期的起始位置(即周几?)
	week = CalendarConvertWeek(year, month, day);
	//printf("%04d-%02d-%02d 是星期%d\n", year, month, 1, week+1); // 测试函数
	
	// 当前\tXXX 为一组,共七组
	printf("\tMon\tTue\tWed\tThu\tFri\tSat\tSun\n");
	
	// 计算当前起始位置:礼拜一是第一列
	j = week%7;  
	
	// 起始第一行的偏移量
	for(i=0; i<j; i++){  
		printf("\t\0\0\0");
	}
	
	// 打印剩余的day,注意换行
	for(i=1; i<=maxday; i++,j++){
		if((j%7) == 0){  // 打印换行
			printf("\n");
		}

		printf("\t%d", i); // 打印日期			
	}
}

// 实现:1.Print a year's calendar
// input : int year 当前查询的年份
//         int type 0 = 平年 1 = 闰年
void PrintfCalendarYear(int year, char type)
{
	int i;
	char sday[12] = {31,28,31,30,31,30,31,31,30,31,30,31};
	
	// 不用做参数范围判断
	if(type){
		sday[1] = 29; // 闰年是29天,默认是28天
	}
	
	// 打印12个月份的日历
	// 使用空间换取时间
	for(i=1; i<=12; i++){
		
		PrintfCalendarAMonth(year, i, sday[i-1]);
		printf("\n");
	}
}

// 实现第三题测试 
void Test03_PrintfCalendar(void)
{
	int rec;
	int year, month;
	
	for(;;){
		
		// 打印人机交互界面
		printf("*********************Please chose*************************\n");
		printf("*************1.Print a year's calendar *******************\n");
		printf("*************2.Print a month's calendar*******************\n");
		printf("*************0.Quit calendar *****************************\n");
		printf("**********************************************************\n");
	
		// 接收选择字符 -> 1 2 0
		printf("your chose:(1 or 2) -> ");
		
		// 问题:假若输入字符或字符串后,就一直执行,停不下
		// 20200229已解决该问题,添加清空缓冲区,但输入多个字符仍出现此类问题
		setbuf(stdin,NULL); // 清空缓冲区
		scanf("%d", &rec);
		
		// 先实现2.Print a month's calendar
		// 在以上的基础上拓展1.Print a year's calendar
		switch(rec){
			case 0: return; // 退出操作
			
			case 1: { // 打印某一整年的日历
					printf("input Year(2100>Year>0) -> ");
					scanf("%d", &year); // 输入年份

					// 检测年份参数是否合法
					// 并判断年份是闰年还是平年
					rec = IsLeapYear(year);
					if(rec < 0){ // 参数错误
						printf("\nInput err, please try again.\n\n");
						break;
					}
					
					PrintfCalendarYear(year, rec); // 打印整年日历
				}return;
				
			case 2: { // 打印某一年某个月的日历
					printf("input Year and Month (eg:2020,2) -> ");
					scanf("%d,%d", &year, &month); // 输入年份月份
					
					// 检测当前年月输入是否正确
					// 并返回当前月份最大是多少天
					rec = FindDate(year, month);
					if(rec < 0){ // 参数错误并返回
						printf("\nInput err, please try again.\n\n");
						break;
					}
					
					PrintfCalendarAMonth(year, month, rec); // 执行打印月份日历
				}return;
			
			default: printf("\nInput err, please try again.\n");
		}
		
		printf("\n");
		rec = 0;
		sleep(1); // 延迟显示下一帧,增强体验感
	}
}

// 主函数
int main(int argc, const char *argv[])
{

#if 1	
    // 使用上题中的两个函数
    // 思想:  1.先做选择-人机交互界面
    //       2.接收选择字符 -> 1或者2
    //       3.先实现2.Print a month's calendar
    //       4.检测当前打印日期的起始位置(即周几?),此处按照win10日历样式显示,与例程稍不一样。
    //       5.计算当前起始位置:礼拜一是第一列
    //       6.打印起始第一行的偏移量
    //       7.打印当前月的所有day(到周日后就换行显示)
    //       8.在7的基础上拓展1.Print a year's calendar
    // 测试完成,效果符合题目要求
    // 已解决的问题:在人机交互界面选择1 or 2时,假若输入字符或字符串后,就一直执行,停不下。
	Test03_PrintfCalendar();
	
	//  打印效果:
	//  2020-02
	//  Mon	Tue	Wed	Thu	Fri	Sat	Sun
	//  					1	2
	//  3	4	5	6	7	8	9
	//  10	11	12	13	14	15	16
	//  17	18	19	20	21	22	23
	//  24	25	26	27	28	29
#endif	

	printf("\n");
	return 0;
}
发布了10 篇原创文章 · 获赞 0 · 访问量 533

猜你喜欢

转载自blog.csdn.net/TurboTab/article/details/104606319
3.