You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

CS50 2022 Problem Set 1 (Credit) 信用卡校验代码错误求助

信用卡号Luhn校验代码错误排查

我尝试通过以下步骤验证信用卡号:

  • 从卡号倒数第二位开始,每隔一位数字乘2,再将这些乘积的各位数字相加。
  • 将上述结果与未乘2的各位数字之和相加。
  • 检查总和的最后一位是否为0。

但编写的C代码在测试有效AMEX卡号371449635398431时返回INVALID,代码如下:

int main(void)
{
    // TODO Prompt for input (DONE)
    long cardnumber;
    do
    {
        cardnumber = get_long("Card no: ");
    }
    while (cardnumber < 0); // Card number must be greater than 0

    // TODO Calculate checksum

    // Get every other digit
    int second = ((cardnumber / 10) % 10);
    int fourth = ((cardnumber / 1000) % 10);
    int sixth = ((cardnumber / 100000) % 10);
    int eighth = ((cardnumber / 10000000) % 10);
    int tenth = ((cardnumber / 1000000000) % 10);
    int twelth = ((cardnumber / 100000000000) % 10);
    int fourteenth = ((cardnumber / 10000000000000) % 10);
    int sixteenth = ((cardnumber / 1000000000000000) % 10);

    // Multiply every other digit by 2 then add those digits
    int checksumpart1 = (second * 2 + fourth * 2 + sixth * 2 + eighth * 2 + tenth * 2 + twelth * 2 + fourteenth * 2 + sixteenth * 2);

    // Get every other other digit
    int first = (cardnumber % 10);
    int third = ((cardnumber / 100) % 10);
    int fifth = ((cardnumber / 10000) % 10);
    int seventh = ((cardnumber / 1000000) % 10);
    int ninth = ((cardnumber / 100000000) % 10);
    int eleventh = ((cardnumber / 10000000000) % 10);
    int thirteenth = ((cardnumber / 1000000000000) % 10);
    int fifteenth = ((cardnumber / 100000000000000) % 10);

    // Sum of every other digit
    int checksumpart2 = (first + third + fifth + seventh + ninth + eleventh + thirteenth + fifteenth);

    // Validity check addition of first two sums
    int checksumfinal = ((checksumpart1 + checksumpart2) % 10);

    // Print AMEX or INVALID

    // validate checksum
    if (checksumfinal != 0) {
        printf("INVALID\n");
    } else {
        printf("VALID\n");
    }
}

错误分析

  1. 核心逻辑错误:未拆分乘积的各位数字相加
    计算checksumpart1时,直接将乘2后的数字相加,不符合Luhn算法要求。比如数字7乘2得14,应该将1+4=5加入总和,而非直接加14。

  2. 卡号长度适配问题
    AMEX卡号为15位,但代码固定按16位提取数字,导致sixteenth等高位变量为0,虽不是当前测试失败的主因,但会影响其他长度卡号的校验。

修正方案

方案1:修复当前代码的计算逻辑

新增一个辅助函数拆分乘积的各位数字,修改checksumpart1的计算方式:

// 新增辅助函数:计算数字的各位和
int sum_digits(int n) {
    return (n / 10) + (n % 10);
}

// 替换原checksumpart1的计算代码
int checksumpart1 = sum_digits(second * 2) + sum_digits(fourth * 2) + sum_digits(sixth * 2) + 
                    sum_digits(eighth * 2) + sum_digits(tenth * 2) + sum_digits(twelth * 2) + 
                    sum_digits(fourteenth * 2) + sum_digits(sixteenth * 2);

方案2:改用循环处理任意长度卡号(更健壮)

固定提取位数的方式扩展性差,建议用循环遍历卡号每一位,自动适配不同长度:

int main(void)
{
    long cardnumber;
    do
    {
        cardnumber = get_long("Card no: ");
    }
    while (cardnumber < 0);

    long temp = cardnumber;
    int checksumpart1 = 0;
    int checksumpart2 = 0;
    int count = 0;

    while (temp > 0)
    {
        int digit = temp % 10;
        count++;
        // 倒数第1、3、5...位(未乘2的位)
        if (count % 2 == 1)
        {
            checksumpart2 += digit;
        }
        // 倒数第2、4、6...位(需乘2后拆位相加)
        else
        {
            int doubled = digit * 2;
            checksumpart1 += (doubled / 10) + (doubled % 10);
        }
        temp /= 10;
    }

    int checksumfinal = (checksumpart1 + checksumpart2) % 10;

    if (checksumfinal != 0) {
        printf("INVALID\n");
    } else {
        // 可在此补充卡号开头数字和长度校验,区分AMEX/VISA/MASTERCARD等
        printf("VALID\n");
    }
}

测试验证

用卡号371449635398431测试修正后的代码,会正确返回VALID。

内容的提问来源于stack exchange,提问作者DKXP

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.11 01:15:53