Почему мой кредит PSET1 работает в песочнице, но не Check50?

У меня возникает проблема, когда моя кредитная программа PSET1 работает в песочнице CS50 и может определить, является ли карта MasterCard, AMEX или VISA, на основе ее длины и алгоритма Луна. Однако, когда я отправляю код в Check50, он определяет, что все введенные данные недействительны.

Обновление: вместо того, чтобы печатать «INVALID», если число не соответствует алгоритму Луна, я изменил его на печать «nope» и обнаружил, что все числа, проверенные с помощью check50, приводят к выводу «nope», поэтому я знаю, что ошибка где-то в этой части программы. Как и раньше, он по-прежнему работает в песочнице.

Я искал похожие проблемы и решения здесь и в других местах.

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

int main(void)
{
    //Ask user to input number.
    long card_num;
    do
    {
        card_num = get_long("Number: ");   
    }
    //Check if card number is greater than zero.
    while (card_num < 0);

    //Starting with the second to last digit, multiply each digit by 2.
    //Add the products' digits together.
    int digit, prod, sum1, dig1, dig2;
    long holder = card_num;
    while (holder > 0)
    {
        digit = (holder / 10) % 10;
        prod = digit * 2;
        if (prod >= 10)
        {
            dig1 = (prod % 100 - (prod % 10)) / 10;
            dig2 = prod % 10;
            prod = dig1 + dig2;
        }
        sum1 = sum1 + prod;
        holder = holder / 100;
    }

    //Add sum1 to product of the other digits in the card number
    long holder1 = card_num;
    int dig3, sum2;
    while (holder1 > 0)
    {
        dig3 = holder1 % 10;
        sum2 = sum2 + dig3;
        holder1 = holder1 / 100;
    }

    //Check if the sum of the first and second sums has a final digit of 0.
    int last_sum = sum1 + sum2;
    if (last_sum % 10 != 0)
    {
        printf("INVALID\n");
    }
    else
    {
        //Calculate number of digits
    int num_digits = 0;
    long holder3 = card_num;
    while (holder3 != 0)
    {
        holder3 = holder3 / 10;
        num_digits++;
    }

    //Find first two digits of card number
    long holder2 = card_num;
    while (holder2 > 100)
    {
         holder2 = holder2 / 10;
    }
    int firstdig, secdig;
    secdig = holder2 % 10;
    firstdig = holder2 / 10;

    //Check if VISA, Mastercard, or AMEX
    if (firstdig == 4)
    {
        if (num_digits == 13 || num_digits == 16)
        {
            printf ("VISA\n");
        }
    }
    else if (firstdig == 5 && secdig >= 1 && secdig <= 5)
    {
        if (num_digits == 16)
        {
            printf ("MASTERCARD\n");
        }
    }
    else if (firstdig == 3 && (secdig == 4 || secdig == 7))
    {
        if (num_digits == 15)
        {
            printf ("AMEX\n");
        }
    }
    else (printf("INVALID\n"));
    }
}

Ожидаемые результаты: MASTERCARD, VISA, AMEX или INVALID. В песочнице это работает, но Check50 получает НЕДЕЙСТВИТЕЛЬНЫЙ для всех номеров.


person nickrunt    schedule 22.09.2019    source источник
comment
используя: else if (firstdig == 3 && (secdig == 4 || secdig == 7)) { if (num_digits == 15) { printf ("AMEX\n"); } } в качестве примера: если введен первый if (), а второй if () завершился неудачно, то ничего не выводится. Однако должна выводиться некоторая индикация ошибки.   -  person user3629249    schedule 22.09.2019
comment
ОТ: настоятельно рекомендую заменить вызов get_long() на что-то вроде: scanf( "%lu", &card_num );, потому что файл заголовка: cs50.h не переносится и / или доступен не везде   -  person user3629249    schedule 22.09.2019


Ответы (2)


Разные системы могут иметь разную реализацию размера «длинного».

Предлагаю использовать uint64_t из stdint.h, потому что

  1. всегда будет одного размера в разных системах / реализациях
  2. значение должно быть без знака, так как сдвиг значений со знаком проблематичен.

при вызове scanf() предложите использовать спецификатор формата: SCNu64

SCNu64 от inttypes.h

пример для scanf()

uint64_t card_num;
scanf( "%" SCNu64, &card_num );

как проверить номер кредитной карты

Запишите последнюю цифру номера кредитной карты. Это цифра контрольной суммы, которую вы будете использовать для проверки оставшейся части номера кредитной карты.

Перечислите каждую цифру номера кредитной карты, начиная с цифры слева от контрольной суммы и двигаясь влево. Если номер кредитной карты состоит из 16 цифр, удвойте количество каждой цифры в нечетных местах, работая справа налево, прежде чем добавлять его в свой список. Для кредитных карт с 15 цифрами вы должны удвоить цифры в четных местах. Если при удвоении цифры получается число больше 10, сложите две цифры нового числа и запишите этот результат в свой список. Например, если цифра на карточке семь, удвоение ее приведет к 14. Сумма двух цифр будет равна пяти.

Подсчитайте свой список чисел. Не включайте цифру контрольной суммы в свою общую сумму. Если общую сумму можно без остатка разделить на 10, значит на кредитной карте есть действительный номер. В противном случае вам не следует обрабатывать транзакцию по кредитной карте.


Как определить поставщика кредитной карты

Определите компанию, выдавшую кредитную карту, по первому номеру. Карты, начинающиеся с цифры «3», относятся к American Express. Те, которые начинаются с «4», - это кредитные и дебетовые карты Visa, те, которые начинаются с «5», - это кредитные и дебетовые карты MasterCard, а те, которые начинаются с «6», - это кредитные карты Discover. Плата за обслуживание, взимаемая с продавцов, варьируется в зависимости от компании-эмитента.

Подсчитайте цифры в номере кредитной карты. Большинство кредитных карт должны содержать 15 или 16 цифр. Кредитные карты American Express содержат 15. Карты трех других крупных кредитных компаний - Visa, Mastercard и Discover - имеют 16-значную последовательность на своих картах.

person user3629249    schedule 22.09.2019
comment
Я изменил тип переменной с long на uint64_t, но это не решило проблему и создало другую проблему. Грейдер check50 по-прежнему считает, что все числа недействительны, и теперь не отклоняет нечисловые входные данные, а просто выводит, что они недействительны. - person nickrunt; 23.09.2019
comment
Опубликованный код OP не реализует ни необходимый алгоритм для правильной проверки карты, ни необходимые тесты, чтобы определить, какая компания-производитель кредитной карты предоставила карту. - person user3629249; 23.09.2019

Я обнаружил, что проблема заключалась в том, что я объявил переменные sum1 и sum2, но не инициализировал их никакими значениями, поэтому им было присвоено любое значение, находящееся в памяти. Когда я их тоже инициализировал 0, программа работала без проблем.

person nickrunt    schedule 25.09.2019