C语言中for循环后未被显式修改的inputLen变量莫名变为0的原因排查
嘿,我帮你揪出了这个奇怪bug的根源——栈内存越界覆盖!
你的inputLen变量在循环后莫名变为0,核心原因是栈数组越界访问,覆盖了相邻的局部变量inputLen,下面给你详细拆解:
具体问题分析
在credit_test函数里,你声明了一个大小为16的栈数组evenArr[16],而inputLen作为同函数的局部变量,在C语言的栈内存布局中,它和evenArr是连续分配的(刚好在数组的相邻位置)。
看你处理偶数位的循环逻辑:
for(int i = 0; inputLen > i; i++) { int n = i * 2; evenArr[evenIndex] = input[n] * 2; // ... 数字拆分逻辑 if(evenArr[evenIndex] > 9) { // ... 拆分两位数 evenIndex++; // 这里evenIndex额外加1 } evenIndex++; // 每次循环必加1 evenSum += evenArr[i]; }
这里的evenIndex完全没有上限约束:
- 当输入卡号长度是16时,循环会执行16次;
- 每次循环至少让
evenIndex加1,遇到需要拆分的数字(比如5*2=10)时,evenIndex还会额外再加1; - 很快
evenIndex就会超过16(evenArr的最大合法索引是15),此时evenArr[evenIndex]就会访问到栈上数组之外的内存——而这个位置正好是inputLen的存储地址,越界写入的数据直接把inputLen覆盖成了0。
代码里的其他潜在问题
除了这个核心bug,还有几个需要修正的点:
- 字符转数字逻辑错误:你用
input[n] * 2后减96是错的——数字字符的ASCII值是48~57(比如'0'是48),正确转换应该是input[n] - '0'(或减48),先转成数字再做乘法。 - 奇数位循环的越界风险:你写的
for(int i = 0; 16 > i; i++)不管卡号长度是15还是16,都会循环16次,会访问input数组的越界位置。 - Luhn算法索引逻辑搞反:标准Luhn算法是从右往左数偶数位(倒数第2、4、6...位)乘以2,你原来从左往右取第0、2、4...位,会导致校验结果错误。
修复后的代码示例
其实根本不需要用数组存储每一位的计算结果,直接边计算边累加就能避免数组越界问题,同时修正算法逻辑:
#include <stdio.h> #include <cs50.h> #include <string.h> int credit_test(string input); int main(void) { string userInput; bool isInvalid = false; do { userInput = get_string("Number: "); isInvalid = false; int len = strlen(userInput); // 先校验长度是否合法 if(len != 13 && len != 15 && len != 16) { isInvalid = true; continue; } // 校验每个字符是否都是数字 for(int i = 0; i < len; i++) { if(userInput[i] < '0' || userInput[i] > '9') { isInvalid = true; break; } } } while(isInvalid); credit_test(userInput); return 0; } int credit_test(string input) { int inputLen = strlen(input); int evenSum = 0; int oddSum = 0; // 处理Luhn算法的偶数位(从右往左数第2、4、6...位) for (int i = inputLen - 2; i >= 0; i -= 2) { int num = input[i] - '0'; int doubled = num * 2; // 拆分两位数:等价于把十位和个位相加,比如10=1+0=1,即10-9=1 evenSum += (doubled > 9) ? (doubled - 9) : doubled; } // 处理奇数位(从右往左数第1、3、5...位) for (int i = inputLen - 1; i >= 0; i -= 2) { oddSum += input[i] - '0'; } int finalSum = evenSum + oddSum; printf("Final Sum: %i\n", finalSum); // 修正卡种判断逻辑(符合各卡组织的真实规则) if (finalSum % 10 == 0) { if (inputLen == 16 && input[0] == '5' && input[1] >= '1' && input[1] <= '5') { printf("MasterCard\n"); } else if ((inputLen == 13 || inputLen == 16) && input[0] == '4') { printf("Visa\n"); } else if (inputLen == 15 && (input[0] == '3' && (input[1] == '4' || input[1] == '7'))) { printf("Amex\n"); } else { printf("Invalid\n"); } } else { printf("Invalid\n"); } return 0; }
内容的提问来源于stack exchange,提问作者IncognitoSpeedy
相关产品推荐
相关产品推荐

