Why do i keep getting an invalid feedback? - c

I've been working on the cs50 pset1 credit for the past 36 hours.
My code is not generating any errors but when i enter my card details it shows invalid, what could be the problem.
I'm a noob, guys please help out.
#include <stdio.h>
#include <cs50.h>
int main (void)
{
long long ccnumber;
do
{
//Prompting the user for his creditcard number
ccnumber=get_long_long("What is your creditcard number\n");
}
while (ccnumber<= 0);
//validating the credit card number to ascertain if its upto 13. 14 or 16
long long numbers = ccnumber;
int totaldigits = 0;
while (numbers > 0)
{
numbers = numbers/10;
totaldigits++;
}
if(totaldigits != 13 || totaldigits !=14 || totaldigits !=16)
{
printf("Invalid\n");
}
//Starting from the second to last digit
//And multiplying through by 2
int number1 = ((ccnumber/10) % 10) *2;
int number2 = ((ccnumber/1000) % 10) *2;
int number3 = ((ccnumber/100000) % 10) *2;
int number4 = ((ccnumber/10000000) % 10) *2;
int number5 = ((ccnumber/1000000000) % 10) *2;
int number6 = ((ccnumber/100000000000) % 10) *2;
int number7 = ((ccnumber/10000000000000) % 10) *2;
int number8 = ((ccnumber/10000000000000000) % 10) *2;
//Getting the Sum of the first number series
int sum1;
sum1 = (number1 + number2 + number3 + number4 + number5 + number6 + number7 + number8);
//Populating the second number series
int number9 = ccnumber % 10;
int number10 = ((ccnumber/100) % 10);
int number11 = ((ccnumber/10000) % 10);
int number12 = ((ccnumber/1000000) % 10);
int number13 = ((ccnumber/100000000) % 10);
int number14 = ((ccnumber/10000000000) % 10);
int number15 = ((ccnumber/1000000000000) % 10);
int number16 = ((ccnumber/100000000000000) % 10);
int sum2;
sum2 =(number9 + number10 + number11 + number12 + number13 + number14 + number15 + number16);
//Adding sum1 and sum2
int checksum;
checksum = sum1 + sum2;
if (checksum % 10 != 0)
{
printf("invalid/n");
}
//Verifying for visacard(1)
if(totaldigits == 13)
{
printf("Visa\n");
}
// Verifying for visa(2)
if(totaldigits == 16)
{
long long visa;
visa = ccnumber/1000000000000000;
if(visa!=4)
{
printf("Invalid\n");
}
else
{
printf("VISA\n");
}
//Verifying for MasterCard
long long master;
master = ccnumber/100000000000000;
if(master!=51 || master!=52 ||master!=53 ||master!=54 ||master!=55)
{
printf("Invalid\n");
}
else
{
printf("MASTER\n");
}
}
//Verifying for Amex
}
/counter
What is your creditcard number
2221000000000009
Invalid
invalid/nInvalid
Invalid

First of all, some of your if conditions are wrong. For example,
if(totaldigits != 13 || totaldigits != 14 || totaldigits != 16)
You want to check if the totaldigits is 13 or 14 or 16, but what you check here is if totaldigits is not 13, then print invalid or if totaldigits is not 14 then, print invalid and so on. Hence, it will always print invalid. You need to use && (AND) instead of || (OR).
The same problem exists in this line as well.
if(master!=51 || master!=52 ||master!=53 ||master!=54 ||master!=55)
Another problem is that you put 1 unnecessary 0 to division in this line, so it always yields 0.
int number8 = ((ccnumber/10000000000000000) % 10) *2; // 1 zero unnecessary
As it is suggested in the comments, you may need to consider creating an array for storing individual digits instead of using 16 different integers. When you have an array you can do the divisions in a for loop so that you don't get confused with a lot of zeros.
As an example, you can refer to this link
A solution for cs50's credit card validation problem .

Related

Trying to implement Luhn's Algorithm in C

