CS50 信用卡验证

CS50 Credit Card Validation

#include #include

int main(void) { long cc = get_long("信用卡:"); // 获取输入

long len = 0;           //intialized length
long x = cc;            // set 2nd variable = to cc to prevent manipulation of cc

while (x != 0)     // length count loop while x is divisable loop will continue will be stored as len
{
    x = x / 10;
    len++;
}


if ((len != 16) && (len != 15) && (len != 13))  //Checking for length to see if number matchs possible postive outcomes
{
    printf("INVALID\n");
    return 0;
}
//pull 2nd to last and then every other digit
long cc_num1 = ((cc % 100) / 10);
long cc_num2 = ((cc % 10000) / 1000);
long cc_num3 = ((cc % 1000000) / (100000));
long cc_num4 = ((cc % 100000000) / (10000000));
long cc_num5 = ((cc % 10000000000) / (1000000000));
long cc_num6 = ((cc % 1000000000000) / (100000000000));
long cc_num7 = ((cc % 100000000000000) / (10000000000000));
long cc_num8 = ((cc % 10000000000000000) / (1000000000000000));

cc_num1 = (cc_num1 * 2);                    //Multiply digits pulled above by 2
cc_num2 = (cc_num2 * 2);
cc_num3 = (cc_num3 * 2);
cc_num4 = (cc_num4 * 2);
cc_num5 = (cc_num5 * 2);
cc_num6 = (cc_num6 * 2);
cc_num7 = (cc_num7 * 2);
cc_num8 = (cc_num8 * 2);

cc_num1 = ((cc_num1 / 10) + (cc_num1 % 10));    //split double digits and add to signles
cc_num2 = ((cc_num2 / 10) + (cc_num2 % 10));
cc_num3 = ((cc_num3 / 10) + (cc_num3 % 10));
cc_num4 = ((cc_num4 / 10) + (cc_num4 % 10));
cc_num5 = ((cc_num5 / 10) + (cc_num5 % 10));
cc_num6 = ((cc_num6 / 10) + (cc_num6 % 10));
cc_num7 = ((cc_num7 / 10) + (cc_num7 % 10));
cc_num8 = ((cc_num8 / 10) + (cc_num8 % 10));

long cc_sum = cc_num1 + cc_num2 + cc_num3 + cc_num4 + cc_num5 + cc_num6 + cc_num7 + cc_num8; // add sum of number above

long cc_num1x = ((cc % 10) / 1);                      //pulls last digit from card then everyother digit
long cc_num2x = ((cc % 1000) / 100);
long cc_num3x = ((cc % 100000) / 10000);
long cc_num4x = ((cc % 10000000) / 1000000);
long cc_num5x = ((cc % 1000000000) / 100000000);
long cc_num6x = ((cc % 100000000000) / 10000000000);
long cc_num7x = ((cc % 10000000000000) / 1000000000000);
long cc_num8x = ((cc % 1000000000000000) / 100000000000000);


long cc_sumx = cc_num1x + cc_num2x + cc_num3x + cc_num4x + cc_num5x + cc_num6x + cc_num7x + 
               cc_num8x; //adds last and everyother digit together

long sumofsums = cc_sum + cc_sumx;  // adds sums of both sums created


if ((sumofsums % 10) != 0)   // Luhn’s Algorithm results will close if not met
{
    printf("INVALID\n");
    return 0;
}

{
    if (len == 15)                       // checks for AMEX by using length then first 2 digits 
    {
        long ax = cc / 10000000000000;
    
        if ((ax == 34 || ax == 37))    
        {
            printf("AMEX\n");   
        }
        else
        {
            printf("INVALID\n");
            return 0;
        }
    }    
}

long mc = cc / 100000000000000;
long v = cc / 1000000000000000;
long v2 = cc / 1000000000000;

if (len == 16)                      // Checks for MC and Via (16 digits) by length then first 2 digits MC or 1 visa
{
    if ((mc == 51 || mc == 52 || mc == 53 || mc == 54 || mc == 55))    
    {
        printf("MASTERCARD\n");   
    }
    else if (v == 4)
    {
        printf("VISA\n");
    }
    else
    {
        printf("INVALID\n");
        return 0;
    }
}

if (len == 13)                                //Checks 2nd Visa length 13 digits then 1st digit 
{
    if (v2 == 4)
    {
        printf("VISA\n");
    }
    else
    {
        printf("INVALID\n");
        return 0;
    }
}

}


