C#If循环条件问题(这不应该是一个无限循环吗?)

C#If循环条件问题(这不应该是一个无限循环吗?),c#,C#,我有这个代码,它想知道控制台上记录了什么 private static int Printer (int j) { for(var i = j; i > 0; i = Printer(i - 1)) { Console.Write(i); } return j; } Printer(2) 很明显,这返回了211,但这为什么不创建一个无限循环呢?因为打印机(anyNumber)总是返回2,因此将i指定为总是>0?我已经开始回答了,所以

我有这个代码,它想知道控制台上记录了什么


private static int Printer (int j)
{
    for(var i = j; i > 0; i = Printer(i - 1))
    {
        Console.Write(i);
    }

    return j;
}

Printer(2)


很明显,这返回了211,但这为什么不创建一个无限循环呢?因为打印机(anyNumber)总是返回2,因此将i指定为总是>0?

我已经开始回答了,所以我想把它贴在这里。也许换一种方式写会有帮助


这是了解调试器的好时机。您可以很容易地一步一步地查看代码中发生了什么(在递归调用期间值是如何变化的,等等)

要说明调用
打印机(2)
时输出
211
的原因:

  • Main()调用打印机(2)
  • i
    初始化为
    2
  • i>0
    true
  • 调用控制台写入(2)
  • i=Printer(i-1)
    被执行(在
    for
    循环中)
  • 调用打印机(1)(从步骤
    4递归调用)
  • i
    初始化为
    1
  • i>0
    true
  • 控制台。调用Write(1)
  • i=Printer(i-1)
    被执行(在
    for
    循环中)
  • 调用打印机(0)(从步骤
    9递归调用)
  • i
    初始化为
    0
  • i>0
    false
  • 0
    返回;堆栈展开到步骤
    9
  • i=0
    分配已完成
  • i>0
    false
  • 返回
    1
    ;堆栈展开到步骤
    4
  • i=1
    分配已完成
  • i>0
    true
  • 控制台。调用Write(1)
  • i=Printer(i-1)
    被执行(在
    for
    循环中)
  • 调用打印机(0)(从步骤
    20递归调用)
  • i=0
    分配已完成
  • i>0
    false
  • 0
    返回;堆栈展开到步骤
    20
  • i=0
    分配已完成
  • i>0
    false
  • 返回
    2
    ;控件从步骤
    0

  • 您可以使用调试器逐步完成代码并自行查看。我建议学习使用调试器。取决于你问谁我刚才说的不是一个好答案。所以,要么我想提供一个更好的解释,要么剩下的答案是我在炫耀……让我们两者都说一点


    我们设置
    i=j
    。我们检查
    i>0

    该检查可以是
    true
    false


    如果这是
    false
    (即
    i
    小于或等于
    0
    ),我们返回
    j
    。这就是我们的退出条件


    否则,我们递归调用带有
    i-1
    的函数,这将是
    j
    的新值

    但是
    j
    的值是多少?第一次运行代码时,
    j
    将有一些价值……让我们称之为
    j₀。那么
    i=j
    意味着
    i=j₀。因此,我们使用
    j调用函数₀-1
    。让我们称之为
    j₁

    只要
    i>0
    继续为
    true
    ,我们就会有
    j₂ = J₁ - 1
    j₃ = J₂ - 1
    等等……一般公式是
    jₙ = Jₙ₋₁ - 1

    请注意,此公式正在减小,因此它最终将导致值小于或等于
    0
    (这是我们的退出条件)。因此,我们知道递归结束了


    因为函数只会在初始值大于
    0
    时执行有趣的操作。从现在起,我们将假设
    j₀
    大于
    0
    (换句话说,代码不输出任何内容,就是这样)

    现在我知道序列结束了,我将翻转命名法。设
    N
    be
    j₀。设
    N-1
    be
    j₁等等。最后一个值是
    N-N
    ,即
    0
    。为什么?因为随着值的减小,
    0
    是第一个不大于
    0
    的值。这是第一个不会产生输出的值。最后一个输出是
    1


    函数返回什么<代码>返回j
    。而
    j
    是函数得到的任何输入,因为
    j
    没有修改。因此,函数返回它得到的任何输入。并输出一些值

    由于我们将通过
    i-1
    ,我们知道它将返回
    i-1
    。因此,
    i
    的值减小。因此,我们知道迭代也结束了。因为递归和迭代都结束了,我们知道代码终止了


    因此,第一次
    i=j
    给出
    i
    N
    。我们检查
    i>0
    。记住,为了便于论证,我们说
    N
    大于
    0
    (否则代码返回,就是这样)

    然后我们用
    i-1
    递归调用函数,我们称之为
    N-1
    。由于函数返回它得到的任何值,它将返回
    N-1
    。然后我们打印该值。然后重复

    到目前为止,我们知道函数的输出遵循以下顺序:

    N
    (some values)
    N-1
    (some values)
    N-2
    (some values)
    ·
    ·
    ·
    
    但是那些
    (一些值)
    看起来怎么样?嗯,同样的。由于序列是递归的,因此序列是分形的(自相似)

    因此,序列结束如下:

    ·
    ·
    ·
    4
    3
    2
    1
    1
    2
    1
    1
    3
    2
    1
    1
    2
    1
    1
    
    通过一些缩进可以更容易理解:

    4
     3
      2
       1
      1
     2
       1
     1
    3
      2
       1
      1
    2
     1
    1
    
    或者一些ASCII艺术:

    ·           ·
    ·           ·
    ·           ·
    4-----------+
    3--------+  |
    2        |  |
    1        |  |
    1        |  |
    2        |  |
    1        |  |
    1--------+  |
    3--------+  |
    2 ----+  |  |
    1     |  |  |
    1 ----+  |  |
    2 ----+  |  |
    1 -+  |  |  |
    1 -+ -+ -+ -+
    
    在这里,我们看到:

  • 当我们用th调用函数时
    ·           ·
    ·           ·
    ·           ·
    4-----------+
    3--------+  |
    2        |  |
    1        |  |
    1        |  |
    2        |  |
    1        |  |
    1--------+  |
    3--------+  |
    2 ----+  |  |
    1     |  |  |
    1 ----+  |  |
    2 ----+  |  |
    1 -+  |  |  |
    1 -+ -+ -+ -+