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