必须有比我计划执行此操作更好的方法。长度计数循环在 10 位数字之前都很好,但随后会提取随机数。

每隔一个数字公式似乎可以通过递归完成,但我对此一无所知。由于数量最多限制为 16,因此我使用的公式似乎有效。

  1. 判断卡是否为15 || 16 || IF Else loop
  2. if not mark In valid in valid in if Else loop 13位数字
  3. 使用CC校验和公式If else循环(不满足Criteria则有效)
  4. 查看 2 个起始号码以确定 AX、MC 或 Visa
    #include <stdio.h>
    #include <cs50.h>
    #include <string.h>
    
    
    int main(void)
    {
        long cc = get_long("Credit Card: " );  // gets input
    
    
        int len = 0;           //intialized length
        int x = cc;            // set 2nd variable = to cc to prevent manipulation of cc
    
        while(x != 0)      // length count loop while x is divisable loop will continue will be stored as len
        {
            x = x/10;
            len++;
        }
    
        printf("%i\n", len);     // REMOVE !!!!!!!!!!! BUG TEST
    
                                              //pull 2nd to last and then every other digit 
        int cc_num1 = ((cc % 100)/10);
        int cc_num2 = ((cc % 10000)/1000);
        int cc_num3 = ((cc % 1000000)/(100000));
        int cc_num4 = ((cc % 100000000)/(10000000));
        int cc_num5 = ((cc % 10000000000)/(1000000000));
        int cc_num6 = ((cc % 1000000000000)/(100000000000));
        int cc_num7 = ((cc % 100000000000000)/(10000000000000));
        int cc_num8 = ((cc % 10000000000000000)/(1000000000000000));
    
    
        printf("%i %i %i %i %i %i %i %i", cc_num1, cc_num2, cc_num3, cc_num4 , cc_num5, cc_num6 , cc_num7 , cc_num8 );
    
    
    }
    

让我们先感谢房间里的大象。

long cc = get_long("Credit Card: " );

...

int x = cc;

C 标准指定 long 至少为 32 位,而 int 必须至少为 16 位。当然,实际值取决于您的系统和您的库实现。但通常情况下,long 能够存储比 int 更多的位。就像这里的情况一样。这意味着“超过 10 位的数字”,本质上是太大而无法存储到 int 中的数字将导致 undefined behavior。要确切知道 system/environment 中 int 的上限是哪个数字,您可以打印 limits.h.

中定义的 INT_MAX 的值

解决方案当然是将 long 变量存储在 另一个 long 变量中,而不是 int。或者,只需将值传递给执行必要工作的函数。现在将所有内容都放在 main 中不是很有条理是吗。

我们如何制作一个函数,根据卡号打印一张卡的所有详细信息?

签名看起来像-

void print_card_details(long num)

现在我们需要一个函数来通过 luhn 的算法来放置卡片。我们还可以为此创建一个函数-

int is_valid(long num)
{
    int curr_digit, add_digit, prod_sum = 0, sum = 0;
    for (int digit_count = 0; num != 0; num /= 10, digit_count++)
    {
        // Strip each digit from number, starting from the end
        curr_digit = num % 10;
        if (digit_count % 2 != 0)
        {
            // Every 2nd digit from the right goes through this
            // The current digit gets doubled
            // The digits of that result are added to the sum
            add_digit = curr_digit * 2;
            prod_sum += add_digit % 10 + add_digit / 10;
        }
        else
        {
            // The remaining digits go through this
            // They are all summed up
            sum += curr_digit;
        }
    }
    if ((prod_sum + sum) % 10 != 0)
    {
        // If the sum of prod_sum + sum doesn't end in 0
        // It is invalid
        return 0;
    }
    else
    {
        // The card is valid
        return 1;
    }
}

迭代一个数的数字的传统方法不是暴力地手动除10的任意幂,而是迭代它并除以模数10。例如,这个片段-

