【问题标题】:Weird output Calendar in CC中奇怪的输出日历
【发布时间】:2016-05-13 15:45:32
【问题描述】:

我用 C 编写了一个非常简单的日历。它以年份作为输入,然后计算该年的日期和工作日。 这假设日期 0001-01-01 是星期一。 除了在一个地方,我已经让它工作得很好。当它即将打印出所有第 31 个日期的行时。 基本上出了问题的是,当它要检查在 4 月 31 日是否有任何要打印的内容(没有)时,它会排除 weekday 变量。这使得以下 31 日日期错误。 有没有人可以看看我是否做错了什么或者可能想帮助我? :)

编辑 忘了说这是一个需要解决的任务,不需要任何计算日期代码等的公式。唯一允许使用的参考是日期 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;
}

【问题讨论】:

  • days_in_month[1] = 29; -> 应该是 days_in_month[2] = 29;
  • 哦,对了,我测试的时候忘记改了,虽然这只适用于闰年,但遗憾的是这不是问题:)
  • 我想你的问题是关于你的代码中的void calendar(int year)。请您详细说明这个函数的预期输入和相应的输出应该是什么?一个示例(可能显示错误)会有所帮助。
  • 是的,没错。它是关于那个功能的。这个函数的输入是用户想要计算日期的年份。 (例如,我可以输入 2016 年,它会显示该年每个月的所有日期和工作日。)这是第 1 年的output screen

标签: c date calendar codeblocks


【解决方案1】:

这里,在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&lt;=31; d++){ loop )你迭代工作日。所以四月一号应该是星期天。如果您检查结果,哪个是有效的。

但是,您按月中的日期计算工作日。所以当我们在三月一号打印 31 时,我们的 day 变量等于 31。

现在,三月结束(我们打印三月的第 31 天),我们的工作日设置为星期日。我们去计算四月的天数。但是看看你的代码,在for(d=1; d&lt;=31; d++) 循环内,你有if(day&gt;days_in_month[m]) {break;}。 当我们的程序检查 4 月的第一天,并且 day 等于 31 时,它会停止使用 break 指令计算 4 月的天数。我们去计算五月的天数。但是我们的工作日仍然是星期日。如果您看到有效代码,首先可能应该是星期二。但是当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

【讨论】:

  • 这种方式似乎解决了我遇到的问题,非常感谢您的详细回答。虽然现在在闰年计算似乎有问题。测试时,我发现第 1,2 和第 3 年的数字匹配。到第 3 年年底,工作日是星期三。但是当我查看第四年时,它从星期六开始,这是完全错误的,应该是星期四。对此有什么想法吗? :)
  • 非常感谢,这已解决。非常感谢您的详细回答:)
【解决方案2】:

您可以调用一个函数来计算给定日期的星期几,而不是保存一个工作日变量。为此,您可以使用 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");
    }               

}

这实际上是一种更有效的生成工作日的方式,而不是循环全年

【讨论】:

  • 我明白了,我可以理解为什么这比我的方法更有效率。但是在我的任务中,我不允许使用在网上找到的任何公式或算法。我唯一可以提及的是日期 0001-01-01 是星期一。 (我知道,这让任务变得更复杂了哈哈)
  • @HampusSiversson:这是一个非常糟糕的起点。您是应该针对 1582 年的公历改革进行调整,还是您的老师追溯调整了(所以实际上之前的日期是错误的)?
  • @HampusSiversson 那么你可以重写函数dayofweek,让它从01-01-0001开始迭代并找到给定日期的星期几
猜你喜欢
  • 2021-12-03
  • 2011-06-14
  • 1970-01-01
  • 2023-01-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-03-05
相关资源
最近更新 更多