【问题标题】:Why does this recursive code throw a segfault?为什么这个递归代码会引发段错误?
【发布时间】:2016-02-03 20:00:57
【问题描述】:

当我运行以下使用gcc 编译的代码(打开的唯一选项是-std=c99)并运行可执行文件时,我得到一个分段错误(msg 核心转储)。

这是为什么呢?

#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;
}

【问题讨论】:

  • 因为在count_factors 中你永远无法摆脱递归。把printf("%d %d\n", n, i);放在count_factors开头就明白了。
  • 哦,讽刺的是,在一个名为“StackOverflow”的网站上。
  • 编译时应始终启用警告,例如-Wall。请注意,这是一般建议,可能无助于解决您的特定问题。
  • 当然,通过琐碎的调试无法检测到失控的递归...... :((
  • 嗨,我想检测像这样的无限递归错误属于停止问题,所以编译器不可能检测到它?还是我夸大了?

标签: c recursion segmentation-fault


【解决方案1】:

在您的递归中,您正在考虑一种基本情况。但是,有两个:

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

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

当你再次递归时,你有m=1n=2。这将遇到else 子句,在该子句中您再次使用m=1n=3 调用count_factors。这种情况一直持续到堆栈爆炸为止。

添加第二个基本情况将修复无限递归:

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 秒。

【讨论】:

    猜你喜欢
    • 2016-07-10
    • 1970-01-01
    • 1970-01-01
    • 2022-01-25
    • 2017-04-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-08-02
    相关资源
    最近更新 更多