Iam trying to implement Luhn's algorithm in the C language to check credit card validity, for those who don't know... this is it:
Multiply every other digit by 2, starting with the number’s
second-to-last digit, and then add those products’ digits together.
Add the sum to the sum of the digits that weren’t multiplied by 2.
If the total’s last digit is 0 (or, put more formally, if the total
modulo 10 is congruent to 0), the number is valid!
and to implement that, I looped through the whole number and if the number place I was in had a modulo 2 equal to 0 then I would multiply by two and add to a variable called totalEven.
if that wasn't the case I would add the number I was in to totalOdd without multiplication.
I would then increment the place by one and check the other numbers until I reach 16 (the max digits for a card).
I would later add both variables and check if the total modulo ten was equal to 0. If it means the credit card number is correct, else it is false.
here is the code:
#include <stdio.h>
#include <cs50.h>
//list of variables
//is the card valid
bool isValid = true;
// the creditcard number
long input;
//mod stands for modules, and is used to single out each number as seen later
int mod = 10;
//the location at which number I am checking
int place = 1;
//num is the number I am checking that has been singled out
int num = 0;
//total of numbers * 2 located at locations numbered with even numbers
int totalEven = 0;
//total of numbers located at locations numbered with odd numbers
int totalOdd = 0;
//gets input and stores it in well.. input
input = get_long("Number: ");
// a formula to single out a number, starting with the ones and then as you can see, mod is muliplied by 10 to go over the second number.
num = ((input % mod) - (input % (mod /10))) / (mod/10);
//loops 16 times
for(int i = 0; i < 16; i++)
{
// if the place is even execute below
if(place % 2 == 0)
{
totalEven = totalEven + num * 2;
}
//else do this
else if (place % 2 != 0)
{
totalOdd = totalOdd + num;
}
//moves to the next number
mod = mod * 10;
place++;
}
//fufils the last step of the algorithm
if((totalEven + totalOdd) % 10 == 0 )
{
isValid = true;
}
else
{
isValid = false;
}
problem is that this block of code gives me invalid or !isValid even though the credit card number is supposed to be correct and I checked my "formula" and it works just fine...
I have absolutely no idea what to do... I am a humble hobbyist so plz don't roast me for the monstrosity above.
here is a complete version of the code
#include <stdio.h>
#include <cs50.h>
long power();
int main(void)
{
//AMERX 15 STRT 34 OR 37
//MC 16 STRT 51, 52, 53, 54, 55
//VZA 13 OR 16 STRT 4
long input;
bool isValid = true;
string type;
int mod = 10;
int place = 1;
int num = 0;
int totalEven = 0;
int totalOdd = 0;
do
{
input = get_long("Number: ");
}
while(input < 0);
for(int i = 0; i < 16; i++)
{
num = ((input % mod) - (input % (mod /10))) / (mod/10);
if(place % 2 == 0)
{
totalEven = totalEven + num * 2;
}
else
{
totalOdd = totalOdd + num;
}
mod = mod * 10;
place++;
}
if((totalEven + totalOdd) % 10 == 0 )
{
isValid = true;
}
else
{
isValid = false;
printf("%i , %i", totalEven, totalOdd);
}
if (isValid == true){
if((input < (38 * power(10, 13)) && input >=(37 * power(10, 13))) || (input < (35 * power(10,13)) && input >= (34 * power(10, 13))))
{
type = "AMEX\n";
}
else if(input >= (51 * power(10, 14)) && input < (56 * power(10, 14)))
{
type = "MASTERCARD\n";
}
else if((input < (5 * power(10, 12)) && input >= (4 * power(10, 12))) || (input < (5 * power(10, 15)) && input >= (4 * power(10, 15))))
{
type = "VISA\n";
}
else{
type = "error\n";
}
}
else
{
type = "INVALID\n";
}
if((totalEven + totalOdd) % 10 == 0 )
{
isValid = true;
}
else
{
isValid = false;
}
printf("%s", type);
}
long power(int n, int p)
{
long result = 1;
for(int i = 0; i<p; i++)
{
result = result * n;
}
return result;
I'm not an expert in Luhn algorithm but when I read https://en.wikipedia.org/wiki/Luhn_algorithm it seems to me that you are doing it wrong.
Quote from https://en.wikipedia.org/wiki/Luhn_algorithm :
From the rightmost digit (excluding the check digit) and moving left, double the value of every second digit. The check digit is neither doubled nor included in this calculation; the first digit doubled is the digit located immediately left of the check digit. If the result of this doubling operation is greater than 9 (e.g., 8 × 2 = 16), then add the digits of the result (e.g., 16: 1 + 6 = 7, 18: 1 + 8 = 9) or, alternatively, the same final result can be found by subtracting 9 from that result (e.g., 16: 16 − 9 = 7, 18: 18 − 9 = 9).
I don't see anywhere in your code where you handle that bolded part.
Instead of
totalEven = totalEven + num * 2;
I think you need
int tmp = num * 2;
if (tmp > 9) tmp = tmp - 9;
totalEven = totalEven + tmp;
That said - I think you are making the implementation much more complex than needed by storing the input as a number. Instead of a number you could use an array of digits.
That is - instead of
long input = 1122334455667788
use
int digits[] = {8, 8, 7, 7, 6, 6, 5, 5, 4, 4, 3, 3, 2, 2, 1, 1};
// Notice that index zero is the rightmost digit
In this way the algorithm is much more simple:
// Double every second element and check for overflow
for (idx = 1; idx < 16; idx += 2)
{
digits[idx] = 2 * digits[idx];
if (digits[idx] > 9) digits[idx] = digits[idx] - 9;
}
// Calculate the sum
sum = 0;
for (idx = 0; idx < 16; ++idx)
{
sum = sum + digits[idx];
}
If you must receive the input as a number, start by calling a function that converts the number to an array of digits. You can find many, many examples of how that conversion is done here on SO. Here Converting integer into array of digits is just one of many examples.
As I was looking at your code, there some mistakes I want to point out.
You forgot: #include <string.h> as you did declare string type in the code.
input = get_long("Number: "); should have its own do-while loop in case user inputs letters or incorrect numbers.
if(place % 2 == 0){
totalEven = totalEven + num * 2;
}
else if (place % 2 != 0){
totalEven = totalEven + num;
} should totalOdd = totalOdd + num for the second part
totalEven = totalEven + num * 2 is right and wrong at the same time. It only works if the number multiplied by 2 is less than 10. If the num * 2 >= 10, lets say num = 6, then 6 * 2 is 12 which would then be 1 + 2 + totalEven.
num = ((input % mod) - (input % (mod /10))) / (mod/10); This should be in the first for loop.
In #include <math.h>, there is a power function called pow which does exactly as your power() function.
Caution: I have made use of CS50X Library as the question seems to be the one from the same.
#include <stdio.h>
#include <cs50.h>
// Luhn's Algorithm
int main(void)
{
long cardNumber = get_long("Please, enter your card number: ");
int sum1 = 0, num = 0, remainder = 0, sum2 = 0;
long temp = cardNumber;
while (temp > 0)
{
num = ((temp / 10) % 10) * 2; // Multiplying every other digit by 2, starting with the number’s second-to-last digit
while (num > 0)
{
remainder = num % 10;
sum1 += remainder; // Adding those products’ digits together
num /= 10;
}
temp /= 100;
}
// So as to restore the initial values of remainder and temp for the use in next loop
remainder = 0;
temp = cardNumber;
while (temp > 0)
{
remainder = temp % 10;
sum2 += remainder; // Sum of the digits that weren’t multiplied by 2
temp /= 100;
}
((sum1 + sum2) % 10) == 0 ? printf("Valid\n") : printf("Invalid\n");
return 0;
}

CS50 Pset1 Credit: Why isn't my program responding right?

I have basically no coding experience and am enrolled in CS50x on edX. I am currently working on Problem Set 1's Credit problem (in the C language). My program uses Luhn's Algorithm to determine whether a credit card number belongs to American Express, MasterCard, or Visa. When I test the program, inputing test credit card numbers gives me responses I don't want; every valid (test) credit card number I input gives no output.
I've been fighting with this for a few days. There was a point where my program recognized all 3 credit card company numbers, but allowed any random number to be inputted, while I wanted the program to print "INVALID" if that was the case.
Another problem I've had is getting an error for my integer variable, digitcount, (see code below) not being declared as a variable in one line of code (even though there are a few lines of code where digitcount is recognized just fine?)
I had fixed some of these bugs by reading into the error messages I got, but sometimes I can't understand them and just messing around ends up fixing them. It makes no sense to me. (Such as deleting or moving parenthesis and interchanging == with =.)
I have also tried looking at other peoples' codes, but when I try to use similar concepts to what I see, my program doesn't work.
Sorry if any of this is messy or hard to read! Even though I've been trying to teach myself what I need to know to make this work, I often get confused when using variable names like "n" and need some separation between certain parts of the code so I don't feel unorganized.
I could just skip Credit since I've done all the other problems in Problem Set 1, but I really want to learn and use any knowledge I come across to complete and understand as much as I can.
Here's my code! Many thanks to anyone who decides to take a look and help me understand where I'm wrong!
#include <cs50.h>
#include <math.h>
int main(void)
{
long long CCnumber;
//prompts the user for a credit card number
do
{
CCnumber = get_long_long("Enter your Credit Card Number: ");
}
while (CCnumber < 0);
//--------------------
//defines counter as a long type variable and digitcount as an integer type variable
int counter = 0;
int digitcount = 0;
//loop the counts the digit-length of the credit card number
while (counter > 0)
{
counter = CCnumber / 10;
digitcount++;
}
//--------------------
//grabs every other digit in the credit card number, starting from the second to last digit
//% grabs the remainder of a number divided, while / grabs the quotient of the number divided
int digit1 = (((CCnumber % 100) / 10) * 2);
int digit1a = (digit1 / 10);
int digit1b = (digit1 % 10);
int digit2 = (((CCnumber % 10000) / 1000) * 2);
int digit2a = (digit1 / 10);
int digit2b = (digit1 % 10);
int digit3 = (((CCnumber % 1000000) / 100000) * 2);
int digit3a = (digit1 / 10);
int digit3b = (digit1 % 10);
int digit4 = (((CCnumber % 100000000) / 10000000) * 2);
int digit4a = (digit1 / 10);
int digit4b = (digit1 % 10);
int digit5 = (((CCnumber % 10000000000) / 1000000000) * 2);
int digit5a = (digit1 / 10);
int digit5b = (digit1 % 10);
int digit6 = (((CCnumber % 1000000000000) / 100000000000) * 2);
int digit6a = (digit1 / 10);
int digit6b = (digit1 % 10);
int digit7 = (((CCnumber % 100000000000000) / 10000000000000) * 2);
int digit7a = (digit1 / 10);
int digit7b = (digit1 % 10);
int digit8 = (((CCnumber % 10000000000000000) / 1000000000000000) * 2);
int digit8a = (digit1 / 10);
int digit8b = (digit1 % 10);
//adds all the digits together
int checksum1 = (digit1a + digit1b + digit2a + digit2b + digit3a + digit3b + digit4a + digit4b + digit5a + digit5b + digit6a + digit6b +digit7a +digit7b + digit8a +digit8b);
//grabs all the other digits from the credit card number
int otherdigit1 = ((CCnumber % 10) / 1);
int otherdigit2 = ((CCnumber % 1000) / 100);
int otherdigit3 = ((CCnumber % 100000) / 10000);
int otherdigit4 = ((CCnumber % 10000000) / 1000000);
int otherdigit5 = ((CCnumber % 1000000000) / 100000000);
int otherdigit6 = ((CCnumber % 100000000000) / 10000000000);
int otherdigit7 = ((CCnumber % 10000000000000) / 1000000000000);
int otherdigit8 = ((CCnumber % 1000000000000000) / 100000000000000);
//adds all the other digits together
int checksum2 = (otherdigit1 + otherdigit2 + otherdigit3 + otherdigit4 + otherdigit5 + otherdigit6 + otherdigit7 + otherdigit8);
//adds the checksum halfs together
int TOTALchecksum = (checksum1 + checksum2);
//checks the last digit of the total checksum
int lastdigit = (TOTALchecksum / 1);
//--------------------
//determines what the credit card number's first and second digits are (15-digit count)
int startingdigit115 = (CCnumber / 100000000000000);
int startingdigit215 = ((CCnumber / 10000000000000) % 10);
int startingdigitsum15 = (startingdigit115 + startingdigit215);
//determines what the credit card number's first and second digits are (16-digit count)
int startingdigit116 = (CCnumber / 1000000000000000);
int startingdigit216 = ((CCnumber / 100000000000000) % 10);
int startingdigitsum16 = (startingdigit116 + startingdigit216);
//determines what the cred card number's first and second digits are (13-digit count)
int startingdigit113 = (CCnumber / 1000000000000);
int startingdigit213 = ((CCnumber / 100000000000) % 10);
int startingdigitsum13 = (startingdigit113 + startingdigit213);
//--------------------
if ((lastdigit == 0) && (digitcount == 15))
{
//determines if credit card number belongs to American Express
if (startingdigitsum15 == 7 || startingdigitsum15 == 10)
{
printf("AMEX\n");
}
}
else if ((lastdigit == 0) && (digitcount == 16))
{
//determines if credit card number belongs to MasterCard
if (startingdigitsum16 == 6 || startingdigitsum16 == 7 || startingdigitsum16 == 8 || startingdigitsum16 == 9 || startingdigitsum16 == 10)
{
printf("MASTERCARD\n");
}
}
else if ((lastdigit == 0 && digitcount == 13) || (lastdigit == 0 && digitcount == 16))
{
//determines if credit card number belongs to Visa
if ((startingdigit113 == 4 || startingdigit116 == 4))
{
printf("VISA\n");
}
}
else if ((lastdigit == 0 && digitcount != 13) || (lastdigit == 0 && digitcount != 15) || (lastdigit == 0 && digitcount != 16))
{
printf("INVALID\n");
}
}```
Counting leading zeroes is a little hard with numeric input. Maybe you should read the card number as string into a char * array using scanf; then, validate the CCNumber.
...
...
...
// max CCNumber char length is 16, plus 1 for string terminator '\0' = 17 chars
char CCNumber[17];
int notValidInput = 1;
int digitCount = 0;
while (notValidInput) {
notValidInput = 0;
scanf("%s", CCNumber);
digitCount = 0;
while (CCNumber[digitCount] != '\0') {
// CCNumber character validation
if (CCNumber[digitCount] < '0' || CCNumber[digitCount] > '9') {
notValidInput = 1;
printf("error: must contain numeric chars.\n");
break;
}
else {
digitCount++;
}
}
...
...
...
}

CS50 Credit Card Validation

#include <stdio.h>
#include <cs50.h>
int main(void)
{
long cc = get_long("Credit Card: "); // gets input
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;
}
}
}
There has to be a better way then the way I am planning to do this. The Length count loop is fine until 10 digits but then pulls random numbers.
The every other digit formula seems like it can be done through recursion but I am blanking on that. Since the number is limited to 16 at most the formula I am using seems to work.
Determine if card is 15 || 16 || 13 digits if not mark In valid in IF Else loop
Use CC check sum formula If else loop (In valid if it doesn't meet Criteria)
Look at 2 Starting numbers to determine AX, MC or 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 );
}
Let's acknowledge the elephant in the room first.
long cc = get_long("Credit Card: " );
...
int x = cc;
The C standard specifies long to be at least 32 bits, whereas int must be at least 16 bits. The actual values are dependent on your system and your library implementation of course. But more often than not, long will be capable of storing more bits than an int. As is the case here. This means "numbers with more than 10 digits", essentially numbers that are too large to be stored into an int, will cause undefined behavior. To know exactly which number is the upper limit for int in your system/environment, you may print the value of INT_MAX, defined in limits.h.
The solution is, of course, to store the long variable in another long variable, not an int. Or, simply pass the value to a function that does the necessary work. Putting everything in main isn't being very organized now is it.
How about we make a function that basically prints all the details about a card given the card's number?
The signature will look like-
void print_card_details(long num)
Now we need a function to put the card through luhn's algorithm. We can also make a function for that-
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;
}
}
The conventional way to iterate through the digits of a number is not to bruteforcefully divide arbitrary powers of 10 manually, but to iterate through it and divide and modulus by 10. For example, this snippet-
while (x != 0)
{
printf("Current digit: %d\n", x % 10);
x /= 10;
}
Will print all digits of the number stored in x. This is essentially what we've used in the luhn's algorithm loop. Except we also keep a count of the total digits, because we only want every second digit starting from the end. How do we know the current digit qualifies this criteria? We check if the current digit_count is even (by dividing by 2 and checking the leftover is 0).
The formula that follows-
add_digit = curr_digit * 2;
prod_sum += add_digit % 10 + add_digit / 10;
is basically the implementation of this-
Multiply every other digit by 2, starting with the number’s second-to-last digit, and then add those products’ digits together.
Make sure only the digits of the resulting add_digit is added. So if add_digit ended up being 12. We need to add 1 + 2. That's exactly what add_digit % 10 + add_digit / 10 does. 12 % 10 is, of course, 2. And 12 / 10 is 1.
This function returns 1 if the card is valid, 0 if it's not. You can fit this up in your main function and check the return value to know whether the card is valid.
If it is valid, move on to the next step of checking the number of digits the card has, as well as what it begins with.
We can make a loop to count the number of digits, as well as store the very first and second digit of the number.
int len = 0;
int curr_digit = 0, prev_digit = 0;
while(num != 0)
{
prev_digit = curr_digit;
curr_digit = num % 10;
num /= 10;
len++;
}
This will give you the length of the card number. Notice, in the last iteration, the value of prev_digit is the second digit and the curr_digit is the first. So curr_digit * 10 + prev_digit will yield the first 2 numbers (together) that the credit card number begins with.
Finally, you just need a bunch of simple if/else clauses to verify which card it is. You're only asked to check for a very small subset as well. So here it is-
// 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");
}
Put that all together, and you should hopefully get
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;
}

Detect valid credit card number algorithm

I just enrolled in the online CS50 course and doing the pset1 about detecting valid credit card number. However, my algorithm does not work well as I expected. I used debugging tool to see step by step result, as long as variable i run from 1 to 9 it works perfectly, all values are added to the sum correctly. But when it comes to i = 10 and so on, the numNotSquared got assigned -8 and numSquared got assigned -16 and it keeps like that until the end of the number. Please help me with that, thank you.
// Headers and libraries
#include <stdio.h>
#include <cs50.h>
#include <math.h>
int main(void)
{
// Prompt user for card number
long cardNumber = get_long("Enter card number: ");
// Get the length of input
int length = floor(log10(cardNumber)) + 1;
// Range validation
if (length < 13 || length > 16)
{
printf("INVALID\n");
}
int numSquared = 0;
int numNotSquared = 0;
int sum = 0;
// Algorithm to detect valid card
// Based on Luhn's algorithm (https://lab.cs50.io/cs50/labs/2020/x/credit/)
for (int i = 1; i <= length; i++)
{
// If digit is on odd position then mutiply by two
if (i % 2 != 0)
{
{
numSquared = ((int)(cardNumber / pow(10, length - i)) % 10) * 2;
}
// If the total is >= 10, then sum the products' digit
if (numSquared >= 10)
{
sum += ((numSquared % 10) + 1);
}
else
{
sum += numSquared;
}
}
// If digit is on even position then add to the sum
else
{
numNotSquared = (int)(cardNumber / pow(10, length - i)) % 10;
sum += numNotSquared;
}
}
// Find remainder of (total / 10)
if (sum % 10 == 0)
{
if (floor(cardNumber / pow(10, length - 1)) == 4)
{
printf("VISA\n");
}
else
{
int firstTwoDigits = floor(cardNumber / pow(10, length - 2));
if (firstTwoDigits == 34 || firstTwoDigits == 37)
{
printf("AMEX\n");
}
else if (firstTwoDigits == 51 || firstTwoDigits == 52 || firstTwoDigits == 53 || firstTwoDigits == 54 || firstTwoDigits == 55)
{
printf("MASTERCARD\n");
}
}
}
else
{
printf("INVALID\n");
}
}

Wanted to check if a credit card number is valid or not

I wanted to check if a credit card number is valid or not but when i run the code, every number I give as input, the output comes as invalid.
The example given below is what I should i do.
Example with David’s Visa: 4003600000000014.
For the sake of discussion, let’s first underline every other digit, starting with the number’s second-to-last digit:
4003600000000014
Okay, let’s multiply each of the underlined digits by 2:
1•2 + 0•2 + 0•2 + 0•2 + 0•2 + 6•2 + 0•2 + 4•2
That gives us:
2 + 0 + 0 + 0 + 0 + 12 + 0 + 8
Now let’s add those products’ digits (i.e., not the products themselves) together:
2 + 0 + 0 + 0 + 0 + 1 + 2 + 0 + 8 = 13
Now let’s add that sum (13) to the sum of the digits that weren’t multiplied by 2 (starting from the end):
13 + 4 + 0 + 0 + 0 + 0 + 0 + 3 + 0 = 20
, the last digit in that sum (20) is a 0, so David’s card is legit!
#include <stdio.h>
int main()
{
int no;
printf("Visa number: ");`
scanf("%d", &no);
int d_1, d_2, d_3, d_4, d_5, d_6, d_7, d_8, d_9, d_10, d_11, d_12, d_13, d_14, d_15;
d_15 = no%10;
d_14 = ((no%100)/10)*2;
d_13 = (no%1000)/100;
d_12 = ((no%10000)/1000)*2;
d_11 = (no%100000)/10000;
d_10 = ((no%1000000)/100000)*2;
d_9 = (no%10000000)/1000000;
d_8 = ((no%100000000)/10000000)*2;
d_7 = (no%1000000000)/100000000;
d_6 = ((no%10000000000)/1000000000)*2;
d_5 = (no%100000000000)/10000000000;
d_4 = ((no%1000000000000)/100000000000)*2;
d_3 = (no%10000000000000)/1000000000000;
d_2 = ((no%100000000000000)/10000000000000)*2;
d_1 = (no%1000000000000000)/100000000000000;
int d[7] = {d_2, d_4, d_6, d_8, d_10, d_12, d_14};
int n,add;
for (n=1; n<=7; n++)
if(d[n]>10)
{
d[n] = (d[n]%10);
d[(15-n)+1] = ((d[n]%100)/10);
int sum=0;
for (int i=0; i<7; i++)
sum += d[i];
}
else
{
add = d_14 + d_12 + d_10 + d_8 + d_6 + d_4 + d_2;
}
int sum = add + d_15 + d_13 + d_11 + d_9 + d_7 + d_5 + d_3 + d_1;
if ((sum % 10) == 0)
{
printf("%s\n", "The card is valid");
}
else
{
printf("%s\n", "The card is invalid");
}
}
every number I give as input, the output comes as invalid.
Too big
OP's int is likely 32-bit.
Reading text input that would attempt to form an int outside the int range is undefined behavior. Rest of code is irrelevant.
int no;
scanf("%d", &no); // attempt to read "4003600000000014" leads to UB.
Consider reading user input into a string first and then process the characters. #Weather Vane
char buf[100];
if (fgets(buf, sizeof buf, stdin)) {
int i;
sum[2] = { 0, 0 }; // sums of even indexed digits and odd indexed digits.
// Note: only 1 sum really needed, but using 2 sums to mimic OP's approach
for (i = 0; isdigit((unsigned char) buf[i]); i++) {
digit = buf[i] - '0';
if (i%2 == 0) {
digit *= 2;
if (digit >= 10) {
digit = (digit/10 + digit%10);
}
}
sum[i%2] += digit;
}
// reject bad input: too long or missing expected end
if (i > 16 || (buf[i] != '\n' && buf[i] != '\0')) {
puts("Bad input");
} else {
// pseudo code to not give everything away.
// do math on sum[0], sum[1]
// if as expected --> success
}
}
#include <stdio.h>
#include <cs50.h>
long credit;
int getting_the_final_total_number (void);
void checking_which_kind (void);
int main(void)
{
credit = get_long("Number: ");
int i = 0;
long number_count = credit;
//finding how many numbers are there.
while(number_count > 0)
{
number_count /= 10;
i++;
}
//we use and because (using or make once true, the code block will work and always telling INVALID)
if(i != 13 && i != 15 && i != 16)
{
printf("INVALID\n");
return 0;
}
int total = getting_the_final_total_number(); //adding sum_1 and sum_2
if(total % 10 != 0)
{
printf("INVALID\n");
return 0;
}
checking_which_kind();
}
//assigning the credit to another variable for the loop
int getting_the_final_total_number (void)
{
long credit_one = credit;
int mod_1;
int mod_2;
int sum_1 = 0;
int m;
int d;
int sum_2 = 0;
do
{
//cutting the number into two pieces with all the last numbers and all the second-last-numbers
//cutting the last numbers.
mod_1 = credit_one % 10;
credit_one = credit_one / 10;
sum_1 += mod_1;
//cutting the second-last-numbers.
mod_2 = credit_one % 10;
credit_one = credit_one / 10;
//doubling the mod_2 (the second-last-numbers)
mod_2 = mod_2 * 2;
//making them into one number (if there is 16 or 18 in the product then make them 1 and 6 or 1 and 8. After that add them all together ).
m = mod_2 % 10; //This is for only one standing numer like 1 or 2 or 9 etc (but no 12 or 14 or 16)
d = mod_2 / 10; //This is for ten's digit to make sure to become ONE standing digit
sum_2 = sum_2 + m + d;
}
while(credit_one > 0);
return sum_1 + sum_2;
}
//checking the first two number of credit
void checking_which_kind (void)
{
long cc = credit;
do
{
cc = cc / 10;
}
while(cc > 100);
if(cc / 10 == 5 && (cc % 10 > 0 || cc % 10 < 6))
{
printf("MASTERCARD\n");
}
else if(cc / 10 == 3 && (cc % 10 == 4 || cc % 10 == 7))
{
printf("AMERICAN EXPRESS\n");
}
else if(cc / 10 == 4 && cc % 10 >= 0)
{
printf("VISA\n");
}
else
{
printf("ERROR");
}
}

Resources