1

我正在尝试使用 C++ 使用前 12 位来计算 13 位 ISBN 的最后一位。我觉得我的代码应该是正确的,但我觉得我使用的公式可能是错误的。

公式为:

10 - (d0 + d1 * 3 + d2 + d3 * 3 + d4 + d5 * 3 + d6 + d7 * 3 + d8 + d9 * 3 + d10 + d11 * 3) % 10

这是我所拥有的:

#include <cstring>
#include <iostream>

int main() {
    int weightedSum = 0;
    int checksum = 0;
    int i;      //for loop decrement
    int mul = 3;
    const int LENGTH = 12;
    char ISBNinput[LENGTH];

    std::cout << "Enter first 12 digits of ISBN: ";   //ask user for input
    std::cin >> ISBNinput;       //stores input into ISBNinput
    std::cout << std::endl;

    for (i = 0;  i < strlen(ISBNinput);  i++) {

        weightedSum += (ISBNinput[i] % 12) * mul;

        if (mul == 3) {
            mul = 1;
        } else {
            mul = 3;
        }

    }//close for loop

    checksum = weightedSum % 10;        //calculates checksum from weightedSum

    std::cout << checksum << std::endl;       //prints checksum with new line for format

    return 0;
}

例如:

978007063546 应该返回 3

978032133487 应该返回 9

感谢您的任何帮助。

4

2 回答 2

2

这就是我如何解决这个问题。

首先,让我们决定如何测试它。我假设我们已经编写了函数,并且它给出了正确的输出。所以我从办公桌上拿起几本书,并测试它是否适合他们:

#include <iostream>

int main()
{
    std::cout << "Book 1 - expect 3, got " << checksum("978032114653") << std::endl;
    std::cout << "Book 2 - expect 0, got " << checksum("978020163361") << std::endl;
}

当然,当我们尝试编译它时,我们会得到一个错误。所以在之前创建函数main()

char checksum(const char *s)
{
    return '1';
}

现在它编译了,但结果总是1,但现在我们可以开始填充正文了。让我们从一些较小的例子开始,我们可以手动计算;在开头添加这些main()

    std::cout << "1 digit - expect 4, got " << checksum("6") << std::endl;

现在让我们开始工作 - 这让我们至少可以从字符转换为数字并返回:

char checksum(const char *s)
{
    int digit = *s - '0';
    return '0' + 10 - digit;
}

让我们试试 2 位数字:

    std::cout << "1 digit - expect 6, got " << checksum("11") << std::endl;

现在我们的测试又失败了。所以添加一些更多的处理,使这个通过(而不是打破个位数的测试):

char checksum(const char *s)
{
    int sum = 0;
    int digit = *s - '0';
        sum += digit;
    ++s;
    if (*s) {
        digit = *s - '0';
        sum += 3 * digit;
    }
    return '0' + (10 - sum)%10;
}

我们现在可能已经准备好把它变成一个循环了。一旦通过,我们不再需要简短的测试,我有:

#include <iostream>

char checksum(const char *s)
{
    int sum = 0;
    for (int mul = 1;  *s;  ++s) {
        int digit = *s - '0';
        sum += mul * digit;
        mul = 4 - mul;
    }
    return '0' + (1000 - sum)%10;
}

int test(const char *name, char expected, const char *input)
{
    char actual = checksum(input);
    if (actual == expected) {
        std::cout << "PASS: " << name << ": "
                  << input << " => " << actual
                  << std::endl;
        return 0;
    } else {
        std::cout << "FAIL: " << name << ": "
                  << input << " => " << actual
                  << " - expected " << expected
                  << std::endl;
        return 1;
    }
}

int main()
{
    int failures = 0;
    failures += test("Book 1", '3', "978032114653");
    failures += test("Book 2", '0', "978020163361");
    return failures > 0;
}

我在这里将实际检查分解为一个函数,因此我们可以记录失败次数,并以适当的状态退出,但其他一切都如我上面所述。

您将需要添加更多测试用例 - 特别是,确保函数正确返回极值0以及9何时返回。

于 2015-12-01T10:28:16.997 回答
1

您的代码中有一个明显的错误:您没有在 for 中分​​配足够的空间ISBNinput。你应该让它长一个字符:

const int LENGTH = 13;

这样做的原因是字符数组字符串以一个额外的空字符终止。你可能很幸运,内存中的下一个字节有时恰好是一个空字节,在这种情况下,程序有时仍然可以工作。

如果您使用 valgrind 或类似的内存检查器运行程序,您可能会看到错误,因为程序访问的内存超出了堆栈上分配的内存。

另外我认为还有另一个错误。我认为mul应该初始化为1.

顺便说一句,这段代码非常脆弱,取决于你输入的字符不超过 12 个,所有字符都假定为数字。作为概念验证的快速破解,它可能是可以的,但不应在任何实际程序中使用。

于 2015-12-01T05:53:45.963 回答