You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

为何校验和程序陷入死循环?求问题排查与修复建议

排查Luhn校验和程序的死循环问题及修复方案

嘿,我来帮你揪出代码里死循环的根源,顺便给你靠谱的修复建议~你的代码里有两处核心的循环逻辑错误,还有一些容易踩坑的细节问题,咱们一步步拆解:

一、死循环的核心原因

1. 内层循环条件完全逻辑错误

你写内层循环是为了计算2*current_digit的各位数字之和,但循环条件写的是:

while (fmod(second_number, pow(10,j)) == number);

这个逻辑完全跑偏了——fmod(second_number, pow(10,j))是取second_number的后j位,而number是原始的大数字,这两个值几乎不可能相等,所以内层循环会一直跑下去,直接卡死。

2. 外层循环的递增逻辑缺失

在外层循环里,你只在else分支(需要乘2的位数)里写了i++,但if分支(不需要乘2的位数)完全没有让i递增的代码!这就导致当处理到不需要乘2的位数时,i永远停在同一个值,外层循环会反复处理同一位数字,直接陷入死循环。

另外,外层循环的停止条件while (fmod(number,pow(10, i)) != number);逻辑也不够严谨,不过相比前面两个问题,这个是次要的。

二、额外的坑:用double存储长数字的隐患

double来存储银行卡号这类长数字是非常危险的——double的精度有限,最多能精确表示15-17位十进制数,当数字超过这个长度,会丢失末尾的精度,导致你取出来的数字完全错误。建议要么用字符串处理(最可靠),要么用long long(如果数字长度在19位以内)。

三、修复后的代码(推荐字符串版本)

我给你重写了代码,解决了死循环问题,同时改用字符串处理(彻底避免精度问题),逻辑也更清晰:

#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>

string input(void);
int main(void) {
    string number = input();
    int sum = 0;
    int len = strlen(number);

    // 处理需要乘2的位数:从倒数第二位开始,每隔一位往前
    for (int i = len - 2; i >= 0; i -= 2) {
        int digit = number[i] - '0';
        int product = digit * 2;
        // 简化乘积的各位和计算:>=10时,等价于product-9(比如14=1+4=5=14-9)
        sum += (product >= 10) ? (product - 9) : product;
    }

    // 处理不需要乘2的位数:从倒数第一位开始,每隔一位往前
    for (int i = len - 1; i >= 0; i -= 2) {
        sum += number[i] - '0';
    }

    printf(sum % 10 == 0 ? "true\n" : "false\n");
    return 0;
}

string input(void) {
    string number = get_string("Number: ");
    // 简单校验输入是否全为数字
    for (int i = 0; number[i] != '\0'; i++) {
        if (!isdigit(number[i])) {
            printf("请输入有效的纯数字!\n");
            return input();
        }
    }
    return number;
}

四、修复要点说明

  1. 改用字符串处理:直接按字符遍历每一位,彻底避免double的精度丢失问题,逻辑也更直观。
  2. 拆分循环逻辑:把需要乘2的位数和不需要乘2的位数分成两个独立循环,避免嵌套循环的混乱,可读性更强。
  3. 简化乘积求和:当乘积>=10时,各位数字之和等价于product - 9,不用再嵌套循环逐位取数,效率更高。
  4. 严格遵循算法要求:从字符串末尾往前遍历,完全符合Luhn算法“从倒数第二位开始每隔一位乘2”的规则。

如果你坚持想用数字类型处理(不推荐),也可以修正循环逻辑:

  • 内层循环改成用整数处理:把second_number转成int,然后用while (second_number > 0),每次取余10加和,再除以10。
  • 外层循环里,不管if还是else分支,都要执行i++,并且循环条件改成pow(10, i-1) <= number(确保遍历完所有位数)。

不过还是字符串版本的代码更稳定、更容易维护。

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

火山引擎 最新活动