Why is my code wrong?? I don't know why... This problem is to get a card number from the user and tell whether it is a valid card number or an invalid card number. It could either be an American Express card, MasterCard, or a Visa. American Express card has 15 digits and must either start with 34 or 36, while MasterCard has 16 digits and can start with 51, 52, 53, 54, 55. The Visa card must either have 13 or 16 digits, and must start with a 4. This problem also uses the Luhn's algorithm wherein to check if a card number is valid every other number starting from the tens place multiplied by two, then if added the digits no their product but their digits, so if you multiply 8 by 2 its 16 so you must add 1 + 6 and the other numbers. Then once you got the sum you must add them to the ones you didn't multiply by 2, then lastly if their sum is divisible by 10 then it is valid. I really don't know where I went wrong I've been looking at my code for almost 3 hours. Also noob programmer here..
#include<stdio.h>
int main(void)
{
//declare and initialize card number
long long number = 0;
//ask user for their credit card number
do
{
printf("Number: ");
scanf("%lli", &number);
}
while (number < 0);
//declare and initialize a counter for the number of the digits
int counter = 0;
long long temp = number;
//loop to count the number of digits
while (temp > 0)
{
temp /= 10;
counter++;
}
//statement for invalid digits
if (counter != 13 && counter != 15 && counter != 16)
{
printf("Invalid number of digits\n");
}
//array to store the digits individually
int digits[counter];
// loop to store the digits in the array
for (int i = 0; i < counter; i++)
{
digits[i] = number % 10;
number /= 10;
}
//loop to multiply every other digit by 2
for (int j = 1; j < counter; j += 2)
{
digits[j] *= 2;
}
// loop to separate then add digits that are greater than 10
for (int x = 1; x < counter; x += 2)
{
if (digits[x] > 10)
{
int s = digits[x] % 10;
digits[x] /= 10;
digits[x] = (digits[x] % 10) + s;
}
}
int sum = 0;
//loop to get the sum of all numbers
for (int y = 0; y < counter; y++)
{
sum += digits[y];
}
sum %= 10;
switch (sum)
{
case '0':
if (counter == 15 && (digits[14] == 3 && (digits[13] == 4 || digits[13] == 7)))
{
printf("American Express\n");
}
else if (counter == 16 && digits[15] == 5)
{
printf("Master Card\n");
}
else if (counter == 13 && digits [12] == 4)
{
printf("Visa\n");
}
else if (counter == 16 && digits[15] == 4)
{
printf("Visa\n");
}
break;
default:
printf("Invalid\n");
break;
}
}
There are three errors, and I'm ashamed that it took myself so long to spot especially the second one.
if (digits[x] > 10) is a kind of off-by-one error. Rather than greater than 10, the Description of the Luhn algorithm says: If the result of this doubling operation is greater than 9 …, so this has to be if (digits[x] > 9).
case '0': must rather be case 0:, since sum is an integer, not a character representation.
if (counter == 15 && (digits[14] == 3 && (digits[13] == 4 || digits[13] == 7))) fails because the digits have been modified by the algorithm in-place, so the 7 has become a 5. We could write if (counter == 15 && (digits[14] == 3 && (digits[13] == 4 || digits[13] == 7*2-9))) instead; same for else if (counter == 16 && digits[15] == 5).
Related
The calculating if the card is valid is correct as I tested that and the code performed correctly there, so I removed that section from under the Do section loop to appease stackoverflow. The problem comes from deciding what type of card was used; the program does nothing and waits for the next command in the console. I'm just not seeing what the issue is. Below is my code and I tested with card number 4003600000000014, the result should've printed out "Visa":
#include <stdio.h>
#include <cs50.h>
#include <math.h>
int main(void)
{
// Array to store the individual digits of the card
long card, card_copy;
int pos = 0, sum = 0, card_id;
do
{
card = get_long("CC#: ");
card_copy = card;
while(card != 0)
{
if(pos % 2 != 0)
{
int temp = 2 * (card % 10);
// For #s > 9
if(temp > 9)
{
sum += (temp % 10 + temp / 10);
}
else
{
sum += temp;
}
}
else
{
sum += card % 10;
}
card /= 10; // Divides card # to remove the decimal place
// and moves to the next digit in CC
pos++;
}
}
while(card != 0);
if(sum % 10 == 0)
{
// Divides card to only have the first 2 digits
card_id = card_copy / (pow(10, pos - 1));
// Divides card to only have first digit; 4 for Visa
int visa_id = card_copy / (pow(10, pos - 2));
// 16-digit; start with 51, 52, 53, 54, or 55
if(pos == 15 && (card_id >= 51 && card_id <= 55))
{
printf("MasterCard");
}
// 15-digit; start with 34 or 37
else if(pos == 14 && (card_id == 34 || card_id == 37))
{
printf("American Express");
}
// 13-digit; start with 4
else if(pos == 12 && visa_id == 4)
{
printf("Visa");
}
// 16-digit; start with 4
else if(pos == 15 && visa_id == 4)
{
printf("Visa");
}
}
else
{
printf("Invalid: %d\n", sum);
}
}
The long type has a maximum value of 2147483647. This wouldn't hold the shortest card type I know which is 12 digits.
Either change to unsigned long long or better still use a string.
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");
}
}
I'm currently working through CS50x's 2018 programme and I'm completing the 'credit' part of pset1. We're supposed to be executing Luhn's algorithm, but I can't get it to work.
Luhn's algorithm is an algorithm that uses checksum to determine whether or not a credit card is valid. The input should be a credit card number, or something that could be a credit card number. It then takes the number, multiplies every other digit by 2 (or every even digit as implied in my code), sums them, then takes the remaining digits (the odd ones) and sums them with the first sum. The algorithm then states that if the last digit of the summed value is 0 then the number is valid (or if it divides by ten perfectly). If the answer isn't 0 then it should print "INVALID" to the user. If it is 0 the code should then analyse whether or not the number could be a valid card. We are supposed to use American Express, Visa and MasterCard as our potential cards. If it's AMEX it will be 15 digits and start with 34 or 37, MASTERCARD is 16 digits and starts with 51, 52, 53, 54 or 55, and VISA is either 13 or 16 digits and starts with 4. The expected output is either one of the card companies or "INVALID" if the number doesn't fit that criteria.
Instead of this, my code simply runs until overflow after a number is submitted. I know my logic must be flawed somewhere, but I have no idea where I've gone wrong. My code is as follows:
//Checks credit card no. to see if valid
#include <cs50.h>
#include <stdio.h>
#include <math.h>
int main(void)
{
//Get card no. from user
long long n;
do
{
n = get_long_long("Card Number: ");
}
while (n < 0);
//Define variables for checksum process
int odd = 0;
int even = 0;
long long temp_n = n;
int sum_a = 0;
int sum_b = 0;
int counter = 0;
//Execute checksum until all of n assessed
while (temp_n >= 0)
{
//Take final digit, add up, then update temp no., increase digit counter by 1
odd = temp_n % 10;
sum_b = sum_b + odd;
temp_n = (temp_n - odd) / 10;
counter++;
//Take final digit (which is an even digit of n), multiply by 2 and add up, update temp no., increase counter by 1
even = temp_n % 10;
sum_a = sum_a + 2 * even;
temp_n = (temp_n - even) / 10;
counter++;
}
//Validate checksum
int test = (sum_a + sum_b) % 10;
//Return results
if (test == 0)
{
if (counter == 16 && odd == 5 && (even == 1 || even == 2 || even == 3 || even == 4 || even == 5))
{
printf("MASTERCARD\n");
}
else if ((counter == 16 || counter == 13) && odd == 4)
{
printf("VISA\n");
}
else if (counter == 15 && odd == 3 && (even == 4 || even == 7))
{
printf("AMEX\n");
}
else
{
printf("INVALID\n");
}
}
else
{
printf("INVALID\n");
}
}
I would appreciate any help I can get about where I've gone wrong. Thank you in advance.
while (temp_n >= 0)
{
//Take final digit, add up, then update temp no., increase digit counter by 1
odd = temp_n % 10;
sum_b = sum_b + odd;
temp_n = (temp_n - odd) / 10;
counter++;
//Take final digit (which is an even digit of n), multiply by 2 and add up, update temp no., increase counter by 1
even = temp_n % 10;
sum_a = sum_a + 2 * even;
temp_n = (temp_n - even) / 10;
counter++;
}
This assumes that input will always have even number of digits. Take a bool flag = true; and change it to:
while (temp_n >= 0)
{
//Take final digit, add up, then update temp no., increase digit counter by 1
if(flag){
odd = temp_n % 10;
sum_b = sum_b + odd;
temp_n = (temp_n - odd) / 10;
counter++;
flag = !flag;}
//Take final digit (which is an even digit of n), multiply by 2 and add up, update temp no., increase counter by 1
else{
even = temp_n % 10;
sum_a = sum_a + 2 * even;
temp_n = (temp_n - even) / 10;
counter++;
flag = !flag;}
}
I need my program to prompt a user for an input and re-prompt in case the input doesn't follow a credit card format (ex: negative numbers or letters, etc.) and then apply the algorithm to see if the number is a valid credit card number and if yes, whether it's Visa, MasterCard or AmEx.
I know that this question has been answered with different codes on this website, I swear I read everything that I could possibly find (on this site and elsewhere on the net) but I'm having a really hard time understanding the C syntax and I wanted to try to come up with something myself instead of copying bits of codes I don't understand from other answers. If someone can help me out and look at what I've done so far and tell me what I'm doing wrong I would be really grateful. Also, any tips that could help me make sense of the C syntax logic better would be extremely appreciated.
My program is compiling but when I run it it's acting up in a very weird way: when I enter an input sometimes it will say that it is invalid (even if it's a valid number) and sometimes it will just not return anything after I press enter and won't stop running no matter how many times I press the return key.
Here is my code so far:
#include <stdio.h>
#include <cs50.h>
#include <math.h>
int main(void)
{
printf("Please give me your credit card number:\n") ;
long long card_num ;
do
{
card_num = GetLongLong() ;
}
while (card_num < 1 || card_num > 9999999999999999) ;
// Make a copy of the card number to be used and modified throughout the process.
long long temp_num = card_num ;
int digit = 0 ;
int count = 0 ;
int sum_a = 0 ;
int sum_b = 0 ;
// Isolate every digit from the credit card number using a loop and the variable 'digit'.
// Keep track of the amount and position of each digit using variable 'count'.
while (card_num >= 0)
{
digit = card_num % 10 ;
count++ ;
temp_num = (card_num - digit) / 10 ;
break ;
// Apply Luhn's algorithm using two different 'for' loops depending on the position of each digit.
for (count = 0 ; count % 2 == 0 ; count++)
{
sum_a = sum_a + ((card_num % 10) * 2) ;
while ((card_num % 10) * 2 >= 10)
{
sum_a = (sum_a % 10) + 1 ;
}
}
for (count = 0 ; count % 2 != 0 ; count++)
{
sum_b = sum_b + digit ;
}
return sum_a ;
return sum_b ;
return count ;
}
// Checking the validity of the number according to Luhn's algorithm
int total_sum = sum_a + sum_b ;
if (total_sum % 10 != 0)
{
printf("This is an invalid number.\n") ;
}
// If the number entered doesn't have the right amount of digits according
// to variable 'count', declare the number as invalid.
if (count != 13 || count != 15 || count != 16)
{
printf("This is an invalid number.\n") ;
}
// Reset value of variable 'temp_num' and apply calculations that will isolate the first two digits.
// Store the results in a variable 'company_id'.
temp_num = card_num ;
int company_id ;
while (temp_num > 100)
{
temp_num = card_num - (card_num % 10) ;
company_id = temp_num / 10 ;
}
return company_id ;
// Print the type of credit card depending on the company ID and amount of digits.
if (company_id > 50 && company_id < 56 && count == 16)
{
printf("MASTERCARD\n") ;
}
else if ((company_id == 4) && (count == 13 || count == 16))
{
printf("VISA\n") ;
}
else if ((company_id == 34 || company_id == 37) && (count == 15))
{
printf("AMEX\n") ;
}
else
{
printf("This is an invalid number.\n") ;
}
return 0 ;
}
Your answer is a out of order pastiche with sections that don't follow logically from the previous.
Specific issues:
This logic:
if (count != 13 || count != 15 || count != 16)
invalidates every card, the ors (||) should be ands (&&) for this to work.
This loop makes no sense:
while (card_num >= 0)
{
digit = card_num % 10 ;
count++ ;
temp_num = (card_num - digit) / 10 ;
break ;
...
}
The break is unconditional so it exits the loop and ignores the next twenty lines.
You appear to have spliced in subroutines from elsewhere as you call return five times, only the last of which is valid:
return sum_a ;
return sum_b ;
return count ;
return company_id ;
return 0 ;
In several places you use card_num when you should be using temp_num.
You fail to exit the program once you know the card is invalid -- instead you just keep on testing. You fail to acknowledge when a card is valid.
You count the number of digits in the card number but wait until after you run other checks before testing if that digit count was valid or not.
What follows is my rework of your code to address the above and some style issues:
#include <stdio.h>
#include <cs50.h>
#include <math.h>
int main(void)
{
printf("Please give me your credit card number: ") ;
long long card_num = 0LL;
while (card_num < 1LL || card_num > 9999999999999999LL)
{
card_num = GetLongLong();
}
// Make a copy of the card number to be used and modified throughout the process.
long long temp_num = card_num;
// Isolate every digit from the credit card number using a loop and the variable 'digit'.
// Keep track of the amount and position of each digit using variable 'count'.
int count = 0;
while (temp_num > 0LL)
{
temp_num = temp_num / 10LL;
count++;
}
// If the number entered doesn't have the right amount of digits according
// to variable 'count', declare the number as invalid.
if (count != 13 && count != 15 && count != 16)
{
printf("This is an invalid number (# of digits).\n");
return 1;
}
// Reset value of variable 'temp_num' and apply calculations that will isolate the first two digits.
// Store the results in a variable 'company_id'.
temp_num = card_num;
while (temp_num > 100LL)
{
temp_num = temp_num / 10LL;
}
int company_id = temp_num;
// Print the type of credit card depending on the company ID and amount of digits.
if (company_id > 50 && company_id < 56 && count == 16)
{
printf("MASTERCARD\n") ;
}
else if ((company_id == 34 || company_id == 37) && (count == 15))
{
printf("AMEX\n") ;
}
else if ((company_id / 10 == 4) && (count == 13 || count == 16 || count == 19))
{
printf("VISA\n") ;
}
else
{
printf("This card was issued by an unknown company.\n");
}
// Apply Luhn's algorithm.
int sum = 0;
temp_num = card_num;
for (int i = 1; i <= count; i++)
{
int digit = temp_num % 10LL;
if (i % 2 == 0)
{
digit *= 2;
if (digit > 9)
{
digit -= 9;
}
}
sum += digit;
temp_num /= 10LL;
}
// Checking the validity of the number according to Luhn's algorithm
if (sum % 10 != 0)
{
printf("This is an invalid number (Luhn's algorithm).\n");
return 1;
}
printf("This is a valid number.\n");
return 0;
}
This is not a finished program -- there's error checking and other details needed. Rather than summing the digits when a doubled card number is greater than 9, I used the simpler approach of subtracting 9.
Here my solution, this method received the var long credit card number, I hope to be helpful.
void check_card(long n)
{
long temp_n = n;
int count = 2;
while(temp_n > 100)
{
temp_n = temp_n / 10;
count ++;
}
long temp_n2 = n;
int sum = 0;
for (int i = 1; i <= count; i++)
{
int digit = temp_n2 % 10;
if (i%2 == 0)
{
if (digit * 2 > 9)
{
sum += (digit * 2) - 9;
}
else
{
sum += digit * 2;
}
}
else
{
sum += digit;
}
temp_n2 /= 10;
}
bool flag = (sum % 10 == 0) ? true : false;
if (count == 15 && (temp_n == 34 || temp_n == 37) && flag)
{
printf("AMEX\n");
}
else if(count == 16 && (temp_n > 50 && temp_n < 56) && flag)
{
printf("MASTERCARD\n");
}
else if((count == 13 || count == 16) && (temp_n / 10 ==4) && flag)
{
printf("VISA\n");
}
else
{
printf("INVALID\n");
}
I'm a first time programmer trying to complete a simple command line program as part of the first assignment for an online course I am taking, but I seem to have hit a roadblock that I can't figure out with GDB or my own research.
After hours of rewrites, and hours of debugging, I finally got the code below to compile. The program is supposed to take a credit card number as an input, and then check whether it's valid per the specifications of the assignment. I used a test number from here: PayPal Test Credit Cards
The odd thing is, when I enter an AMEX card number, it correctly produces the text "AMEX", but when I try a Visa or a Master Card, it prints "INVALID".
In GDB I broke at the Verify function and it seems to incorrectly skip these two if/else if statements without proceeding to the Checksum function even though conditions appear to be met.
if (firstDigit == 4 && totalDigits == (13 | 16) && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Visa.
...
else if (firstDigit == 5 && secondDigit == (1 | 2 | 3 | 4 | 5) && totalDigits == 16 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Mastercard.
...
The AMEX line of code that correctly executes is:
else if (firstDigit == 3 && secondDigit == (4 | 7) && totalDigits == 15 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid American Express.
The arguments for all three lines seem to be formatted exactly the same. That is far as I could get in GDB though. I would print totalDigits, firstDigit, and secondDigit in GDB right before stepping through the above two non-executing lines and everything looked correct. So I'm stumped, why is the AMEX line executing, but not the others?
Thanks in advance everyone. This is the first program after hello.c that I've tried to write, so I am open to absolutely any criticism or suggestions if it looks like I'm doing something weird/wrong.
Full code:
checker.c
#include <stdio.h>
#include <stdlib.h>
int MAX = 16;
int* DigitSort(unsigned long long x, int* array);
int Verify(int* array);
int main (void)
{
int* output = malloc (sizeof(int) * (MAX + 2)); // creates a blank array for the individual digits of the card number.
unsigned long long userInput = 0;
do
{
printf("Please enter a credit card number:\n");
scanf("%lld", &userInput);
}
while (userInput <= 0); // checks to make sure the user entered a number.
switch(Verify(DigitSort(userInput, output))) // sorts the user's input into individual digits and verifies the card type and validity.
{
case 1 :
printf("VISA\n");
break;
case 2 :
printf("MASTERCARD\n");
break;
case 3 :
printf("AMEX\n");
break;
case 0 :
printf("INVALID\n");
break;
default :
printf("INVALID\n");
}
free(output);
return 0;
}
int Verify(int* array) // verifies whether or not a card number is valid. Must pass the function a sorted array of individual digits.
{
int* cardNumber = array;
int firstDigit = cardNumber[0];
int secondDigit = cardNumber[1];
int totalDigits = 0;
int Checksum(int* cardNumber, int totalDigits);
int i = 0;
while (firstDigit >= 1 && cardNumber[i] >= 0) // this step counts the number of digits in the array.
{
totalDigits = totalDigits + 1;
i++;
}
if (firstDigit == 4 && totalDigits == (13 | 16) && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Visa.
{
return 1;
}
else if (firstDigit == 5 && secondDigit == (1 | 2 | 3 | 4 | 5) && totalDigits == 16 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid Mastercard.
{
return 2;
}
else if (firstDigit == 3 && secondDigit == (4 | 7) && totalDigits == 15 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid American Express.
{
return 3;
}
else // if the card number doesn't match any of the above conditions or fails the checksum, an 'I' for Invalid is returned.
{
return 0;
}
}
int* DigitSort(unsigned long long x, int* array) // takes a long long as input and sorts it into individual digits
{
int* arrayReversed = malloc (sizeof(int) * (MAX + 2)); // creates a new array to hold the reversed order of digits.
int i = 0;
arrayReversed[0] = 0;
if (i < (MAX - 1) && x >= 10)
{
do
{
arrayReversed[i] = x % 10;
x = x / 10;
i++;
}
while (i < (MAX -1) && x >= 10);
}
if (i < MAX && x >= 1 && x <= 9)
{
arrayReversed[i] = (int) x;
x = (x - x);
}
if (x == 0)
{
int j = 0;
do
{
array[j] = arrayReversed[i]; // sorts the digits from the reversed array and places them into the sorted array.
j++;
i--;
}
while (j < MAX && i >= 0);
array[j] = -1;
}
free(arrayReversed);
return array;
}
int Checksum(int* cardNumber, int totalDigits)
{
int sum1 = 0;
int sum2 = 0;
int i = (totalDigits - 2);
int j = (totalDigits - 1);
while (i >= 0)
{
sum1 = ((cardNumber[i] * 2)%10) + ((cardNumber[i] * 2)/10) + sum1;
i -= 2;
}
while (j >= 0)
{
sum2 = (cardNumber[j] + sum2);
j -= 2;
}
if (((sum1 + sum2) % 10) == 0)
{
return 0;
}
else
{
return 1;
}
}
Your first problem is here:
if (firstDigit == 4 && totalDigits == (13 | 16) && ...
You need to write:
if (firstDigit == 4 && (totalDigits == 13 || totalDigits == 16) && ...
Your first check is looking for 0x1D == 29 as the number of digits (because, as paisanco points out in a comment, the | operator is the bitwise OR operator), and no credit card needs 29 digits (yet, and not for a long time to come). Note the extra parentheses for clarity and accuracy. Don't mess around risking removing them — the code won't work properly again. And in general, be explicit if your condition has both && and || operators and use parentheses to group terms explicitly.
You have similar problems elsewhere. As it happens, (4 | 7) is the same value as 7, so the condition works when the second digit is 7 (but not when it is 4). But it doesn't mean what you intended it to mean.
Computer languages don't work the same as human languages. Get used to writing out the condition somewhat more verbosely. Some other languages provide shorthands for these conditions; C is not such a language.