Task: the user enters the card number and needs to determine whether the card is valid and, if so, determine the type of card (Visa, MasterCard, American Express). We have [https://cs50.harvard.edu/college/2021/spring/psets/1/credit/#luhns-algorithm][Luhn's Algorithm] to determine the validation of card number.
Problem: sometimes programm identifies invalid card as Visa(for example: 4111111111111113, 4222222222223). I really don't know how to solve this problem( I've already seen other solutions of this CS50 Credit task, but since I'm a beginner, I want to know what's wrong exactly with this code. I would be grateful for any hints on this problem and the code as a whole. Appreciate your help!
#include <cs50.h>
#include <stdio.h>
#include <math.h>
int main(void)
{
long credit;
do
{
credit = get_long("Number of card:\n");
}
while (credit < 0);
long number = credit;
int digits;
for (digits = 0; number > 0; digits++)
{
number /= 10;
}
int checksum = 0;
int i;
for (i = 0; number > 0; i++, number /= 10)
{
if (i % 2 == 0)
{
checksum += (number % 10);
}
else
{
int n = (number % 10) * 2;
if (n > 9)
{
n = (n / 10) + (n % 10);
}
checksum += n;
}
}
checksum = checksum % 10;
if ((checksum == 0) && ((credit >= 34e13 && credit < 35e13) || (credit >= 37e13 && credit < 38e13)))
{
printf("AMEX\n");
}
else if ((checksum == 0) && (credit >= 51e14 && credit < 56e14))
{
printf("MASTERCARD\n");
}
else if ((checksum == 0) && ((credit >= 4e12 && credit < 5e12) || (credit >= 4e15 && credit < 5e15)))
{
printf("VISA\n");
}
else
{
printf("INVALID\n");
}
}
Code changes number
for (digits = 0; number > 0; digits++) {
number /= 10;
}
int checksum = 0;
int i;
Consider the value of number after the above loop. Certainly 0. Next loop does not iterate.
for (i = 0; number > 0; i++, number /= 10)
Code needs to preserve number.
Related
Been working on this problem set for the past few hours and I thought I was doing pretty well, but when I ran it, doesn't really work as expected.
Kinda stuck at the moment, can anyone offer some insight?
EDIT
Sorry guys, I'll provide a little more insight on the problem because too little info is provided for it in my post. So basically I have to implement the Luhn's algorithm. According to Luhn’s algorithm, you can determine if a credit card number is (syntactically) valid as follows:
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!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
printf("type a credit card number: ");
char ccnum[17];
fgets(ccnum, 17, stdin);
int ccnumber[15];
int n = strlen(ccnum);
for (int i = 0; i<16; i++)
{
ccnumber[i] = ccnum[i] -'0';
}
int ccnumber_m[7];
for (int i = 0; i < 16; i+=2)
{
ccnumber_m[i] = ccnumber[i]*2;
}
int sum = 0;
for (int i = 0; i < 8; i++)
{
if (ccnumber_m[i] > 9)
{
sum += (ccnumber_m[i] % 10) + 1;
}
else
{
sum += ccnumber_m[i];
}
printf("%d\n", sum);
}
for (int i = 1; i < 16; i+=2)
{
sum += ccnumber[i];
}
if (sum%10 == 0)
{
if ( (n == 15) && (ccnumber[0] == 34 || ccnumber[0] == 37))
{
printf("AMEX\n");
}
else if ((n == 16) && (ccnumber[0] == 51 || ccnumber[0] == 52 ||ccnumber[0] == 53 || ccnumber[0] == 54 || ccnumber[0] == 55))
{
printf("MASTERCARD\n");
}
else if ((n == 13 || n == 16) && ccnumber[0] == 4)
{
printf("VISA\n");
}
}
else
{
printf("INVALID\n");
}
}
I've added a printf to my sum variable to see where the program is failing and that's where things seem to be screwing up. Every time I run it, different values of sum appear?!
Thanks in advance.
Okay guys, found the solution. Yes I messed up most of my loops and the array ranges and the conditions were all over the place. Did some tweaks to my code overall and after a few more hours, the code works as expected. Here's the updated code.
Pretty sure the code could be more succinct and could be solved much faster. Will take a look at it tomorrow again in order to brainstorm more ideas and find ways to solve it faster.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(void)
{
printf("type a credit card number: ");
char ccnum[17];
fgets(ccnum, 17, stdin);
int ccnumber[15];
int n = strlen(ccnum);
int counter = 0;
for (int i = 0; i < n; i++)
{
ccnumber[i] = ccnum[i] -'0';
if (ccnumber[i] >= 0)
{
counter ++;
}
}
int sum = 0;
if (counter == 16)
{
int ccnumber_m[7];
int index = 0;
for (int i = counter - 2; i > -1 ; i-=2, index++)
{
ccnumber_m[index] = ccnumber[i]*2;
}
for (int i = 0; i < 8; i++)
{
if (ccnumber_m[i] > 9)
{
sum += (ccnumber_m[i] % 10) + 1;
}
else
{
sum += ccnumber_m[i];
}
}
for (int i = 1; i < counter + 1; i+=2)
{
sum += ccnumber[i];
}
}
else if (counter == 15)
{
int ccnumber_m[6];
int index = 0;
for (int i = counter-2; i > 0; i-=2, index++)
{
ccnumber_m[index] = ccnumber[i]*2;
}
for (int i = 0; i < 7; i++)
{
if (ccnumber_m[i] > 9)
{
sum += (ccnumber_m[i] % 10) + 1;
}
else
{
sum += ccnumber_m[i];
}
}
for (int i = 0; i < counter + 1; i+=2)
{
sum += ccnumber[i];
}
}
else if(counter == 13)
{
int ccnumber_m[5];
int index = 0;
for (int i = counter-2; i > 0; i-=2, index++)
{
ccnumber_m[index] = ccnumber[i]*2;
}
for (int i = 0; i < 6; i++)
{
if (ccnumber_m[i] > 9)
{
sum += (ccnumber_m[i] % 10) + 1;
}
else
{
sum += ccnumber_m[i];
}
}
for (int i = 0; i < counter + 1; i+=2)
{
sum += ccnumber[i];
}
}
else
{
printf("INVALID\n");
return 0;
}
if (sum%10 == 0)
{
if ((counter == 15) && ((ccnumber[0] == 3 && ccnumber[1] == 4) || (ccnumber[0] == 3 && ccnumber[1] == 7)))
{
printf("AMEX\n");
}
else if ((counter == 16) && ((ccnumber[0] == 5 && ccnumber[1] == 1) || (ccnumber[0] == 5 && ccnumber[1] == 2) || (ccnumber[0] == 5 && ccnumber[1] == 3) || (ccnumber[0] == 5 && ccnumber[1] == 4) || (ccnumber[0] == 5 && ccnumber[1] == 5)))
{
printf("MASTERCARD\n");
}
else if ((counter == 13 || counter == 16) && (ccnumber[0] == 4))
{
printf("VISA\n");
}
else
{
printf("INVALID\n");
return 0;
}
}
else
{
printf("INVALID\n");
return 0;
}
}
I am really stuck here. The programm gives right answer to invald credit card numbers but never say if its VISA, AMEX or MASTERCARD.
I need to post the complete code because I do not have so much experience wit the C language.
The checksum part in the end could also have been "bool" but I always got error messages with that.
#include <cs50.h>
#include <stdio.h>
int main(void)
{
long long card;
int checksum = 0;
do
{
card = get_long_long("Number: ");
}while (card <= 0);
int count = 0;
while (card != 0) {
card /= 10; // n = n/10
++count;
}
if(count != 16 && count != 13 && count != 15){
printf("INVALID\n");
}
else if(checksum != 0){
printf("INVALID\n");
}
else if(card >= 34e13 || card >= 37e13){
printf("AMEX\n");
}
else if(card >= 51e14 || card >= 52e14 || card >= 53e14 || card >= 54e14 || card >= 55e15) {
printf("MASTERCARD\n");
}
else if(card >= 4e15 || card >=4e12) {
printf("VISA\n");
}
else {
printf("INVALID\n");
}
}
int checksum(long long card_nr)
{
int sum = 0;
for (int i=0;card_nr !=0; i++, card_nr/=10 )
{
if(i % 2 == 0)
sum += card_nr % 10;
else
{
int digit = 2 * (card_nr % 10);
sum += digit / 10 + digit % 10;
}
}
return (sum % 10) == 0;
}
There may be major issue or only some parenthesis, the programm is compiling. Thanks for any help.
There are many errors with the logic:
#include <cs50.h>
#include <stdio.h>
int main(void)
{
long long card;
int checksum = 0;
do
{
card = get_long_long("Number: ");
}while (card <= 0);
int count = 0;
// ** In here you destroy card, so later card whill allways be 0
while (card != 0) {
card /= 10; // n = n/10
++count;
}
if(count != 16 && count != 13 && count != 15){
printf("INVALID\n");
}
else if(checksum != 0){
printf("INVALID\n");
}
//** here it is the same as if(card >= 34e13)
else if(card >= 34e13 || card >= 37e13){
printf("AMEX\n");
}
//** here it is the same as if(card >= 51e14)
//** also these values are already covered by last check
else if(card >= 51e14 || card >= 52e14 || card >= 53e14 || card >= 54e14 || card >= 55e15) {
printf("MASTERCARD\n");
}
//** here it is the same as if(card >= 4e15)
//** also these values are already covered by previous check
else if(card >= 4e15 || card >=4e12) {
printf("VISA\n");
}
else {
printf("INVALID\n");
}
}
int checksum(long long card_nr)
{
int sum = 0;
for (int i=0;card_nr !=0; i++, card_nr/=10 )
{
if(i % 2 == 0)
sum += card_nr % 10;
else
{
int digit = 2 * (card_nr % 10);
sum += digit / 10 + digit % 10;
}
}
return (sum % 10) == 0;
}```
After loop:
while (card != 0) {
card /= 10; // n = n/10
++count;
}
card = 0 and original card number is lost.
You can save original card number to another variable and then compare it.
Also it is better to use integer constants like 54LL << 14 instead of float 54e14
When I enter a credit card number that should work it outputs "INVALID" when it should output the credit card brand. I believe something is going wrong in the validity function but i can't seem to figure out what. I've spent a couple hours trying to fix the problem but nothing has worked. It would be great if I could get some help, thanks so much!
This is my code:
#include <stdio.h>
#include <cs50.h>
bool validity(long long creditNum);
int find_length(long long n);
bool checksum(long long ccn);
void credit_card_num(long long ccn);
int main(void)
{
long long creditNum;
do
{
creditNum = get_long_long("Enter Card Number: ");
}
while(creditNum < 0);
if (validity(creditNum) == true)
credit_card_num(creditNum);
else
printf("INVALID\n");
}
bool validity(long long creditNum)
{
int length = find_length(creditNum);
if ((length == 13 || length == 15 || length == 16) && checksum(creditNum))
return true;
else
return false;
}
int find_length(long long n)
{
int length;
for (length = 0; n != 0; n/= 10)
length++;
return length;
}
bool checksum(long long ccn)
{
int sum = 0;
int digit;
for (int i = 0; ccn != 0; i++, ccn /= 10)
{
if (i % 2 == 0)
sum += ccn % 10;
else
digit = 2 * (ccn % 10);
sum += digit / 10 + digit % 10;
}
if ((sum % 10) == 0)
return true;
else
return false;
}
void credit_card_num(long long ccn)
{
if ((ccn >= 34e13 && ccn < 35e13) || (ccn >= 37e13 && ccn < 38e13))
printf("AMEX\n");
else if (ccn >= 51e14 && ccn < 56e14)
printf("MASTERCARD\n");
else if ((ccn >= 4e12 && ccn < 5e12) || (ccn >= 4e15 && ccn < 5e15))
printf("VISA\n");
else
printf("INVALID\n");
}
It looks like your error is in your checksum function; specifically, the for loop.
for (int i = 0; ccn != 0; i++, ccn /= 10)
{
if (i % 2 == 0)
sum += ccn % 10;
else
digit = 2 * (ccn % 10);
sum += digit / 10 + digit % 10;
}
should be
for (int i = 0; ccn != 0; i++, ccn /= 10)
{
if (i % 2 == 0){
sum += ccn % 10;
} else {
digit = 2 * (ccn % 10);
sum += digit / 10 + digit % 10;
}
}
There was incorrect nesting around your if-else statement. I tested with a couple numbers and they printed the correct output.
First of all, it would be great if you included the "get_long_long" function, so we could see how the input is taken.
Secondly, the digit variable inside the checksum function wasn't initialized, which caused some problems.
Lastly, from a brief look here, you kinda implemented the algorithm in a wrong way, I fixed it, please check that the result is working for you:
bool checksum(long long ccn)
{
int sum = 0;
int digit;
for (int i = 0; ccn != 0; i++, ccn /= 10)
{
digit = ccn % 10;
if (i % 2 != 0) {
digit *= 2;
if (digit > 9)
digit -= 9;
}
sum += digit;
}
if ((sum % 10) == 0)
return true;
else
return false;
}
I first attempted the code myself, then tweaked it after watching Deliberate Think's video on Youtube. While my code can be compiled, all credit card number inputs return "INVALID" e.g. when using the testing AMEX number on PayPal (378282246310005), check50 says that: "identifies 378282246310005 as AMEX expected "AMEX\n", not "INVALID\n". I think there may be a problem under //implementing Luhn's algorithm.
Below is my code:
#include <stdio.h>
#include <cs50.h>
int find_length(long long ccn);
bool check_luhn(long long ccn);
bool check_validity(long long ccn);
void print_card_brand(long long ccn);
//prompt user for credit card number; if invalid prompts again
int main(void)
{
long long ccn;
do
{
ccn = get_long_long("Credit Card Number: ");
}
while (ccn < 0);
if (check_validity(ccn))
print_card_brand(ccn);
else
printf("INVALID\n");
}
//find the length of the credit card number
int find_length(long long ccn)
{
int length;
for (length = 0; ccn!= 0; ccn /=10);
length++;
return length;
}
//implementing Luhn's algorithm
bool check_luhn(long long ccn)
{
int sum = 0;
for (int i = 0; ccn != 0; i++, ccn /= 10)
{
if (i % 2 == 0)
sum += ccn % 10;
else
{
int digit = 2 * (ccn % 10);
sum += digit / 10 + digit % 10;
}
}
return (sum % 10) == 0;
}
//check length and Luhn's algorithm
bool check_validity(long long ccn)
{
int length = find_length(ccn);
return (length == 13 || length == 15 || length == 16) && check_luhn(ccn);
}
//print credit card brand
void print_card_brand(long long ccn)
{
if ( (ccn >= 34e13 && ccn < 35e13) || (ccn >= 37e13 && ccn < 38e13) )
printf("AMEX\n");
else if (ccn >= 51e14 && ccn < 56e14)
printf("MASTERCARD\n");
else if ( (ccn >= 4e12 && ccn < 5e12) || (ccn >= 4e15 && ccn < 5e15) )
printf("VISA\n");
else
printf("INVALID\n");
}
Thank you all in advance for your help, I've been stuck on this for so many days. Having never done coding before, I have no idea what went wrong.
You have a few bugs in there, one pointed out in the comments above is a rogue semicolon. Your implementation of luhn wasn't quite right so I've tried to fix it. I tried to fix this whilst making minimal changes. I didn't have access to CS50.h, so I addded stdbool and a dodgy scanf. I would undo those two changes.
#include <stdio.h>
#include <stdbool.h>
int find_length(long long ccn);
bool check_luhn(long long ccn);
bool check_validity(long long ccn);
void print_card_brand(long long ccn);
//prompt user for credit card number; if invalid prompts again
int main(void)
{
long long ccn;
do
{
scanf("Credit card number: %lld", &ccn);
}
while (ccn < 0);
if (check_validity(ccn))
print_card_brand(ccn);
else
printf("INVALID\n");
}
//find the length of the credit card number
int find_length(long long ccn)
{
int length;
for (length = 0; ccn!= 0; ccn /=10)
length++;
return length;
}
//implementing Luhn's algorithm
bool check_luhn(long long ccn)
{
int sum = 0;
long long temp_ccn = ccn;
int length = find_length(ccn);
for (int i = 1; i <= find_length(ccn); i++)
{
int rightDigit = temp_ccn % 10LL;
if (i % 2 == 0)
{
rightDigit = rightDigit * 2;
if (rightDigit > 9)
{
rightDigit -= 9;
}
}
sum += rightDigit;
temp_ccn /= 10LL;
}
return (sum % 10) == 0;
}
//check length and Luhn's algorithm
bool check_validity(long long ccn)
{
int length = find_length(ccn);
return (length == 13 || length == 15 || length == 16) && check_luhn(ccn);
}
//print credit card brand
void print_card_brand(long long ccn)
{
if ( (ccn >= 34e13 && ccn < 35e13) || (ccn >= 37e13 && ccn < 38e13) )
printf("AMEX\n");
else if (ccn >= 51e14 && ccn < 56e14)
printf("MASTERCARD\n");
else if ( (ccn >= 4e12 && ccn < 5e12) || (ccn >= 4e15 && ccn < 5e15) )
printf("VISA\n");
else
printf("INVALID\n");
}
I am working on the credit problem of CS50. However, I am only printing INVALID no matter what card number I put in. May I ask what is the problem with my code? It seems that there is something wrong with the part to calculate the total sum.
#include <cs50.h>
#include <stdio.h>
#include <math.h>
int main(void)
{
// Get the card number
long num;
do
{
num = get_long("What is the card number?\n");
} while (num < 0);
long sum = 0, sum2 = 0, count = 0;
//Get the sum
for (long i = num; i > 0; i = i / 10)
{
sum += i % 10;
count++;
}
for (long i = num / 10; i > 0; i = i / 100)
{
sum2 += i % 10;
}
if ((sum + sum2) % 10 != 0)
{
printf("INVALID");
}
else
{
long digits = num / (10 * (count - 2));
if (count == 15 &&
(digits == 34 || digits == 37))
{
printf("AMERICAN EXPRESS");
}
else if (count == 16 && 51 <= digits <=55)
{
printf("MASTERCARD");
}
else if ((count == 16 || count == 13) && (digits / 10) == 4)
{
printf("VISA");
}
else
{
printf("INVALID");
}
}
}
This gives the sum of every digit.
for (long i = num; i > 0; i = i / 10)
{
sum += i % 10;
count++;
}
Review the problem set again, specifically the discussion of Luhn's Algorithm. There are two sums, however they are "mutually exclusive". If a digit is added to sum1 it will not be added to sum2. And versa vice. There is also a noticeable lack of *2 (times 2) anywhere in the code.
Perhaps you will find this walkthrough video helpful. Be warned: it is from an earlier version of the course and mentions the function get_long_long. That has been retired, use get_long as you have done here.