CS50 Problem Set 1 (Credit) 2020 Требуется помощь - PullRequest
0 голосов
/ 27 февраля 2020

Я пытаюсь запросить у пользователя номер кредитной карты и определить, является ли это реальным номером кредитной карты или нет, и если да, то какой тип номера кредитной карты.

Я думал, что наконец-то однако, при выполнении check50 следующие два ввода не выдают никаких результатов:

  • 1234567890
  • 4111111111111113

Они должны выдавать INVALID, но я не могу выяснить, почему они не дают никакого вывода.

Это мой код:

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

int main(void)

{
    long Card_Number;
    int Digit_Number = 0, Current_Digit = 0, Even_x2_Product = 0, Even_Digits = 0, Odd_Digits = 0,
        Total_Digit_Sum = 0;
    bool is_even = false;

// Prompt User for Credit Card Number

    do
    {
        Card_Number = get_long("Card Number: ");
    }
    while (Card_Number < 0);

// Check First Digits of Number

    int Digits_MstrCrd = Card_Number / pow(10, 14);
    int Digits_Visa_16 = Card_Number / pow(10, 15);
    int Digits_AmEx = Card_Number / pow(10, 13);
    int Digits_Visa_13 = Card_Number / (pow(10, 12));

// Loop to determine identity of each digit

    while (Card_Number != 0)
    {
        // Get Last Digit of Number

        Current_Digit = (Card_Number % 10);

        // Increase Digit Number by 1 

        Digit_Number += 1;

        // Check if Current Digit is at Odd or Even Position in Card Number

        if (is_even == true)
        {
            // Multiply Digit by 2

            Even_x2_Product = Current_Digit * 2;

            // Add Digits of Multiplication Product

            while (Even_x2_Product != 0)
            {
                Even_Digits += Even_x2_Product % 10;
                Even_x2_Product /= 10;
            }

            // Tell Program Next Digit is Odd

            is_even = false; 
        }
        else 
        {
            // Add Odd Digits

            Odd_Digits += Current_Digit;

            // Tell Program Next Number is Even 

            is_even = true; 
        }

        // Remove Last Digit and Repeat

        Card_Number /= 10;
    }

    // Add Odd and Even Digits Together

    Total_Digit_Sum = Even_Digits + Odd_Digits;

// Loop to Check if Card Number is Valid

    if (Total_Digit_Sum % 10 == 0)
    {
        // Check Mastercard

        if (Digit_Number == 16)
        {
            if (Digits_MstrCrd <= 55 && Digits_MstrCrd >= 51)
            {
                printf("MASTERCARD\n");
            }

            // Check Visa 16

            else if (Digits_Visa_16 == 4)
            {
                printf("VISA\n");
            }
            else
            {
                printf("INVALID\n");
            }
        }

        // Check American Express

        else if (Digit_Number == 15)
        {
            if (Digits_AmEx == 34 || Digits_AmEx == 37)
            {
                printf("AMEX\n");
            }
            else 
            {
                printf("INVALID\n");
            }
        }

        // Check Visa 13

        else if (Digit_Number == 13)
        {
            if (Digits_Visa_13 == 4)
            {
                printf("VISA\n");
            }
            else
            {
                printf("INVALID\n");
            }
        }
        else 
        {
            printf("INVALID\n");
        }
    }
}



Ответы [ 2 ]

2 голосов
/ 27 февраля 2020

Что печатает программа, если Total_Digit_Sum % 10 равно не равно 0? У него нет else; после закрытия } блока нет никаких команд.

1 голос
/ 29 февраля 2020

