1

我正在使用以下代码完成一个非常简单的编程练习:

    using System;

    namespace Factorial

{
    class MainClass
    {

        static int fives(int x) {

            int r = 0;
            while(x % 5 == 0) {
                r++;
                x /= 5;
            }
            return r;

        }

        static int z(int x) {

            if (x == 1)
                return 0;
            else
                return z (x-1) + fives (x);

        }

        public static void Main (string[] args)
        {
            int testCases = Convert.ToInt32 (Console.ReadLine ());
            int[] xs = new int[testCases];
            for (int i=0; i<testCases; i++)
                xs [i] = Convert.ToInt32 (Console.ReadLine ());
            foreach (int x in xs)
                Console.WriteLine (z (x));
        }
    }
}

小数字似乎可以正常工作,但是示例中的 8735373 会打印“分段错误:11”。这是否意味着由于递归太深而导致内存不足?是什么原因造成的?

(我在 Mac 上的 Mono 2.10.8 中运行 C#。)

PS:如果有人对 excersize 本身感兴趣,这是我的最终解决方案(更加优化)。

4

4 回答 4

4

这看起来像一个未处理的StackOverflowException- 在过度使用递归时很常见。所以......不要过度使用递归。它可能适用于数学和一些非常特定的语言(F# 可能会应付),但 C# ......不是那么多。

看起来像(未验证):

    static int z(int x)
    {
        int accumulator = 0;
        while(x!=1)
        {
            accumulator += fives(x);
            x--;
        }
        return accumulator;
    }

这不会出错 - 它不会递归(尽管fives每次迭代都会调用)。更好的是:做代数找到直接公式。

于 2012-05-29T21:48:25.777 回答
2

当您使用较大的数字时,您的递归步骤会导致 StackOverflowException 并且如果您查看调试器,您将看到发生了多少递归步骤后异常发生。

我认为 Mono 代码以某种方式考虑了 Segmentaiton 故障的 stackoverflow 异常,这可能是它的处理方式。

在此处输入图像描述

如果您愿意,您可以调试它: 如何在没有任何调试器的情况下在 Ubuntu 上调试 Mono 中的分段错误?

于 2012-05-29T21:55:40.587 回答
1

从递归到循环的简单转换似乎解决了这个问题:

    static int z (int x)
    {
        int result = 0;
        for (int i=1; i<=x; i++) {
            result += fives (i);
        }
        return result;
    }
于 2012-05-29T21:51:37.117 回答
1

如果问题是由大量递归引起的,则错误可能是 StackOverflowException。正如前面所说的 golergka,我很确定这是 Mono 故障。当试图到达不应到达的内存地址而对内存管理不善时,就会出现分段错误。这种类型的错误是系统错误......不是 C# 异常。我几乎可以肯定 Mono 不能很好地管理大量的内存。我希望这对你的研究有所帮助。

于 2012-05-29T22:00:04.907 回答