解决一个简单的问题,但由于程序正在写入数组的末尾而导致分段错误。
#include <iostream>
#include <stdio.h>
static const int N = 46350;
int main()
{
int* intarray = new int[N];
for (int i = 2; i < N; ++i)
{
intarray[i] = 1;
}
for (int i = 2; i < N; ++i)
{
if (intarray[i])
{
for (int j = i; j*i < N; ++j)
{
printf("before i: %i j: %i ", i, j);
std::cout << "a: " << intarray + i*j << std::endl;
intarray[i*j] = 0;
printf("after i: %i j: %i ", i, j);
std::cout << "a: " << intarray + i*j << std::endl;
}
}
}
delete [] intarray;
return 0;
}
控制台输出:
before i: 211 j: 219 array: 0x21dd24c
after i: 211 j: 219 array: 0x21dd24c
before i: 46349 j: 46349 array: 0x2488aec
对于N = 46349,这不会发生。不确定发生了什么。
答案 0 :(得分:3)
整数溢出导致了这种情况。 i
和j
的乘积溢出了int
类型的范围并产生负值,显然比较为“小于N
”。稍后您尝试修改该负索引i * j
的内存,这会导致不可预测的结果。实际上,溢出本身已经产生了未定义的行为。
对于N
的此值,您可以使用unsigned int
类型而不是int
类型来逃避。前者的正范围大两倍。但在一般情况下,您必须记住,两个int
值的乘积不一定符合int
类型的范围。
在您的情况下i
可以变得与46349
和46349 * 46349 = 2148322500一样大,这大于有符号2的补码32位整数2147483647的典型上限。
N = 463549的版本正式也以同样的方式被打破,除了你幸运的是那个版本。 if (intarray[i])
检查可防止内循环在导致溢出的情况下运行。
答案 1 :(得分:0)
您的案例中的最大整数(int
)为2^31-1
,即2147483647
。该数字的平方根为46340.95...
因此,当您乘以i * j
时,您会得到一个整数溢出,结果看起来是负数,它看起来是< N
并且在循环中被允许通过。所以你得到了一个错误。实际上,任何高于46340
的东西都会出现问题。