【问题标题】:CS50 Problem Set 1 (Credit) 2020 help neededCS50 Problem Set 1 (Credit) 2020 需要帮助
【发布时间】:2020-02-26 23:47:04
【问题描述】:

我正在尝试提示用户输入信用卡号,并确定它是否是真实的信用卡号,如果是,是什么类型的信用卡号。

我以为我终于明白了,但是在执行 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");
        }
    }
}



【问题讨论】:

  • 你做了什么调试?您是否在调试器中运行程序以跟踪程序执行? How to debug small programs。例如,您当然可以找出它通过哪个代码路径来解释为什么没有输出。这可以通过在调试器中单步执行代码,甚至只是添加调试打印语句来完成。
  • 如果您将输入视为字符串而不是long,则问题更容易解决。换句话说,使用get_string读取数字,而不是get_long
  • 将 main 分解为 main 调用的较小函数。这使得代码更容易编写和调试。每个函数都应该执行一项任务。

标签: c cs50


【解决方案1】:

如果Total_Digit_Sum % 10等于0,程序会打印什么?它没有else;块的关闭} 之后没有命令。

【讨论】:

    【解决方案2】:

    我会在你的程序(带有嵌入式多行 cmets)中向你展示我通过简单检查看到的所有令人反感的东西(我不得不对其进行一些修改,因为你没有提供 @987654323 的实现@函数,还有一些你也没有提供的文件。后来我给你一个更好的解决方案,它没有整数限制的问题,因为它使用字符串来计算校验和。 最后引用了一个 github 存储库,其中考虑了所有版本的解决方案(包括 DFA ---确定性有限自动机---可能是该问题的最快解决方案)

    /* 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 上,您可以从 here 下载完整的程序。如果您签出标记为SO_60424279 的版本,您会在此处找到发布的版本,并且在分支master 中,您将获得一个应该比这个运行得更快的表驱动的DFA 实现。

    要编译,只需执行

    make
    

    在您提取源代码的目录中。

    【讨论】:

    • powmath.h 中。 cs50.h 是课程的一部分,包括 get_long。你可以得到它here
    • 另外,??&gt;} 的三元组。在 CS50 课程期间默认启用 IIRC 三元组。
    • 哦,你是对的 :) 抱歉....对此我深表歉意....我会在此处插入一个空格....
    • @S.S.Anne, pow() 用于生成数字10.0E14,即double。当您将浮点数除以 10 的幂时,您会得到一个不精确的浮点数,必须对其进行近似,从而导致舍入错误,这会给您带来无效的结果。恐怕这次你错了(无论如何,谢谢你的反对)
    • 您的评论说 “如果您只使用整数,则不需要 math.h”,但代码使用 pow,它存在于 math.h .我认为这是剩下的唯一问题,所以我会继续删除我的反对票。感谢您修复三字母组。
    【解决方案3】:
    #include <stdio.h>
    #include<cs50.h>
    #include <math.h>
    
    int main(void)
    {
    long  x = get_long("enter the credit card number");
    int  digit = 0, sum = 0;
    //digit is used for odd and even checker.
    long y = x;
    
    //checksum card digits
    
    while (y != 0)
    {
        int sumeven = 0, sumodd = 0;
        int rem = y % 10;
        digit++;
        if (digit % 2 == 0)                        //if digit is even
        {
            int multiply = rem * 2;
            if (multiply == 0)
            {
                sumeven += multiply;
            }
    
            else
            {  
                while (multiply != 0)                   //adding all  digits after         
                {
                    sumeven += multiply % 10;
                    multiply /= 10;                   //minus last digit of multiply
                }
            }
        }
        else                                 //if digit is odd
        {
            sumodd += rem;
        }
        y /= 10;                              //minus last digit from y
    
        sum += sumeven + sumodd;
    }
    
    
    
    
    //check for valid credit card
    if (digit != 13 && digit != 15 && digit != 16) //for first if
    {
        printf("INVALID\n");
    }
    
    else if (sum % 10 == 0)
    {
        if (digit == 16) //if digit is 16
        {
            if (x / 100000000000000 >= 51 && x / 100000000000000 <= 55)
            {
                printf("MASTERCARD\n");
            }
            else if (x / 1000000000000000 == 4)
            {
                printf("VISA\n");
            }
            else    //if digit is not 16
            {
                printf("INVALID\n");
            }
        }
    
        else if (digit == 15)
        {
            if (x / 10000000000000 == 34 || x / 10000000000000 == 37)
            {
                printf("AMEX\n");
            }
            else
            {
                printf("INVALID\n");
            }
        }
    
    
    
        else  if (digit == 13)
        {
            if (x / 1000000000000 == 4)
            {
                printf("VISA\n");
            }
            else
            {
                printf("INVALID\n");
            }
    
        }
    
    }
    
    
    else
    {
        printf("INVALID\n");
    }
    }`
    

    【讨论】:

      【解决方案4】:

      【讨论】:

      • 虽然此链接可能会回答问题,但最好在此处包含答案的基本部分并提供链接以供参考。如果链接页面发生更改,仅链接答案可能会失效。 - From Review
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2022-01-04
      • 2017-10-05
      • 2017-03-23
      相关资源
      最近更新 更多