《三行代码判断闰年?这才是正确写法!》

《你真的会写闰年判断吗?90%的人都忽略了这些细节》

大家好,今天来聊一个看起来很简单,但处处藏着"门道"的编程问题——如何判断闰年。

先看最原始的代码

很多C语言初学者第一次写的闰年判断代码大概是这样:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>

int main() {
    int year = 0;
    scanf("%d", &year);
    
    if ((year % 4 == 0 && year % 100 != 0) || (year % 400 == 0))
        printf("是闰年");
    else
        printf("不是闰年");
    
    return 0;
}

这段代码能跑,逻辑也对,但它离"工程级"代码还差得远

今天我们就从这十几行代码出发,看看如何把一个"玩具级"程序写成"专业级"代码。


先搞懂:为什么闰年的规则这么奇怪?

在看代码之前,先搞懂一个常识问题:为什么闰年是"4年一闰,百年不闰,四百年再闰"?

答案很简单:地球绕太阳转一圈不是刚好365天,而是365天5小时48分46秒(约365.2422天)。

如果每年都按365天算,每4年就少算了约23小时15分,所以加1天补上——这就是"4年一闰"。

但这样每4年又多补了45分钟,累积400年就多算了3天,所以每400年要减去3个闰年——这就是"百年不闰,四百年再闰"。

翻译成代码逻辑就是:

能被4整除 并且 不能被100整除
            或者
能被400整除

对应:(year % 4 == 0 && year % 100 != 0) || (year % 400 == 0)


第一次优化:封装成函数

上面的代码把所有逻辑都堆在main函数里,复用性很差。如果另一个地方也要判断闰年怎么办?复制粘贴?

我们来把核心逻辑抽成独立函数:

#include <stdio.h>
#include <stdbool.h>  // 用bool类型比int更语义化

/**
 * @brief 判断给定年份是否为闰年
 * @param year 待判断的年份
 * @return 是闰年返回true,否则返回false
 */
bool is_leap_year(int year) {
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

int main() {
    int year;
    printf("请输入年份:");
    scanf("%d", &year);
    
    if (is_leap_year(year))
        printf("%d 是闰年\n", year);
    else
        printf("%d 不是闰年\n", year);
    
    return 0;
}

优点:

  1. 语义清晰:函数名is_leap_year一眼就知道干啥的
  2. 可复用:任何地方需要判断闰年,直接调用这个函数就行
  3. 易测试:可以单独测试这个函数的正确性

第二次优化:加上边界校验

你有没有想过,如果用户输入-2024或者0会怎么样?代码照样跑,但结果毫无意义。

公历(格里高利历)是1582年才开始实行的,所以1582年之前的年份用这套规则判断是不准确的。专业的代码必须处理非法输入:

bool is_leap_year(int year) {
    // 边界校验:年份必须大于等于1582年
    if (year < 1582) {
        printf("⚠️  警告:公历闰年规则从1582年开始适用\n");
        return false;
    }
    
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

很多人写代码只考虑"正确输入",但专业程序员会花50%的精力考虑"错误输入"


第三次优化:写个测试用例

怎么证明你的代码是对的?靠脑子想几个测试用例?太不专业了。

直接写个自动化测试:

int main() {
    // 测试用例:覆盖各种边界情况
    int test_years[] = {
        2024,   // 普通闰年 ✓
        2023,   // 平年 ✗
        2000,   // 400年闰年 ✓
        1900,   // 能被100整除但不能被400整除 ✗
        1600,   // 400年闰年 ✓
        1582,   // 公历起始年 ✗
        1581,   // 公历之前 ❌
        0,      // 非法输入 ❌
        -2024   // 非法输入 ❌
    };
    
    int n = sizeof(test_years) / sizeof(test_years[0]);
    
    printf("========== 闰年测试 ==========\n");
    for (int i = 0; i < n; i++) {
        bool result = is_leap_year(test_years[i]);
        printf("%4d -> %s\n", test_years[i], 
               result ? "是闰年 ✅" : "不是闰年 ❌");
    }
    printf("==============================\n");
    
    return 0;
}

运行结果:

========== 闰年测试 ==========
2024 -> 是闰年 ✅
2023 -> 不是闰年 ❌
2000 -> 是闰年 ✅
1900 -> 不是闰年 ❌
1600 -> 是闰年 ✅
1582 -> 不是闰年 ❌
⚠️  警告:公历闰年规则从1582年开始适用
1581 -> 不是闰年 ❌
⚠️  警告:公历闰年规则从1582年开始适用
   0 -> 不是闰年 ❌
⚠️  警告:公历闰年规则从1582年开始适用
-2024 -> 不是闰年 ❌
==============================

所有边界情况一目了然。


90%的人都会犯的3个错误

❌ 错误1:漏加括号

// 虽然运算符优先级没错,但可读性差
if (year % 4 == 0 && year % 100 != 0 || year % 400 == 0)

括号不只是给编译器看的,更是给人看的。多写一对括号,拯救无数后来人

❌ 错误2:逻辑写反

// 手滑把 != 写成了 ==,1900年就会被误判为闰年
if ((year % 4 == 0 && year % 100 == 0) || (year % 400 == 0))

❌ 错误3:忘记"百年不闰"

// 这是最常见的错误!1900、2100、2200都会被误判
if (year % 4 == 0)

完整的最终版代码

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdbool.h>

/**
 * @brief 判断给定年份是否为闰年(公历1582年起适用)
 * @param year 待判断的年份(必须 >= 1582)
 * @return 是闰年返回true,否则返回false
 */
bool is_leap_year(int year) {
    // 边界校验:公历从1582年开始实行
    if (year < 1582) {
        printf("⚠️  警告:公历闰年规则从1582年开始适用\n");
        return false;
    }
    
    // 标准闰年判断逻辑
    return (year % 4 == 0 && year % 100 != 0) || (year % 400 == 0);
}

int main() {
    // ========== 测试模式 ==========
    int test_years[] = {2024, 2023, 2000, 1900, 1600, 1582, 1581, 0, -2024};
    int n = sizeof(test_years) / sizeof(test_years[0]);
    
    printf("========== 闰年测试 ==========\n");
    for (int i = 0; i < n; i++) {
        bool result = is_leap_year(test_years[i]);
        printf("%4d -> %s\n", test_years[i], 
               result ? "是闰年 ✅" : "不是闰年 ❌");
    }
    printf("==============================\n\n");
    
    // ========== 交互模式 ==========
    int year;
    printf("请输入年份:");
    scanf("%d", &year);
    
    if (is_leap_year(year))
        printf("%d 是闰年\n", year);
    else
        printf("%d 不是闰年\n", year);
    
    return 0;
}

判断闰年是编程入门最基础的题目,但从"能跑"到"好用"之间隔着好几个层级:

  1. 功能正确 → 逻辑没写错
  2. 可读性好 → 别人能看懂
  3. 边界安全 → 处理非法输入
  4. 可测试 → 容易验证正确性

所谓"优秀的代码",无非就是把这些小事做到极致。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值