Home > Net >  Same code works on Linux but not on windows
Same code works on Linux but not on windows

Time:10-01

This is the credit problem from CS50x I wrote this code on Windows and it didn't work there. After entering a 15 digit card number on windows it wasn't accepting the number and was prompting me again and again. But when i pasted the same code on CS50's cloudspace in VSCode which is on linux, the code runs perfectly fine there. The issue seems to be in the get_long function, it wasnt letting me input a 15 digit card number on windows.

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

int main()
{
   long number;
   
    number = get_long("Enter your card number: ");
   
   //Check length of number
   int i = 0;
   long length = number;
   while (length > 0 )
   {
    length = length / 10;
    i  ;
   }

    if (i != 16 && i != 15 && i!= 13)
    {
        printf ("INVALID");
    }
    else
    {
        int sum1 = 0;
        int sum2 = 0;
        long x = number;
        int mod1 = 0;
        int mod2 = 0;
        int d1 = 0;
        int d2 = 0;
        int final_sum = 0;

        do
        {
            //Remove last digit and add to sum1
            mod1 = x % 10;
            x = x / 10;
            sum1 = sum1   mod1;
            
            //Remove second last digit
            mod2 = x % 10;
            x = x / 10;

            //Multiply second last digit by two 
            mod2 = mod2 * 2;

            //Extract the digits
            d1 = mod2 % 10;
            d2 = mod2 / 10;

            //Add to sum2
            sum2 = sum2   d1   d2;

        } while (x > 0 );

        final_sum = sum1   sum2;
        
        //Check Luhns Algorithm
        if (final_sum % 10 != 0)
        {
            printf("INVALID\n");
        }
        else
        {
            long y = number;
            int j = 0;
            do
            {
                y = y / 10;
                j  ;

            } while (y > 100 );

            if ( y / 10 == 4)
            {
                printf ("VISA");
            }
            else if ((y / 10 == 5) && (0 < y % 10 && y % 10 < 6))
            {
                printf("MASTERCARD");
            }
            else if ((y / 10 == 3) && (y % 10 ==4 || y % 10 == 7) )
            {
                printf("AMEX");
            }
        }
    }

}

CodePudding user response:

Your code works because on your Linux platform, type long happens to be an 8-byte, 64-bit type that can easily handle integers matching even 15- or 16-digit credit card numbers.

Your code fails on Windows because there, type long is a 32-bit type, not capable of handling numbers greater than 2,147,483,647 or 4,294,967,295 (depending on whether signed or unsigned).

This discrepancy between the two platforms is not a bug: C's short, int, and long types have always been somewhat loosely defined. The requirement for type long is, in effect, that it have at least 32 bits, which on both platforms it certainly does.

It was rather unfair and misleading for your assignment to have said "Best to use get_long from CS50’s library to get users’ input". This is a nonportable programming practice for this task.

In portable C, type long long is guaranteed to be at least 64 bits long, so it would work reliably here. I do not know if CS50's library has a get_long_long function. (Update: per comments below, it does.)

In the long run, it's generally easier to deal with credit card numbers as strings, not integers. But during week 1 of CS50, students haven't learned about strings yet.

CodePudding user response:

The discussion in the comments of 32-bit v. 64-bit should be educational for you, and I hope that you can integrate that information into your program.

Compliments to the layout and logic of your beginner code. Very clear and very easy to read and follow (including appropriate comments.) Keep this up and you will become a fine programmer!

I've revised your code (without appreciably changing any of its logic) to suggest how it may be slightly improved. The following is offered for your consideration. It is your code only slightly modified. It's up to you to consider if you want to apply any of these "alterations" to your code.

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

int main()
{
    long number = get_long("Enter A card number: ");
    long x = number; // will reload and reuse x several times
    int i = 0; // handy to have around

    // Check length of number
    while (x > 0 )
    {
        x = x / 10;
        i  ;
    }

    if (i != 16 && i != 15 && i!= 13)
    {
        printf ("INVALID");
        return 1; // early termination saves one level of indentation
    }

    int sum1 = 0;
    int sum2 = 0;
    int mod1 = 0;
    int mod2 = 0;
    int d1 = 0;
    int d2 = 0;
    int final_sum = 0;

    x = number; // reload
    while ( x > 0 )
    {
        //Remove last digit and add to sum1
        mod1 = x % 10;
        x = x / 10;
        sum1 = sum1   mod1;

        //Remove second last digit
        mod2 = x % 10;
        x = x / 10;

        //Multiply second last digit by two
        mod2 = mod2 * 2;

        //Extract the digits
        d1 = mod2 % 10;
        d2 = mod2 / 10;

        //Add to sum2
        sum2 = sum2   d1   d2;
    }

    final_sum = sum1   sum2;

    //Check Luhns Algorithm
    if (final_sum % 10 != 0)
    {
        printf("INVALID\n");
        return 1;  // early termination
    }

    x = number; // reload
    while ( x > 99 ) // NB! subtle change!!
    {
        x = x / 10; // shrink until 10 <= x <= 99
    }

    if ( 40 <= x && x <= 49 ) // check this
    {
        printf ("VISA");
    }
    else if ( 50 <= x && x < 56 ) // check this
    {
        printf("MASTERCARD");
    }
    else if ( x == 34 || x == 37 ) // check this
    {
        printf("AMEX");
    }
    else
    {
        printf("INVALID\n");
        return 1; // early termination
    }

    return 0;
}

CodePudding user response:

The instructions for your task state the following:

But do not assume that the user’s input will fit in an int! Best to use get_long from CS50’s library to get users’ input.

This advice is misleading when using the Microsoft Windows platform.

On Microsoft Windows, the data type long has a width of only 32 bits, whereas on most other common platforms, such Linux and MacOS, it has a width of 64 bits. The ISO C standard only requires long to have a minimum width of 32 bits, so all the mentioned operating systems are complying with the standard in this respect.

A 32-bit signed integer is able to represent numbers up to 2,147,483,647, whereas a 64-bit signed integer is able to represent numbers up to 9,223,372,036,854,775,807. Therefore, a 32-bit integer data type is insufficient to represent a credit card number; you require a 64-bit integer data type.

In constrast to long, the data type long long is guaranteed to be at least 64 bits wide on all platforms.

For the reasons stated above, if you want your program to work on Microsoft Windows, you will have to use the long long data type to represent a credit card number, instead of long. You will also have to use the function get_long_long instead of get_long.

  • Related