while (x != 0)
{
    printf("Current digit: %d\n", x % 10);
    x /= 10;
}

将打印存储在 x 中的号码的所有数字。这基本上就是我们在 luhn 算法循环中使用的内容。除了我们还对总位数进行计数,因为我们只想要从末尾开始的每一秒数字。我们如何知道当前数字符合此标准?我们检查当前 digit_count 是否为偶数(通过除以 2 并检查剩余为 0)。

后面的公式-

add_digit = curr_digit * 2;
prod_sum += add_digit % 10 + add_digit / 10;

基本上就是这个-

的实现

Multiply every other digit by 2, starting with the number’s second-to-last digit, and then add those products’ digits together.

确保仅添加结果 add_digit。因此,如果 add_digit 最终为 12。我们需要添加 1 + 2。这正是 add_digit % 10 + add_digit / 10 所做的。 12 % 10 当然是 2。而 12 / 10 是 1。

这个函数return如果卡片有效则返回 1,否则返回 0。你可以把它放在你的主要功能中,并检查 return 值以了解该卡是否有效。

如果有效,请继续下一步检查卡片的位数以及开头的数字。

我们可以做一个循环来计算数字的个数,以及存储数字的第一位和第二位。

int len = 0;
int curr_digit = 0, prev_digit = 0;
while(num != 0)
{
    prev_digit = curr_digit;
    curr_digit = num % 10;
    num /= 10;
    len++;
}

这将为您提供卡号的长度。注意,在最后一次迭代中,prev_digit 的值是第二个数字,curr_digit 是第一个数字。因此 curr_digit * 10 + prev_digit 将产生信用卡号开头的前 2 个数字(一起)。

最后,你只需要一堆简单的if/else子句来验证它是哪张卡。您也只被要求检查一个非常小的子集。所以这里是-

// Construct the 2 digit number that this card num begins with
int begins_with = curr_digit * 10 + prev_digit;
if (len == 13 && begins_with / 10 == 4)
{
    // We know only VISA uses 13 digits
    // And it begins with 4 (second digit does not matter)
    printf("VISA\n");
}
else if (len == 15 && begins_with == 34 ||)
{
    // We know only AMEX uses 15 digits
    printf("AMEX\n");
}
else if (len == 16)
{
    // Both VISA and MASTERCARD use 16 digits
    if (curr_digit == 4)
    {
        // But VISA card number begins with 4
        printf("VISA\n");
    }
    else if (curr_digit == 5)
    {
        // MASTERCARD number begins with 5
        printf("MASTERCARD\n");
    }
    else
    {
        // Out of context for this problem
        printf("INVALID\n");
    }
}
else
{
    // Out of context for this problem
    printf("INVALID\n");
}

把这些放在一起,你应该有希望得到

void print_card_details(long num)
{
    if (!is_valid(num))
    {   
        // Card did not pass luhn's algo
        printf("INVALID\n");
        return;
    }
    int len = 0;
    int curr_digit = 0, prev_digit = 0;
    while(num != 0)
    {
        prev_digit = curr_digit;
        curr_digit = num % 10;
        num /= 10;
        len++;
    }
    // Construct the 2 digit number that this card num begins with
    int begins_with = curr_digit * 10 + prev_digit;
    if (len == 13 && curr_digit == 4)
    {
        // We know only VISA uses 13 digits
        // And it begins with 4 (second digit does not matter)
        printf("VISA\n");
    }
    else if (len == 15 && (begins_with == 34 || begins_with == 37))
    {
        // We know only AMEX uses 15 digits
        printf("AMEX\n");
    }
    else if (len == 16)
    {
        // Both VISA and MASTERCARD use 16 digits
        if (curr_digit == 4)
        {
            // But VISA card number begins with 4
            printf("VISA\n");
        }
        else if (begins_with >= 51 && begins_with <= 55)
        {
            // MASTERCARD number begins with 51, 52, 53, 54, or 55
            printf("MASTERCARD\n");
        }
        else
        {
            // Out of context for this problem
            printf("INVALID\n");
        }
    }
    else
    {
        // Out of context for this problem
        printf("INVALID\n");
    }
    return;
}