为什么这个递归代码抛出一个段错误?

时间:2015-11-03 15:30:43

标签: c recursion segmentation-fault

当我运行以下使用gcc编译的代码(仅打开选项为-std=c99)并运行可执行文件时,我会收到分段错误(msg core dumped)。

为什么?

#include <stdio.h>

int count_factors(int n, int i) {
    int m = n;
    if (m == i) {
        return 1;
    } else if (m % i == 0) {
        while (m % i == 0) m = m / i;
        return 1 + count_factors(m, i);
    } else {
        return count_factors(m, i+1);
    }
}

int main() {

    int streak_size = 4;
    int streak = 0;
    int solution = 0;
    int n = 2;

    while (solution == 0) {
        n += 1;
        int c = count_factors(n, 2);
        if (c == streak_size) {                  
            streak += 1;
        } else {
            streak = 0;
        }
        if (streak == streak_size) solution = n;
    }
    printf("%i", solution);
    return 0;
}

1 个答案:

答案 0 :(得分:2)

在您的递归中,您需要考虑一个基本案例。但是,有两个:

  • m == i:当只有一个最大因素
  • 时会发生这种情况
  • m == 1:当存在多个最大因素
  • 时会发生这种情况

您在m=4n=2上进入无限循环,因为您错过了第二种情况。这里if (m % i == 0)为真,因此while (m % i == 0) m = m / i;运行。由于4是2的倍数,因此当m为1时,此循环将结束。

再次递归时,您有m=1n=2。这将触及else子句,您可以使用count_factorsm=1再次致电n=3。这种情况一直持续到堆栈爆炸为止。

添加第二个基本案例将修复无限递归:

int count_factors(int n, int i) {
    int m = n;
    if (m == i) {
        return 1;
    } else if (m == 1) {
        return 0;
    } else if (m % i == 0) {
        while (m % i == 0) m = m / i;
        return 1 + count_factors(m, i);
    } else {
        return count_factors(m, i+1);
    }
}

实际上,你可以摆脱第一种情况,因为它只是if (m % i == 0)的一个特例:

int count_factors(int n, int i) {
    int m = n;
    if (m == 1) {
        return 0;
    } else if (m % i == 0) {
        while (m % i == 0) m = m / i;
        return 1 + count_factors(m, i);
    } else {
        return count_factors(m, i+1);
    }
}

程序然后运行完成,输出134046。

编辑:

它会在没有递归的情况下运行得更快:

int count_factors(int n, int i) {
    int m = n;
    int total = 0;
    while (m != 1) {
        if (m % i == 0) {
            while (m % i == 0) m = m / i;
            total++;
        }
        i++;
    }
    return total;
}

在我的机器上,递归版本大约需要9秒。迭代版本大约需要3秒钟。