Я покажу вам в вашей программе (со встроенными многострочными комментариями) все объектные вещи, которые я видел простым осмотром (мне пришлось немного его изменить, поскольку вы не предоставляете реализацию get_long(char *prompt) function, и некоторые другие файлы, которые вы также не предоставляете. Позже я дам вам лучшее решение, в котором нет проблемы целочисленного предела, поскольку он использует строки для вычисления контрольной суммы. В конце есть ссылка на репозиторий github, в котором рассматриваются все версии решения (включая DFA --- Deterministi c Finite Automaton - вероятно, самое быстрое решение проблемы)

/* sorry, I need to comment this, as you have not provided this
 * file. */
//#include <cs50.h>

/* you don't need math.h if you are using only integers */
//#include <math.h>

/* what is needed is stdbool.h, to use booleans  in C */
#include <stdbool.h>
#include <stdio.h> /* and stdio, of course */

unsigned long long get_long(char *prmpt)
{
        unsigned long long result;

        fprintf(stderr, "%s> ", prmpt);

        /* this loop is not protected against EOF, so you will have
         * to interrupt the program if you reach the end of file
         * here. */
        while (scanf("%llu", &result) != 1)
                fprintf(stderr, "?? >");
        return result;
}

int main(void)

{
        /* you need a 64bit number, so better use a long long here
         * 32bit integers range only up to 4294967296, which is too
         * short to use in your problem.
         * on dividing your card number by 100000000000000 you'll
         * allways get 0.
         */
    long Card_Number;
    int Digit_Number = 0, Current_Digit = 0, Even_x2_Product = 0, Even_Digits = 0, Odd_Digits = 0,
        Total_Digit_Sum = 0;
    bool is_even = false;

// Prompt User for Credit Card Number

    do
    {
        Card_Number = get_long("Card Number: ");
    }
    while (Card_Number < 0);

// Check First Digits of Number

        /* don't use pow(3) to produce a constant to divide 
         * in floating point by a power of ten.  It allways
         * produces inexact results, ad 1/10 cannot be represented
         * as a finite number of digits in base 2.  Just use
         * 100000000000000LL, instead. 
         * In order to get the ttype of card, it is better to compare
         * the number, as in
         * // number is 15digits, at least
         * if (Card_number >= 1000000000000000ULL) {
         *      Digit_number = 15;
         * } else if (Card_number >= 10000000000000ULL) {
         *      Digit number = 14;
         * } else if (Card_number >= 1000000000000ULL) {
         *      Digit_number = 13;
         *  ...
         */
    int Digits_MstrCrd = Card_Number / pow(10, 14);
    int Digits_Visa_16 = Card_Number / pow(10, 15);
    int Digits_AmEx = Card_Number / pow(10, 13);
    int Digits_Visa_13 = Card_Number / (pow(10, 12));

// Loop to determine identity of each digit

    while (Card_Number != 0)
    {
        // Get Last Digit of Number

        Current_Digit = (Card_Number % 10);

        // Increase Digit Number by 1 

                /* why do you increment the digit by one, the digit value
                 * is just that, the remainder of the integer division.
                 */
        Digit_Number += 1;

        // Check if Current Digit is at Odd or Even Position in Card Number

                /* better use if (is_even) as is_even is already a
                 * boolean */
        if (is_even == true)
        {
            // Multiply Digit by 2

            Even_x2_Product = Current_Digit * 2;

            // Add Digits of Multiplication Product

                        /* Even_x2_Product cannot be higher that 18,
                         * so why not just check if it is greater than 10
                         * and then subtract 10 and add 1 (or better,
                         * just subtract 9), as in:

                        if (Even_x2_Product >= 10)
                                Even_x2_product -= 9;

                         */
            while (Even_x2_Product != 0)
            {
                Even_Digits += Even_x2_Product % 10;
                Even_x2_Product /= 10;
            }

            // Tell Program Next Digit is Odd

                        /* Shouldn't we add this result somewhere,
                         * mod 10 ??? Like in:

                         accumulated_checksum += Even_x2_Product;

                                Note: you do in the odd part.
                         */

            is_even = false; 
        }
        else 
        {
                        /* I suggest you to add all digits together.
                         * As in:

                         accumulated_checksum += Current_digit;

                         */

            // Add Odd Digits

            Odd_Digits += Current_Digit;

            // Tell Program Next Number is Even 

            is_even = true; 
        }

                /* if we have added two digits (the accumulated_checksum
                 * and the calculated one, no possibility of having more
                 * than 18 as the sum is possible, so check if the result
                 * is 10 or more, and subtract 10 to eliminate the carry.

                 if (accumulated_checksum >= 10)
                        accumulated_checksum -= 10;

                 */

        // Remove Last Digit and Repeat

        Card_Number /= 10;
    }

        /* you can use only one sum.  Both are digits... and if you
         * have made the checks suggested above, it is already a number
         * modulo 10. */
    // Add Odd and Even Digits Together

        /* this is not necessary */
    Total_Digit_Sum = Even_Digits + Odd_Digits;

// Loop to Check if Card Number is Valid

        /* you don't need to calculate the modulo 10 here, as you
         * have eliminated all the higher digits in the last loop.
         */
    if (Total_Digit_Sum % 10 == 0)
    if (Total_Digit_Sum % 10 == 0)
    {
        // Check Mastercard

                /* this is not the number of digits you have, this is the
                 * integer result of the division by a huge number...
                 * most of the times this will be zero, but it never be
                 * 16, with the numbers you are giving for the cards. */
        if (Digit_Number == 16)
        {
            if (Digits_MstrCrd <= 55 && Digits_MstrCrd >= 51)
            {
                printf("MASTERCARD\n");
            }

            // Check Visa 16

            else if (Digits_Visa_16 == 4)
            {
                printf("VISA\n");
            }
            else
            {
                printf("INVALID\n");
            }
        }

        // Check American Express

                /* also this is not true, by the same reason above. */
        else if (Digit_Number == 15)
        {
            if (Digits_AmEx == 34 || Digits_AmEx == 37)
            {
                printf("AMEX\n");
            }
            else 
            {
                printf("INVALID\n");
            }
        }

        // Check Visa 13

                /* same as above */
        else if (Digit_Number == 13)
        {
            if (Digits_Visa_13 == 4)
            {
                printf("VISA\n");
            }
            else
            {
                printf("INVALID\n");
            }
        }
        else 
        {
                        /* so you always end here */
            printf("INVALID\n");
        }
    }
}

Нет необходимости преобразовывать цепочка цифр в число ... это сделает вашу обработку более сложной, и вам нужно будет перейти к long long числам, чтобы использовать ее на самых длинных номерах карт.

Я разработал эту процедуру:

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

#include "main.h"
#include "proc.h"

int process(const char *str)
{
    int l = strlen(str);
    const char *p = str + l;
    int res = 0;
    enum {
        ODD_DIGIT,
        EVEN_DIGIT,
    } pos = ODD_DIGIT;

    DEB("processing: [%s]\n", str);

    while (--p >= str) {
        if (!isdigit(*p)) {
            WARN("%s\n", str);
            WARN("%*s^: is not a digit\n", (int)(p-str), "");
            return -1;
        }
        int dig = *p - '0';
        switch (pos) {
        case ODD_DIGIT: pos = EVEN_DIGIT;
            DEB("Add dig(%d) to res(%d)\n", dig, res);
            res += dig; break;
        case EVEN_DIGIT: pos = ODD_DIGIT;
            DEB("Add double(dig(%d)) to res(%d)\n", dig, res);
            dig <<= 1;
            if (dig >= 10)
                dig -= 9;
            res += dig; break;
        }
        if (res >= 10)
            res -= 10;
        DEB("res <= %d\n", res);
    }
    DEB("Returning => %d\n", res);
    if ((flags & FLAG_QUIET) == 0) {
        printf("%s: %d\n", str, res);
    }
    return res;
}

, который использует строку цифр и обрабатывает ее справа налево (начиная с конца строки) часть этого кода, опубликованная в github и которую вы можете скачать полную программу с здесь . Там вы найдете опубликованную здесь версию, если вы извлечете версию, помеченную как SO_60424279, и в ветке master вы получите реализацию DFA, управляемую таблицей, которая должна работать быстрее, чем эта.

Для компиляции просто выполните

make

в каталоге, в который вы извлекли источник.

...