上次我们说到格式化屏幕输出的前两个简单问题,接下来我们来看一个稍微复杂一点的例子。
题目3:用户键盘输入一个年份(输入年份从1900开始),请编程实现,根据用户输入的年份,打印输出这一年所有月份的日历。P.S. 计算某一年的第一天是星期几:
days=year-1+(year-1)/400+(year-1)/4-(year-1)/100
weekday=(days+1)%7
输出样例:
不知道怎么入手?那我们可以先做一些与题目既有关又无关的事情,比如先检测用户键盘输入的年份是否符合题目要求,即从1900开始。鉴于我之前的文章C语言丨检测用户键盘输入数据的合法性已经详细介绍过检测用户键盘输入数据的合法性的方法,这里就不再赘述:
int year, ret;
char c;
printf("请输入年份:\n");
ret = scanf("%d", &year);
c = getchar();
while ((year<1900)||(ret!=1)||(c!='\n'))
{
fflush(stdin);
printf("请输入从1900开始的年份:\n");
ret = scanf("%d", &year);
c = getchar();
}
接下来呢?接下来当然是从不用脑子,打印出来中永恒不变的入手:日历的格式。
for (int month=1; month<=12; month++)
{
printf("\t\t\t%d-%d\n", year, month);
printf("Sun\tMon\tTues\tWed\tThur\tFri\tSat\n");
}
接着我们就要开始花费亿点心思了:怎么确定每月第一天是星期几?怎么确定每月有几天?怎么确定2月是28天还是29天(平年还是闰年)?
首先我们来想想第一个问题。确定每月第一天是星期几,首先要确定每年第一天是星期几。鉴于题目已经给出计算公式:
days=year-1+(year-1)/400+(year-1)/4-(year-1)/100
weekday=(days+1)%7
通过分析我们得知:如果是星期日,weekday=0;如果是星期一至六,weekday分别等于1~6。那么按照这个思路,我们也可以计算每月的第一天是星期几:如果weekday的值为1~6,则为星期一至六;如果为0,则为星期日。
那么怎么确定每个月的第一天是星期几呢?首先得确定上一个月的最后一天是星期几,进而得确定上一个月有多少天对不对?那么我们就需要思考第二个问题:怎么确定每月有几天?我相信这个问题小学生应该更清楚:一月大,二月小,三月大……
因此我们可以定义一个数组:int day[13] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
为什么要把day[0]赋值为0?这是为了让day[month]更好地和month匹配,因为我们的month是从1开始到12结束的。
那么这时候有一个问题:day[2]到底是28还是29?这就涉及到第三个问题:怎么确定某一年是平年还是闰年?通过查阅资料,我们有如下判断方法:符合下列条件之一者是闰年:(1)能被4整除,但不能被100整除;(2)能被400整除。
也就是说,我们可以这样判断:
if (((year%4==0)&&(year%100!=0))||(year%400==0))
{
day[2] = 29;
}
else
{
day[2] = 28;
}
接下来,我们可以整理一下我们的思绪:首先,通过计算我们可以得到某一年的第一天是weekday。假如weekday=3,我们需要在输出1号日期前输出3个'\t',已确保与日历格式相符:
for (int i=0; i<weekday; i++)
{
printf("\t");
}
接下来,我们可以通过以下方式模拟一周的weekday的变化:
for (int i=1; i<=day[month]; i++)
{
if (weekday>6)
{
weekday = 0;
}
weekday++;
}
我们可以使用一个循环来控制日期i的变化,在日期变化的同时,weekday也同步变化,当weekday>6时,为weekday重新置0,即可实现星期的循环。
这样,我们就能大致整理出以下代码:
for (int month=1; month<=12; month++)
{
printf("\t\t\t%d-%d\n", year, month);
printf("Sun\tMon\tTues\tWed\tThur\tFri\tSat\n");//输出日历的格式
for (int i=0; i<weekday; i++)
{
printf("\t");
}//使每月第一天与其是星期几对应
for (int i=1; i<=day[month]; i++)
{
if (weekday>6)
{
printf("\n");//当过了星期六之后换行
weekday = 0;//并把weekday重新从0开始计算
}
printf("%d\t", i);//输出日期
weekday++;//模拟一星期的循环
}
printf("\n");//输出完每个月后换行
}
这样我们就能得到一个如题要求的日历啦~
这个程序还是蛮有意思的,毕竟有了它就不需要买日历了(互联网时代本来就不需要了😄),下面我把这个文件的链接分享至此:C语言教程-小白入门(日历)-C/C++文档类资源-CSDN下载,有需要的uu们可以自取哦。
人们研究事物总是从最简单的开始,而当事物变得复杂时,我们总可以通过若干手段,把复杂的事物分解为一个一个简单的事物。但事物千变万化,我们需要抓住永恒不变的东西,去寻找变化的事物的规律。毕竟,一切事物都有自己的规律。能量守恒定律、动量守恒定律实际上就用到了事物的规律。其实,关于这类格式化屏幕输出的问题,我们需要做的就是紧紧抓住事物变化的规律,找到变化事物与不变事物之间的关系,进而使用一些手段去完成我们的目的。