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 useget_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
.