C 中奇怪的输出日历
Weird output Calendar in C
我用 C 编写了一个非常简单的日历。它以年份作为输入,然后计算那一年的日期和工作日。
这假设日期 0001-01-01 是星期一。
除了在一个地方,我已经让它工作得很好。当它要打印出所有第 31 个日期的行时。
基本上出了问题的是,当它要检查是否有任何东西要在 4 月 31 日打印时(实际上没有),它会排除工作日变量。这使得以下第 31 个日期错误。
有没有人可以看到我是否做错了什么或者可能想帮助我? :)
EDIT 忘了说这是一个需要解决的任务,没有任何计算日码等的公式。唯一允许使用的参考是日期 0001-01-01 是星期一。
这是我的代码。 (是的,atm 有点乱,但我还在学习。)
int isLeapYear(int year){
if(((year%4==0) && (year%100!=0)) || (year%400==0)){
return 1;
}
else
return 0;
}
int getYear(){
int year = 0;
while(year==0 || year < 0){
printf("Enter year: ");
scanf("%d", &year);
if(year > 0){
break;
}
printf("Invalid input. Try again.\n\n");
}
return year;
}
void printWeekday(int w){
switch(w){
case 0:
printf("Sun");
break;
case 1:
printf("Mon");
break;
case 2:
printf("Tue");
break;
case 3:
printf("Wed");
break;
case 4:
printf("Thu");
break;
case 5:
printf("Fri");
break;
case 6:
printf("Sat");
break;
}
}
void printMonth(int m){
switch(m){
case 1:
printf("Jan");
break;
case 2:
printf(" Feb");
break;
case 3:
printf(" Mar");
break;
case 4:
printf(" Apr");
break;
case 5:
printf(" May");
break;
case 6:
printf(" Jun");
break;
case 7:
printf(" Jul");
break;
case 8:
printf(" Aug");
break;
case 9:
printf(" Sep");
break;
case 10:
printf(" Oct");
break;
case 11:
printf(" Nov");
break;
case 12:
printf(" Dec\n");
break;
}
}
void calendar(int year){
int y = 1;
int m = 1;
int d = 1;
int loop = 1;
int day = 1;
int days_in_month[14] = {0,31,28,31,30,31,30,31,31,30,31,30,31,0};
if(isLeapYear(year)){
days_in_month[1] = 29;
}
for(m=1; m<=12; m++){
printMonth(m);
}
while(loop){
int weekday = 1;
for(y=1; y<=year; y++){
for(m=1; m<=12; m++){
for(d=1; d<=31; d++){
if(weekday%7 == 0){
// printf("h");
weekday = 0;
}
if(y==year){
if(day>days_in_month[m]){
printf(" ");
printf("%d", weekday);
break;
}else if(d == day){
//printf("%d", weekday);
if(m == 1){
printf("%02d ", d);
printWeekday(weekday);
}else if(m == 12){
printf(" %02d ", d);
printWeekday(weekday);
printf("\n");
}else{
printf(" %02d ", d);
printWeekday(weekday);
}
}
}
if(d<=days_in_month[m]){
weekday = weekday + 1;
}
}
}
}
day++;
if(day == 32){
break;
}
}
}
int main()
{
int end = 1;
while(end){
int year = getYear();
printf(" %d\n", year);
calendar(year);
printf("\nEnter 0 to quit: ");
scanf("%d", &end);
//system("cls");
}
return 0;
}
您可以调用一个函数来计算给定日期的星期几,而不是保存工作日变量。为此,您可以使用 Tomohiko Sakamoto 的星期几算法。
int dayofweek(int d, int m , int y){
static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
y -= m < 3;
return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
// 0 - Sunday
// 1 - Monday and so on
如果你想了解这个算法,你可以在这里看到详细的解释:https://www.quora.com/How-does-Tomohiko-Sakamotos-Algorithm-work
但是因为你是初学者,我不会真的推荐它:)它有点混乱。
实现后,您可以将日历功能简化为
void calendar(int year) {
int days_in_month[14] = { 0,31,28,31,30,31,30,31,31,30,31,30,31,0 };
if (isLeapYear(year)) {
days_in_month[2] = 29;
}
for (int m = 1; m<=12; m++) {
printMonth(m);
}
for (int d = 1; d<=31; d++) {
for (int m = 1; m<=12; m++) {
if (d <= days_in_month[m]) {
int weekday = dayofweek(d, m, year);
printf("%02d ", d);
printWeekday(weekday);
printf(" ");
}
else {
printf(" ");
}
}
printf("\n");
}
}
这实际上是一种更有效的生成工作日的方法,而不是循环遍历全年
在这里,在 calendar()
函数中添加以下代码:
if(day>days_in_month[m] /*Add this code: */ && d>days_in_month[m]){
printf(" ");
printf("%d", weekday);
break;
}else if(d == day){...
问题出在哪里?那么,你看到 3 月 31 日了吗?今天是星期六:
在几天的迭代结束时(我的意思是 for(d=1; d<=31; d++){
循环)你迭代工作日。所以四月一号应该是星期天。如果您检查结果,这是有效的。
但是,您是按月份计算工作日的。所以当我们在三月的第一天打印 31 时,我们的 day
变量等于 31。
现在,三月结束了(我们打印三月的第31天),我们的工作日定在星期天。我们去计算四月的天数。但是看看你的代码,在 for(d=1; d<=31; d++)
循环中,你有 if(day>days_in_month[m]) {break;}
。
当我们的程序检查四月的第一天,并且 day
等于 31 时,它会停止使用 break
指令计算四月的天数。我们去计算五月的天数。但是我们的工作日仍然是星期日。如果您看到有效代码,首先应该是星期二。但是当 day
变量等于 31 时,第一个可能作为星期日开始。从 5 月 1 日开始,所有日子都计算错误。
闰年问题:
因为你使用这个:
if(isLeapYear(year)){
days_in_month[2] = 29;
}
它每年增加第 29 天(所以你在前三年中增加三个第 29 天,你会在第 4 年的 1 月 1 日看到结果:))。
要解决它,删除那些代码。在几个月的循环中,添加代表天数的变量:
for(m=1; m<=12; m++){
int monthDays = days_in_month[m]; /*Add this variable*/
if (m==2 && isLeapYear(y))
monthDays++; // Add 29th day to feb. of leap year
for(d=1; d<=31; d++){...
并且在函数内部,将所有 days_in_month[m]
替换为 monthDays
我用 C 编写了一个非常简单的日历。它以年份作为输入,然后计算那一年的日期和工作日。 这假设日期 0001-01-01 是星期一。 除了在一个地方,我已经让它工作得很好。当它要打印出所有第 31 个日期的行时。 基本上出了问题的是,当它要检查是否有任何东西要在 4 月 31 日打印时(实际上没有),它会排除工作日变量。这使得以下第 31 个日期错误。 有没有人可以看到我是否做错了什么或者可能想帮助我? :)
EDIT 忘了说这是一个需要解决的任务,没有任何计算日码等的公式。唯一允许使用的参考是日期 0001-01-01 是星期一。
这是我的代码。 (是的,atm 有点乱,但我还在学习。)
int isLeapYear(int year){
if(((year%4==0) && (year%100!=0)) || (year%400==0)){
return 1;
}
else
return 0;
}
int getYear(){
int year = 0;
while(year==0 || year < 0){
printf("Enter year: ");
scanf("%d", &year);
if(year > 0){
break;
}
printf("Invalid input. Try again.\n\n");
}
return year;
}
void printWeekday(int w){
switch(w){
case 0:
printf("Sun");
break;
case 1:
printf("Mon");
break;
case 2:
printf("Tue");
break;
case 3:
printf("Wed");
break;
case 4:
printf("Thu");
break;
case 5:
printf("Fri");
break;
case 6:
printf("Sat");
break;
}
}
void printMonth(int m){
switch(m){
case 1:
printf("Jan");
break;
case 2:
printf(" Feb");
break;
case 3:
printf(" Mar");
break;
case 4:
printf(" Apr");
break;
case 5:
printf(" May");
break;
case 6:
printf(" Jun");
break;
case 7:
printf(" Jul");
break;
case 8:
printf(" Aug");
break;
case 9:
printf(" Sep");
break;
case 10:
printf(" Oct");
break;
case 11:
printf(" Nov");
break;
case 12:
printf(" Dec\n");
break;
}
}
void calendar(int year){
int y = 1;
int m = 1;
int d = 1;
int loop = 1;
int day = 1;
int days_in_month[14] = {0,31,28,31,30,31,30,31,31,30,31,30,31,0};
if(isLeapYear(year)){
days_in_month[1] = 29;
}
for(m=1; m<=12; m++){
printMonth(m);
}
while(loop){
int weekday = 1;
for(y=1; y<=year; y++){
for(m=1; m<=12; m++){
for(d=1; d<=31; d++){
if(weekday%7 == 0){
// printf("h");
weekday = 0;
}
if(y==year){
if(day>days_in_month[m]){
printf(" ");
printf("%d", weekday);
break;
}else if(d == day){
//printf("%d", weekday);
if(m == 1){
printf("%02d ", d);
printWeekday(weekday);
}else if(m == 12){
printf(" %02d ", d);
printWeekday(weekday);
printf("\n");
}else{
printf(" %02d ", d);
printWeekday(weekday);
}
}
}
if(d<=days_in_month[m]){
weekday = weekday + 1;
}
}
}
}
day++;
if(day == 32){
break;
}
}
}
int main()
{
int end = 1;
while(end){
int year = getYear();
printf(" %d\n", year);
calendar(year);
printf("\nEnter 0 to quit: ");
scanf("%d", &end);
//system("cls");
}
return 0;
}
您可以调用一个函数来计算给定日期的星期几,而不是保存工作日变量。为此,您可以使用 Tomohiko Sakamoto 的星期几算法。
int dayofweek(int d, int m , int y){
static int t[] = { 0, 3, 2, 5, 0, 3, 5, 1, 4, 6, 2, 4 };
y -= m < 3;
return (y + y/4 - y/100 + y/400 + t[m-1] + d) % 7;
}
// 0 - Sunday
// 1 - Monday and so on
如果你想了解这个算法,你可以在这里看到详细的解释:https://www.quora.com/How-does-Tomohiko-Sakamotos-Algorithm-work
但是因为你是初学者,我不会真的推荐它:)它有点混乱。
实现后,您可以将日历功能简化为
void calendar(int year) {
int days_in_month[14] = { 0,31,28,31,30,31,30,31,31,30,31,30,31,0 };
if (isLeapYear(year)) {
days_in_month[2] = 29;
}
for (int m = 1; m<=12; m++) {
printMonth(m);
}
for (int d = 1; d<=31; d++) {
for (int m = 1; m<=12; m++) {
if (d <= days_in_month[m]) {
int weekday = dayofweek(d, m, year);
printf("%02d ", d);
printWeekday(weekday);
printf(" ");
}
else {
printf(" ");
}
}
printf("\n");
}
}
这实际上是一种更有效的生成工作日的方法,而不是循环遍历全年
在这里,在 calendar()
函数中添加以下代码:
if(day>days_in_month[m] /*Add this code: */ && d>days_in_month[m]){
printf(" ");
printf("%d", weekday);
break;
}else if(d == day){...
问题出在哪里?那么,你看到 3 月 31 日了吗?今天是星期六:
在几天的迭代结束时(我的意思是 for(d=1; d<=31; d++){
循环)你迭代工作日。所以四月一号应该是星期天。如果您检查结果,这是有效的。
但是,您是按月份计算工作日的。所以当我们在三月的第一天打印 31 时,我们的 day
变量等于 31。
现在,三月结束了(我们打印三月的第31天),我们的工作日定在星期天。我们去计算四月的天数。但是看看你的代码,在 for(d=1; d<=31; d++)
循环中,你有 if(day>days_in_month[m]) {break;}
。
当我们的程序检查四月的第一天,并且 day
等于 31 时,它会停止使用 break
指令计算四月的天数。我们去计算五月的天数。但是我们的工作日仍然是星期日。如果您看到有效代码,首先应该是星期二。但是当 day
变量等于 31 时,第一个可能作为星期日开始。从 5 月 1 日开始,所有日子都计算错误。
闰年问题: 因为你使用这个:
if(isLeapYear(year)){
days_in_month[2] = 29;
}
它每年增加第 29 天(所以你在前三年中增加三个第 29 天,你会在第 4 年的 1 月 1 日看到结果:))。
要解决它,删除那些代码。在几个月的循环中,添加代表天数的变量:
for(m=1; m<=12; m++){
int monthDays = days_in_month[m]; /*Add this variable*/
if (m==2 && isLeapYear(y))
monthDays++; // Add 29th day to feb. of leap year
for(d=1; d<=31; d++){...
并且在函数内部,将所有 days_in_month[m]
替换为 monthDays