指针分割错误

时间:2012-05-14 01:41:07

标签: c++ segmentation-fault parameter-passing

我的代码在这里遇到了一个非常奇怪的问题。当我使用手动打印语句输出int * primesArr的值时它(貌似)起作用,但如果我尝试使用for循环它会失败。我通过gdb运行它,发现它在我将数组中的下一个单元格设置为值'k'的地方崩溃,这只发生在数字为素数时。第一次迭代成功(即2设置为primesArr [0]),然后程序Segfaults尝试递增数组。但这只在使用for循环时才会发生。当我创建单独的打印语句时,我的程序按预期工作。我不确定如何/为什么我在访问使用for-loop时未被占用的内存。我确定我在某个地方犯了一些业余错误,这可能与我如何通过我的指针有关...但我无法确定它的确切根。我很感激任何帮助,并提前感谢你。

#include<stdio.h>

int genPrimes(int seed, int *test){
    int inNumPrimes=0;
    for(int k=0; k<=seed; k++){//k is number being checked for primeness
        int cnt=0;
        for(int i=1; i<=k; i++){//'i' is num 'k' is divided by
            if(k%i == 0){
                cnt++;
                if(cnt > 2){
                    break;
                }
                }else{
            }

        }
        if(cnt == 2){
            printf("%i IS PRIME\n",k);
            *test=k;
            test++;//according to gdb, the problem is somewhere between here
            inNumPrimes++;//and here. I'd wager I messed up my pointer somehow
        }
        //printf("%i\n",k);
    }
    return inNumPrimes;
}

int main(){
    int outNumPrimes=0;
    int *primesArr;
    int n = 0;
    n=20;

    outNumPrimes=genPrimes(n, primesArr);
    printf("Congratulations!  There are %i Prime Numbers.\n",outNumPrimes);

    //If you print using this for loop, the SEGFAULT occurs.  Note that it does not matter how high the limit is; its been set to many values other than 5. It will eventually be set to 'outNumPrimes'
    //for(int a=0; a<5; a++){
    //printf("%i\n",primesArr[a]);
    //}

    //If you print the array elements individually, the correct value--a prime number--is printed.  No SEGFAULT.
    printf("%i\n",primesArr[0]);
    printf("%i\n",primesArr[1]);
    printf("%i\n",primesArr[2]);
    printf("%i\n",primesArr[3]);
    printf("%i\n",primesArr[4]);
    printf("%i\n",primesArr[5]);
    printf("%i\n",primesArr[6]);
    printf("%i\n",primesArr[7]);
    //
    return 0;
}

使用手动报表输出:

$ ./a.out 
2 IS PRIME
3 IS PRIME
5 IS PRIME
7 IS PRIME
11 IS PRIME
13 IS PRIME
17 IS PRIME
19 IS PRIME
Congratulations!  There are 8 Prime Numbers.
2
3
5
7
11
13
17
19

现在使用for循环:

$ ./a.out 
2 IS PRIME
Segmentation fault

3 个答案:

答案 0 :(得分:6)

您正在将未初始化的指针传递到primes函数中。你得到的行为是不确定的,这就是为什么这看起来如此神秘。变量primesArr可以指向任何地方。

对于像这样的简单案例,使用std::vector<int>

可能更好

答案 1 :(得分:5)

该行

int *primesArr;

primesArr声明为指针变量,但不为其分配任何内存。由于genPrimes()函数希望将其视为将填充素数的空数组,因此您可以在调用main()之前在genPrimes()中分配内存:

int primesArr[MAX_PRIMES];

int *primesArr = malloc(MAX_PRIMES * sizeof(int));

但是,在这两种情况下,您必须保证MAX_PRIMES足够大以容纳genPrimes()找到的所有素数,否则代码将像现在一样生成错误。


其他提示:

1:复杂性

cnt唯一必要的原因是k可以被1k整除。如果你改变了

for (int i=1; i<=k; i++) {  // 'i' is the number 'k' is divided by

for (int i=2; i<k; ++i) {  // 'i' is the number 'k' is divided by

然后这两个案例都被删除了,一旦找到i的{​​{1}}值,循环就会退出。

2:效率

测试

k%i == 0
由于两个原因,

效率仍然很低。首先,没有必要测试每个偶数;如果for (int i=2; i<k; ++i) { // 'i' is the number 'k' is divided by k > 2,则(k % 2) == 0不能成为素数。所以你可以通过明确检查2(素数)或2(非素数)的可分性来消除一半的测试,然后使用

k

但是你可以提高 的效率,因为你可以在到达for (int i = 3; i < k; i += 2) { // 'i' is the number 'k' is divided by 后停止。为什么?如果sqrt(k)可以被某个数字k整除,那么它也必须可以被i整除(因为k/i = i * k/i)。如果k,则i > sqrt(k)和循环已经退出。所以你只需要

k/i < sqrt(k)

如果int r = (int) sqrt(k); for (int i = 3; i <= r; i += 2) { // 'i' is the number 'k' is divided by 不可用,您可以使用

sqrt()

3:风格

只是一件简单的事情,而不是

for (int i = 3;  i*i <= k;  i += 2) {  // 'i' is the number 'k' is divided by

你可以简单地写

int n = 0;
n=20;

答案 2 :(得分:1)

您的primesArr变量未初始化。

将指针声明为

int *ptr;

只需声明一个指向int的指针。但是,指针本身并不指向任何东西。很像宣布

int val;

没有初始化val。因此,您需要为primesArr指针分配内存以指向(使用new或在堆栈上int primesArr[N],其中N是一个大数字。

但是,既然你不知道从genPrimes函数中获得多少素数,并且你没有说过STL是不可能的,我会考虑使用std::vector<int>作为genPrimes功能的输入:

int genPrimes(int seed, std::vector<int>& test)

而且,在函数中,你可以这样做:

test.push_back(k)