JeremyWickwire
JeremyWickwire

Reputation: 13

'if' statement in C not executing even though conditions are met

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;
}
}

Upvotes: 1

Views: 1811

Answers (1)

Jonathan Leffler
Jonathan Leffler

Reputation: 754920

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.

Upvotes: 5

Related Questions