CS50x PSET01 Credit程序无法输出VISA/MASTERCARD/AMEX求助
CS50x PSET1 Credit作业问题排查
问题描述
运行CS50x PSET1的Credit程序时,输入合法卡号会重复提示“Card no: ”,输入无效卡号能正确输出“INVALID”,但无法识别并输出VISA、MASTERCARD、AMEX卡种。以下是代码及编译警告信息:
代码
#include <stdio.h> #include "cs50.h" int main(void) { long card; do { card = get_long("Card no: "); } while (card < 0); // Card number must be greater than 0. int card1, card2, card3, card4, card5, card6, card7, card8; card1 = ((card % 100) / 10) * 2; card2 = ((card % 10000) / 1000 * 2); card3 = ((card % 1000000) / 100000 * 2); card4 = ((card % 100000000) / 10000000 * 2); card5 = ((card % 10000000000) / 1000000000 * 2); card6 = ((card % 1000000000000) / 100000000000 * 2); card7 = ((card % 100000000000000) / 10000000000000 * 2); card8 = ((card % 10000000000000000) / 1000000000000000 * 2); card1 = (card1 % 100 / 10) + (card1 % 10); card2 = (card1 % 100 / 10) + (card2 % 10); card3 = (card1 % 100 / 10) + (card3 % 10); card4 = (card1 % 100 / 10) + (card4 % 10); card5 = (card1 % 100 / 10) + (card5 % 10); card6 = (card1 % 100 / 10) + (card6 % 10); card7 = (card1 % 100 / 10) + (card7 % 10); card8 = (card1 % 100 / 10) + (card8 % 10); int sum1 = card1 + card2 + card3 + card4 + card5 + card6 + card7 + card8; // Now we need to find the digits that are not multiplied by 2. int card9, card10, card11, card12, card13, card14, card15, card16; card9 = (card % 10); card10 = ((card % 1000) / 100); card11 = ((card % 100000) / 10000); card12 = ((card % 10000000) / 1000000); card13 = ((card % 1000000000) / 100000000); card14 = ((card % 100000000000) / 10000000000); card15 = ((card % 10000000000000) / 1000000000000); card16 = ((card % 1000000000000000) / 100000000000000); int sum2 = card9 + card10 + card11 + card12 + card13 + card14 + card15 + card16; int sum3 = sum1 + sum2; int length = 0; long visa = card; long master = card; long amex = card; if ((sum3 % 10) != 0) { printf("%s\n", "INVALID"); return 0; } // Now we need to differentiate between VISA, Master and Amex. while (card > 0) { card = card / 10; length++; } // Identify if the card is VISA. while (visa >= 10) { visa /= 10; } if (visa == 4 && (length == 13 || length == 16)) { printf("%s\n ", "VISA"); return 0; } // Identify if the card is AMEX while (amex >= 10000000000000) { amex /= 10000000000000; } if (length == 15 && (amex == 34 || amex == 37)) { printf("%s\n", "AMEX"); return 0; } // Identify if the card is MASTER while (master >= 100000000000000) { master /= 100000000000000; } if (length == 16 && (master == 51 || master == 52 || master == 53 || master == 54 || master == 55 || master == 56)) { printf("%s\n", "MASTERCARD"); return 0; } else printf("%s\n", "INVALID"); return 0; }
编译警告信息
credit.c: In function 'main': credit.c:17:13: warning: conversion to 'int' from 'long long int' may alter its value [-Wconversion] card5 = ((card % 10000000000) / 1000000000 * 2); ^ credit.c:18:13: warning: conversion to 'int' from 'long long int' may alter its value [-Wconversion] card6 = ((card % 1000000000000) / 100000000000 * 2); ^ credit.c:19:13: warning: conversion to 'int' from 'long long int' may alter its value [-Wconversion] card7 = ((card % 100000000000000) / 10000000000000 * 2); ^ credit.c:20:13: warning: conversion to 'int' from 'long long int' may alter its value [-Wconversion] card8 = ((card % 10000000000000000) / 1000000000000000 * 2); ^ credit.c:41:14: warning: conversion to 'int' from 'long long int' may alter its value [-Wconversion] card14 = ((card % 100000000000) / 10000000000); ^ credit.c:42:14: warning: conversion to 'int' from 'long long int' may alter its value [-Wconversion] card15 = ((card % 10000000000000) / 1000000000000); ^ credit.c:43:14: warning: conversion to 'int' from 'long long int' may alter its value [-Wconversion] card16 = ((card % 1000000000000000) / 100000000000000); ^ credit.c:77:17: warning: comparison is always false due to limited range of data type [-Wtype-limits] while (amex >= 10000000000000) ^~ credit.c:79:17: warning: conversion to 'long int' from 'long long int' may alter its value [-Wconversion] amex /= 10000000000000; ^~~~~~~~~~~~~~ credit.c:88:19: warning: comparison is always false due to limited range of data type [-Wtype-limits] while (master >= 100000000000000) ^~ credit.c:90:19: warning: conversion to 'long int' from 'long long int' may alter its value [-Wconversion] master /= 100000000000000; ^~~~~~~~~~~~~~~
问题分析与修复
1. 变量类型溢出导致重复提示
card被定义为long类型,但get_long()返回的是long long。信用卡号(13-16位)远超过32位long的最大值(2147483647,仅10位),赋值后card会变成负数,触发do-while循环的card < 0条件,导致重复提示输入。
- 修复:将
card、visa、master、amex全部改为long long类型,避免数值溢出。
2. Luhn校验计算错误
计算sum1时,card2到card8的拆分逻辑错误,错误使用了card1的十位数字而非自身的十位数字,导致sum1计算结果错误,合法卡号也会因Luhn校验不通过被判定为无效。
- 修复:每个变量拆分自身的十位和个位相加:
card1 = (card1 / 10) + (card1 % 10); card2 = (card2 / 10) + (card2 % 10); card3 = (card3 / 10) + (card3 % 10); // 以此类推card4到card8
3. 卡种识别逻辑失效
- AMEX和MASTERCARD的循环条件永远为假:
amex是long类型,而10000000000000(10^13)超过了32位long的最大值,导致循环无法执行,无法提取正确前缀。 - 计算卡号长度时修改了原始
card变量,导致后续提取前缀时使用的是已修改后的值。 - 修复:
- 计算卡号长度时使用临时变量,保留原始
card值:long long temp = card; while (temp > 0) { temp /= 10; length++; } - 通过统一方式提取前缀,避免大数字比较:
// 提取前两位数字 long long prefix = card; while (prefix >= 100) { prefix /= 10; } int first_two = prefix; int first_one = prefix / 10; - 根据长度和前缀判断卡种:
// VISA判断 if ((length == 13 || length == 16) && first_one == 4) { printf("VISA\n"); return 0; } // AMEX判断 if (length == 15 && (first_two == 34 || first_two == 37)) { printf("AMEX\n"); return 0; } // MASTERCARD判断(有效前缀为51-55) if (length == 16 && first_two >= 51 && first_two <= 55) { printf("MASTERCARD\n"); return 0; }
- 计算卡号长度时使用临时变量,保留原始
4. 其他小问题
- MASTERCARD前缀范围错误:代码中包含了56,实际有效前缀是51-55,需修正。
- VISA输出多了空格:
printf("%s\n ", "VISA");改为printf("VISA\n");。
内容的提问来源于stack exchange,提问作者Abdul Raffay
相关产品推荐
相关产品推荐

