C:信用卡号码检查器/ Luhn 算法
一切看起来都很好,似乎遵循 Luhn 的算法,但是当我输入自己的信用卡号或这个应该有效的样本号时: 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;
}
Everything looks fine and seems to follow Luhn's algorithm, but when i enter my own credit card number or this sample number that should be valid: 4388576018410707 , it still comes back as invalid...
Can anyone find the problem?
#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;
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
首先要做的就是打印你读到的数据;你尝试过吗?使用 64 字节整数,您可以处理 16 位卡号,但输入格式必须相当严格。或者,您可以将数字读取为字符串(这意味着您的程序可以允许可选标点符号;我发现网站不允许您在实际信用卡上的数字分组处键入空格或破折号,这非常令人讨厌)。调试问题时,请检查程序实际使用的输入数据是否与您的预期一致。
如果您使用 32 位编译,就会遇到问题!
如果您的代码以 64 位模式编译,则示例信用卡号将被识别为有效。
如果您的代码是在 32 位模式下编译的,则示例信用卡号会被识别为无效。 (上面有一条注释,
sizeof(long) == 4
在你的机器上使用你的编译器。要么你在 32 位模式下编译,要么你在 Windows 上以 64 位模式编译64 位平台。 href="https://stackoverflow.com/questions/384502/what-is-the-bit-size-of-long-on-64-bit-windows/384672#384672">long
在 64 位 Windows 上?)当我打印出
scanf()
在 32 位模式下(程序的修改版本)读取的值时,我得到:<前><代码>$ ./ccn <<< 4388576018410707
输入信用卡号 无效卡号 -0000000089805613
$
这是使用
bash
特定的功能将字符串(数字)作为标准输入提供给程序。吸取的教训
了解您的计算机可以以数字的方式处理什么。
检查
scanf()
的返回值。但是,即使这样也无法帮助您解决溢出问题。您最好将一行文本读入字符串,然后使用
strtol()
或相关函数来检查转换。小心地,您可以发现溢出和下溢以及无效值等。您可以报告用户输入的内容,而如果数字转换失败(或伪造的数字转换),则无法报告程序看到的内容.打印输入数据。如果您在输入正数时在输出中看到负数,您会立即知道为什么会出现问题。
如果它是我的程序,它将处理命令行参数而不是提示输入。
Perl 示例:
这区分了表示格式(用户友好且允许使用空格或破折号分隔数字组)和内部操作格式(计算机可以处理的数字字符串)。不应该让人们输入不带标点符号的 16 位数字;这是完全不文明的(尽管我遇到的每个网站都坚持不使用标点符号)。您可以轻松编写一个函数来格式化带分隔符的 16 位数字。
上面的函数并不是为了向用户呈现数据——它确实确定了问题所在,但程序员必须决定如何处理错误。
The first thing to do is to print the data you read; did you try that? With 64-byte integers, you can process 16-digit card numbers, though the input format has to be rather rigid. Alternatively, you can read the number as string (which means your program can allow optional punctuation; I find it very irksome that web sites do not allow you to type spaces or dashes where the digits are grouped on your actual credit card). When debugging problems, check that the input data the program is actually working with agrees with what you expect.
If you're using a 32-bit compilation, you have problems!
With your code compiled in 64-bit mode, the sample credit card number is identified as valid.
With your code compiled in 32-bit mode, the sample credit card number is identified as invalid. (There's a comment above that
sizeof(long) == 4
on your machine with your compiler. Either you're compiling in 32-bit mode or you're compiling in 64-bit mode on a Windows 64-bit platform. See: What is the bit size oflong
on 64-bit Windows?)When I used a Perl script I wrote a decade and more ago, the sample CCN is identified as valid.
When I printed out the value read by
scanf()
in the 32-bit mode (a modified version of your program), I got:That's using a
bash
-specific feature to feed the string (number) as standard input to the program.Lessons to take away
Know what your computer can handle in the way of numbers.
Check the return value from
scanf()
.However, even that does not help you with overflow. You would do better to read a line of text into a string and then use
strtol()
or a relative to check the conversion. With care, you can spot overflows and underflows as well as invalid values, etc. And you can report what the user typed back to them, whereas with a failed numeric conversion (or a bogus numeric conversion), you cannot report what the program saw.Print the input data. If you saw a negative number in the output when you typed in a positive one, you'd instantly know why there are problems.
Were it my program, it would be processing command line arguments instead of prompting for input.
Perl example:
This distinguishes between the presentation format, which is user-friendly and allows spaces or dashes to separate the groups of digits, and the internal operational format, the digit string that computers can handle. People should not be made to type 16-digit numbers without punctuation; that is downright uncivilized (for all that every web site I've encountered insists on no punctuation). You can write a function easily enough to format a 16-digit number with the breaks.
The function above is not intended to present data to the user - it does identify what the trouble is, but the programmer has to decide how to handle the errors.
由于long只有4个字节,因此最多只能存储
2,147,483,648
。您需要存储 4,388,576,018,410,707 ,这显然无法容纳。使用 64 位 int,例如
uint64_t
。Since long is only 4 bytes, it can only store up to
2,147,483,648
.You need to store 4,388,576,018,410,707 which obviously can't fit. Use a 64-bit int like
uint64_t
.您可以使用 int
long long
。能够至少包含 [−9223372036854775807, +9223372036854775807] 范围根据 C99 标准,long long是至少 64 位宽的整数类型。指定了两种整数 64 位类型:
long long int
和unsigned long long int
You can use the int
long long
. Capable of containing at least the [−9223372036854775807, +9223372036854775807] rangeAccording to C99 standard, long long is an integer type which is at least 64-bit wide. There are two integer 64-bit types specified:
long long int
andunsigned long long int