C中的分段错误,可能在中/大型动态分配数组上
注意:我已经查看了其他分段错误公告,与我的问题密切相关的是在堆栈上创建大型数组最终导致溢出。但是,正如您从下面的代码中看到的,我在堆上进行分配,仍然遇到这个问题 我已经使用Valgrind和gdb对此进行了调试,他们告诉我:下面的函数代码中出现了“大小为4…NumberVisors的无效读取”或分段错误。奇怪的是,这适用于49141之前的所有数字,当它循环通过感兴趣的数字时,它将抛出错误或segfault这仅当它处于循环中时。当我输入一个没有循环的大数时,它将报告除数的数量,而不会出错或分段。有人能看到下面代码中的问题吗?谢谢C中的分段错误,可能在中/大型动态分配数组上,c,segmentation-fault,C,Segmentation Fault,注意:我已经查看了其他分段错误公告,与我的问题密切相关的是在堆栈上创建大型数组最终导致溢出。但是,正如您从下面的代码中看到的,我在堆上进行分配,仍然遇到这个问题 我已经使用Valgrind和gdb对此进行了调试,他们告诉我:下面的函数代码中出现了“大小为4…NumberVisors的无效读取”或分段错误。奇怪的是,这适用于49141之前的所有数字,当它循环通过感兴趣的数字时,它将抛出错误或segfault这仅当它处于循环中时。当我输入一个没有循环的大数时,它将报告除数的数量,而不会出错或分段。有
int numberDivisors(int n) {
int lim = (int)floor(sqrt((double)n));
int *primes = (int*)calloc(n, sizeof(int));
int *divisors = (int*)calloc(n, sizeof(int));
int i, j, ctr;
ctr = 0;
if(primes && divisors) {
for(i = 0; i < n; i++) {
primes[i] = 1;
divisors[i] = 0;
}
for(i = 2; i < lim; i++) {
if(primes[i]) {
for(j = i; i * j < n; j++) {
primes[i * j] = 0;
}
}
}
for(i = 2; i < n; i++) {
if(primes[i]) {
if(n % i == 0) divisors[i] = 1;
for(j = i; i * j < n; j++) {
// int result = n % (i * j);
assert(i * j < n); //Added at lsk's request. i * j passes the test.
//if(result == 0) {
if(n % (i * j) == 0) {
if(!divisors[i * j]) {
divisors[i * j] = 1;
}
}
}
}
}
for(i = 2; i < n; i++) {
if(divisors[i]) ctr++;
}
ctr += 2;
} else {
printf("Allocation failed.");
}
free(primes);
free(divisors);
return ctr;
}
int数字查看器(int n){
内部直线=(内部)楼层(sqrt((双)n));
int*素数=(int*)calloc(n,sizeof(int));
int*除数=(int*)calloc(n,sizeof(int));
int i,j,ctr;
ctr=0;
if(素数和除数){
对于(i=0;i
UPDATE我将函数中的所有int都改为unsigned long(只是为了看看它是否可以工作),它现在运行得很好。但是,Umer是对的-我必须重新考虑算法,因为它需要的时间比需要的时间长,但这是另一个问题。感谢社区的帮助!错误事实上是
if(!divisors[i * j]) {
divisors[i * j] = 1;
}
由于整数溢出。请考虑一个简单的例子:
int n = 123123123;
int i = 57641;
int j = 74495;
printf("i = %d\n", i);
printf("j = %d\n", j);
printf("i * j = %d\n", i*j);
printf("i*1.0 * j = %f\n", i*1.0 * j);
printf("n = %d\n", n);
将生成以下输出:
i = 57641
j = 74495
i * j = -1001001
i*1.0 * j = 4293966295.000000
n = 123123123
如您所见,
i*j
是真的,但i*j
是一个负整数。使用负索引索引除数会导致崩溃。错误实际上是
if(!divisors[i * j]) {
divisors[i * j] = 1;
}
由于整数溢出。请考虑一个简单的例子:
int n = 123123123;
int i = 57641;
int j = 74495;
printf("i = %d\n", i);
printf("j = %d\n", j);
printf("i * j = %d\n", i*j);
printf("i*1.0 * j = %f\n", i*1.0 * j);
printf("n = %d\n", n);
将生成以下输出:
i = 57641
j = 74495
i * j = -1001001
i*1.0 * j = 4293966295.000000
n = 123123123
正如您所见,i*j
是真的,但是i*j
是一个负整数。使用负索引索引除数会导致崩溃。哪一行出现问题?我看到的唯一可疑代码是i*j被用作索引,它可能大于分配的大小。您可以添加assert()吗要检查这些条件吗?请添加到您的代码中。每次他使用ij时,它都在一个循环块中,条件ijfor
循环中的条件更改为j
可避免算术溢出(除以i
而不是j
会给优化器留下优化空间。只要除以一个正整数,整数除法就不会溢出。哪一行是问题所在?我看到的唯一可疑代码是i*j被用作索引,它可能大于分配的大小。能否添加assert()要检查这些条件吗?请添加到您的代码中。每次他使用ij时,它都在一个循环块中,条件ijfor
循环中的条件更改为j
可避免算术溢出(除以i
而不是j
会给优化器留下优化的空间。只要除以正整数,整数除法就不会溢出。我完全同意这就是问题所在。在我测试50059的gdb
会话中,我得到:(gdb)p除数
和$1=(int*)0x100034000
(因此除数可以),然后(gdb)pi
和$2=47653`(可以),以及(gdb)pj
和$3=90129
(绝对不可以)我完全同意这就是问题所在。在我测试50059的gdb
会话中,我得到了:(gdb)p除数
和$1=(int*)0x100034000
(因此除数
是可以的),然后(gdb)p i
和$2=47653`(这可能很好),以及(gdb)p j
和$3=90129
(这绝对不好)。在不同的机器上,在不同的n
值下,我得到了不同的碰撞结果。