为何大数值下C语言因数查找程序错误输出2的幂次?
问题根源:整数溢出导致的未定义行为
你的程序出现异常的核心原因不是内存耗尽,而是32位int类型的整数溢出,具体细节拆解如下:
1. 输入值超出int的取值范围
在绝大多数系统中,int是32位有符号整数,它的取值范围是 -2^31 到 2^31-1(也就是 -2147483648 到 2147483647,约2e9)。当你输入1e10或更大的数时,这个值远超出int能容纳的上限,scanf("%d", &inp)会触发整数溢出——这属于C语言中的未定义行为。
溢出后,inp会被赋予一个错误的“绕回”值(通常是输入值对2^32取模后的结果),而这个值大概率是一个2的幂数(比如你看到的2、4、16等)。你的程序实际上是在处理这个错误的小值,而非你输入的大数,自然会输出一堆2的幂因数。
2. 数组分配与输出逻辑的次要问题
你用calloc(inp/4, sizeof(int))分配存储因数的数组,当inp溢出后,inp/4的计算结果完全错误:
- 如果溢出后的
inp是很小的正数,会分配一个极小的数组,可能无法容纳所有因数,导致数组越界(又是未定义行为); - 如果溢出后的
inp是负数,inp/4会被calloc当作无符号数处理,可能分配一个超大数组,但这不是你遇到的核心问题。
另外,你用while(arr[j] != 0)终止输出的逻辑也不可靠:虽然calloc会把数组初始化为0,但如果因数填满数组后覆盖了后续的0,或者数组越界读取到非0值,都会导致输出异常。
修复方案
要处理1e10甚至更大的数,你需要把所有涉及存储大数的变量改成64位整数类型long long,同时调整输入输出格式:
#include <stdio.h> #include <stdlib.h> int main() { long long inp; int size = 0; puts("Enter a number: "); // 使用%lld读取long long类型 scanf("%lld", &inp); // 因数数量最多不超过inp的一半,用inp/2作为数组大小更稳妥 long long *arr = (long long*) calloc(inp/2, sizeof(long long)); if (arr == NULL) { printf("Memory allocation failed!\n"); return 1; } // 循环变量i也要用long long,避免遍历过程中溢出 for(long long i = 2; i <= inp; i++){ if (inp % i == 0){ arr[size] = i; size++; } } // 直接用记录的因数数量size控制输出,比判断arr[j]!=0更可靠 for(int j = 0; j < size; j++){ printf("%lld\n", arr[j]); } free(arr); return 0; }
额外说明:如果要处理更大的数(比如1e18),单纯遍历判断因数的效率会很低,你可以优化算法(比如只遍历到sqrt(inp),同时记录对应的配对因数),但这属于性能优化的范畴了。
内容的提问来源于stack exchange,提问作者vinod-vms
相关产品推荐
相关产品推荐

