为什么这个c代码的结果是"days: 33"而不是"days: 30"?

Why is the result of this c code "days: 33" and not "days: 30"?

我正在为考试而学习,在一次旧考试中被问及以下代码的输出是什么。我对这段代码如何输出“天数:33”感到困惑。有没有办法简单解释一下?

编辑:感谢您的解释,是的,我知道这段代码的逻辑没有意义(就计算给定年份给定月份的实际天数而言),它只是一个旧考试问题。

#include <stdio.h>

int calcDays(int, int);

int main(){

    int days;
    
    days = calcDays(11, 2020);
    
    printf("days: %d\n", days);

    return 0;
}

int calcDays(int month, int yr){

    int days = 28;
    
    switch(month)
    {
        case 2:    days += 1 - yr % 4;
        case 4:
        case 6:
        case 9:
        case 11:   days += 2;
        default:   days += 3;
    }
    
    return(days);
}

你的switch最后没有break,所以一切都会加到days上。试试这个:

switch(month)
{
    case 2:    days += 1 - yr % 4; break;
    case 4:
    case 6:
    case 9:
    case 11:   days += 2; break;
    default:   days += 3; break;
}

您需要防止您的 case 落空:

int calcDays(int month, int yr){

    int days = 28;
    
    switch(month)
    {
        case 2:
          days += leapOffset(yr);
          break;
        case 4:
        case 6:
        case 9:
        case 11:  
          days += 2;
          break;
        default:
          days += 3;
    }
    
    return(days);
}

更简单但更难搞砸的方法:

int calcDays(int month, int yr) {
    switch(month)
    {
        case 2:
          return 28 + leapOffset(yr);
          break;
        case 4:
        case 6:
        case 9:
        case 11:  
          return 30;
          break;
        default:
          return 31;
    }
    
    return(days);
}

这两个都需要有效的 leapOffset() 计算:

int leapOffset(int yr) {
  return ((yr % 4 == 0) && (yr % 100 != 0) || (yr % 400) == 0)) ? 1 : 0;
}

在函数内的switch语句中,这两个标签之间没有break语句

case 11:   days += 2;
default:   days += 3;

所以这些陈述

days += 2;
days += 3;

依次评估。

如果有像

这样的中断语句,你可以得到预期的结果
case 11:   days += 2; break;

default:   days += 3;

例如,如果参数月份设置为 2,则所有这些语句

days += 1 - yr % 4;
days += 2;
days += 3

在此代码段中

case 2:    days += 1 - yr % 4;
case 4:
case 6:
case 9:
case 11:   days += 2;
default:   days += 3

将进行评估。

注意这条语句

days += 1 - yr % 4;

没有意义,因为除以 4 的余数可以是 0、1、2 或 3。

你得到 33 而不是 30,因为在 case:11 中没有中断。你可能想把它写成:

case 11:   {
    days += 2;
    break;
}

一个switch语句是一个“计算跳跃”。它所做的只是跳转到附加语句中的一个标签(通常是包含多个带有标签的语句的复合语句),或者,如果 none 个标签匹配,则跳转到附加语句之外。

因此 switch (month) 跳转到标记为 case 2 的语句或标记为 case 4 的语句,或标记为 case 6 的语句,或标记为 [=15] 的语句=],或者标有 case 11 的那个,或者标有 default 的那个。然后程序继续正常执行:它执行跳转到的语句,然后执行跳转到的语句,再执行后面的语句,依此类推。

标签不会将语句分成单独的集合。案例 2 并未在 case 4 标签所在的位置结束。 case 2 语句执行后,控制继续到 case 4 语句;它不会跳出 switch 语句。

所以,一旦程序跳转到语句case 11: days += 2;,它就会执行days += 2;。然后它继续执行下一条语句,即 default: days += 3;,并执行它。

注意default: days += 3;是语句,case 11: days += 2;也是。在任何语句前面放置一个标签会生成一个新语句:

days += 2; 是一个语句。 case 11: days += 2; 是一个语句(包含另一个语句 days += 2;)。 case 9: case 11: days += 2; 是一个语句(包含另外两个语句)。 case 6: case 9: case 11: days += 2;是语句,依此类推。