2015-06-26 4 views
1

Я программист в первый раз, попробовав заполнить простую программу командной строки как часть first assignment для онлайн-курса, который я принимаю, но, похоже, я попал контрольный блок, который я не могу понять с помощью GDB или моих собственных исследований.Оператор 'if' в C не выполняется, хотя условия выполнены

После нескольких часов перезаписывания и часов отладки я, наконец, получил код для компиляции. Предполагается, что в качестве входа предполагается ввести номер кредитной карты, а затем проверить, действительно ли она соответствует спецификациям задания. Я использовал тестовый номер отсюда: PayPal Test Credit Cards

Странно, когда я ввожу номер карты AMEX, он правильно выдает текст «AMEX», но когда я пытаюсь выполнить визу или основную карту, он печатает «INVALID ».

В GDB я нарушил функцию Verify и, похоже, неправильно пропустил эти два оператора if/else if, не переходя к функции Checksum, даже несмотря на то, что условия выполняются.

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. 

... 

AMEX строка кода, который правильно выполняет это:

else if (firstDigit == 3 && secondDigit == (4 | 7) && totalDigits == 15 && Checksum(cardNumber, totalDigits) == 0) // checks for a valid American Express. 

Аргументы для всех трех линий, кажется, быть отформатирован точно так же. Тем не менее, я могу попасть в GDB. Я бы напечатал totalDigits, firstDigit и secondDigit в GDB прямо перед тем, как пройти через две неработающие строки, и все выглядело правильно. Итак, я в тупике, почему работает линия AMEX, но не другие?

Заранее благодарен всем. Это первая программа после hello.c, которую я пытался написать, поэтому я открыт абсолютно любой критике или предложениям, если это похоже на то, что я делаю что-то странное/неправильное.

Полный код:

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

'secondDigit == (4 | 7)' [не делает то, что вы думаете, что он делает] (https://en.wikipedia.org/wiki/Bitwise_operations_in_C#Bitwise_OR_.22.7C.22) ... – scohe001

+1

Изменить 'secondDigit == (4 | 7)' to '((secondDigit == 4) || (secondDigit == 7))'. – haccks

ответ

5

Ваша первая проблема здесь:

if (firstDigit == 4 && totalDigits == (13 | 16) && ... 

Вам нужно написать:

if (firstDigit == 4 && (totalDigits == 13 || totalDigits == 16) && ... 

Ваш первый чек ищет 0x1D == 29 как количество цифр (поскольку, как paisanco указывает в comment,Операторявляется побитовым оператором ИЛИ), и никакая кредитная карта не нуждается в 29-значных цифрах (но не в течение длительного времени). Обратите внимание на дополнительные скобки для ясности и точности. Не путайте, рискуя удалить их. — код не будет работать должным образом. И вообще, будьте ясными, если ваше условие имеет как операторы &&, так и || и использовать круглые скобки для группового выражения явно.

У вас похожие проблемы в другом месте. Как это бывает, (4 | 7) - это то же значение, что и 7, поэтому условие работает, когда вторая цифра равна 7 (но не тогда, когда она равна 4). Но это не значит, что вы имели в виду.

Компьютерные языки не работают так же, как человеческие языки. Привыкнуть к тому, чтобы написать условие несколько более подробно. Некоторые другие языки обеспечивают сокращение этих условий; C не является таким языком.

+1

Правильно и уточнить для ОП (который говорит, что они новый программист) (13 | 16) является побитовым ИЛИ, а не логическим ИЛИ. Второй пример - правильный логический ИЛИ. – paisanco

+0

Спасибо @ Jonathan Leffler & paisanco. У меня было ощущение, что это могло быть частью этого. Когда я изначально написал его, я использовал ||, но он не компилировался и не предложил использовать один | вместо. Скорректированный мой код в соответствии с приведенной выше рекомендацией, и все работает сейчас. – JeremyWickwire

+0

Хотя это хороший ответ, стоит также упомянуть коммутационный корпус с провалом для таких ситуаций. – technosaurus

Смежные вопросы