C: Проверка номера кредитной карты / алгоритм Луна - PullRequest
2 голосов
/ 08 февраля 2012

Все выглядит хорошо и, кажется, следует алгоритму Луна, но когда я ввожу свой номер кредитной карты или номер образца, который должен быть действительным: 4388576018410707, он все равно возвращается как недействительный ...

Может кто-нибудь найти проблему?

#include <stdio.h>

int isvalid(long num);
int sumofdoubleevenplace(long num);
int getdigit(int num);
int sumofoddplace(long num);
int prefixmatched(long num,int d);
int getsize(long d);
int getprefix(long num,int k);

main(){
  long cardnum=0;
  printf("Enter credit card number ");
  scanf("%ld",&cardnum);
  if(isvalid(cardnum)==1)
    printf("Valid card number\n");
else
    printf("Invalid card number\n ");
return 0;
}

int isvalid(long num){
if(((sumofoddplace(num)+sumofdoubleevenplace(num))%10==0)
   && (getsize(num)<=16 && getsize(num)>=13)
   && (prefixmatched(num,4)==1 || prefixmatched(num,5)==1 ||
       prefixmatched(num,6)==1 || prefixmatched(num,37==1)))
    return 1;
else
    return 0;
}

int sumofdoubleevenplace(long num){
int numdigits=getsize(num)-1;
int sum=0,i;
num/=10;
for(i=0;i<numdigits;i+=2){
    sum+=getdigit((int)(2*(num % 10)));
    num/=100;
}
return sum;
}

int getdigit(int num){
return ((num-num%10)/10)+num%10;
}

int sumofoddplace(long num){
int numberofdigits=getsize(num);
int sum=0,i;
for(i=0;i<numberofdigits;i+=2){
    sum+=num%10;
    num/=100;
}
return sum;
}

int prefixmatched(long num,int d){
if(getprefix(num,getsize(d))==d)
    return 1;
else
    return 0;
}

int getsize(long d){
int n=0;
while(d!=0){
    d/=10;
    n++;
}
return n;
}

int getprefix(long num,int k){
int numberofdigits=getsize(num);
int i;
if(numberofdigits-k>0){
    for(i=0;i<numberofdigits-k;i++){
        num/=10;
    }
    return num;
}
else
    return num;
}

Ответы [ 3 ]

4 голосов
/ 08 февраля 2012

Первое, что нужно сделать, это распечатать прочитанные вами данные;ты пробовал это?С 64-байтовыми целыми числами вы можете обрабатывать 16-значные номера карт, хотя формат ввода должен быть довольно жестким.Кроме того, вы можете прочитать число в виде строки (это означает, что ваша программа может допускать пунктуацию; я считаю очень утомительным, что веб-сайты не позволяют вводить пробелы или тире, где цифры сгруппированы на вашей реальной кредитной карте).При отладке проблем убедитесь, что входные данные, с которыми фактически работает программа, соответствуют ожидаемым.

Если вы используете 32-битную компиляцию, у вас есть проблемы!

  • Когда ваш код скомпилирован в 64-битном режиме, образец номера кредитной карты идентифицируется как действительный.

  • С вашим кодом, скомпилированным в 32-битный режим, образец номера кредитной карты определяется как недействительный.(Там есть комментарий выше sizeof(long) == 4 на вашем компьютере с вашим компилятором. Либо вы компилируете в 32-битном режиме, либо компилируете в 64-битном режиме на 64-битной платформе Windows. См .: Чторазмер бита long в 64-битной Windows? )

  • Когда я использовал сценарий Perl, написанный десять и более лет назад, образец CCN определяется какдействительный.

  • Когда я распечатал значение, считанное scanf() в 32-битном режиме (модифицированная версия вашей программы), я получил:

    $ ./ccn <<< 4388576018410707
    Enter credit card number Invalid card number -0000000089805613
    $
    

    Используется особая bash функция для подачи строки (числа) в качестве стандартного ввода в программу.

Уроки, которые нужно убрать

  1. Знайте, что ваш компьютер может обрабатывать с помощью чисел.

  2. Проверьте возвращаемое значение из scanf().

  3. Однако,даже это не поможет вам с переполнением.Лучше прочитать строку текста в строку, а затем использовать strtol() или родственника для проверки преобразования.С осторожностью вы можете обнаружить переполнения и недополнения, а также недопустимые значения и т. Д. И вы можете сообщить, что пользователь ввел обратно им, в то время как при неудачном преобразовании чисел (или фиктивном преобразовании чисел) вы не можете сообщить, что увидела программа..

  4. Распечатайте введенные данные.Если вы увидели отрицательное число в выводе при вводе положительного числа, вы бы сразу узнали, почему возникают проблемы.

  5. Если бы это была моя программа, это была бы обработка командной строкиаргументы вместо запроса ввода.


Пример Perl:

$ perl -MBRPS -e 'my($x, $y) = validate_account("4388-5760-1841-0708"); print "$x : $y\n";'
 : check digit on account number is incorrect
$ perl -MBRPS -e 'my($x, $y) = validate_account("4388-5760-1841-0707"); print "$x : $y\n";'
4388576018410707 : ok
$ perl -MBRPS -e 'my($x, $y) = validate_account("4388576018410707"); print "$x : $y\n";'
4388576018410707 : ok
$ perl -MBRPS -e 'my($x, $y) = validate_account("4388 5760 1841 0707"); print "$x : $y\n";'
4388576018410707 : ok
$ perl -MBRPS -e 'my($x, $y) = validate_account("4388 57601841 0707"); print "$x : $y\n";'
 : invalid punctuation pattern
$

Различает формат представления, удобный для пользователя и допускающий пробелы илитире для разделения групп цифр и внутреннего операционного формата - строки цифр, которую могут обрабатывать компьютеры.Люди должны , а не печатать 16-значные числа без знаков препинания;это совершенно нецивилизованно (при этом каждый сайт, с которым я сталкивался, настаивает на отсутствии знаков препинания).Вы можете написать функцию достаточно легко для форматирования 16-значного числа с перерывами.

Вышеприведенная функция не предназначена для представления данных пользователю - она ​​действительно определяет, в чем проблема, но программист долженрешить, как обрабатывать ошибки.

1 голос
/ 08 февраля 2012

Поскольку длина составляет всего 4 байта, он может хранить только до 2,147,483,648.

Вам нужно хранить 4 388 576 018 410 707, которые явно не подходят. Используйте 64-битное int как uint64_t.

0 голосов
/ 24 февраля 2016

Вы можете использовать int long long. Способен содержать по крайней мере диапазон [−9223372036854775807, +9223372036854775807]

Согласно стандарту C99 , long long - это целочисленный тип, ширина которого не менее 64 бит. Указаны два целочисленных 64-битных типа: long long int и unsigned long long int

...