【问题标题】:Recursive Reverse Function递归反向函数
【发布时间】:2013-08-07 16:43:33
【问题描述】:

我想知道是否有人可以解释这个小代码 sn-p 的工作原理。

void reverse(char *s)
{
   if(*s)
       reverse(s+1);
   else
       return;

   cout << *s;
}

当您在 main 中调用此函数时,它应该会打印出输入的任何字符串的反面(即 hello 将 cout 为 olleh),但我不明白如何。据我了解, if 语句会增加 s 的值,直到它到达字符串的末尾,同时打印出字符串中的每个值。为什么不只是重新打印字符串。显然我错过了一些东西。 (抱歉顺便说一句,我是 C++ 和递归函数的新手)

【问题讨论】:

  • 尝试通过这个函数手动滚动一个短字符串(“猫”或“狗”会浮现在脑海中)并在纸上记录,一次一步,发生了什么。您可能想先学习指针算法。
  • 您可能会遇到的问题是字符串末尾有一个 \0,因此if 语句有一个退出条件。
  • 仅供参考,您也可以使用 std::reverse
  • @RobertHarvey 我知道存在退出条件。但是,这不只是意味着 *s 指向字符串中的最后一个值吗?其余的值是怎么打印出来的?

标签: c++ function pointers recursion reverse


【解决方案1】:

考虑"hello" 字符串是如何存储在内存中的:假设它的'h' 字符的地址恰好是0xC000。然后字符串的其余部分将按如下方式存储:

0xC000 'h'
0xC001 'e'
0xC002 'l'
0xC003 'l'
0xC004 'o'
0xC005 '\0'

现在考虑reverse的一系列调用:初始调用通过0xC000;从内部调用reverse 传递s+1,所以下一级得到0xC001;下一个得到0xC002,以此类推。

请注意,每个级别都会调用下一个级别,直到看到'\0' 的级别。在我们归零之前,堆栈是这样“加载”的:

reverse(0xC004) // the last invocation before we hit '\0'
reverse(0xC003)
reverse(0xC002)
reverse(0xC001)
reverse(0xC000) // the earliest invocation

现在当顶部调用调用reverse(0xC005) 时,*s 的检查失败,并且函数立即返回而不打印任何内容。此时堆栈开始“展开”,打印其s 参数指向的任何内容:

0xC004 -> prints 'o', then returns to the previous level
0xC003 -> prints 'l', then returns to the previous level
0xC002 -> prints 'l', then returns to the previous level
0xC001 -> prints 'e', then returns to the previous level
0xC000 -> prints 'h', then returns for good.

这就是原始"hello" 字符串的反向打印方式。

【讨论】:

    【解决方案2】:

    尝试可视化调用堆栈的构建方式。每个递归调用都会创建另一个堆栈帧,其中 s 的副本递增 1。当退出条件发生时,堆栈开始展开并为每一帧调用cout 语句。由于后进先出原理,字符串是反向打印的。

    【讨论】:

      【解决方案3】:

      让我们考虑一个长度为 3 的字符串。reverse(i) 是在字符串的第 i 个索引上调用的函数的缩写(从技术上讲,它是 char 指针 + i,但这种解释需要更高级的理解)。

      注意(正如 Robert 指出的)如果s 指向\0(表示字符串的结尾),*s 返回 false 也很有用,因此,在这种情况下,它将简单地返回。

      会发生什么:

      reverse(0)
        calls reverse(1)
          calls reverse(2)
            calls reverse(3)
              end of string - return
            prints 2
          prints 1
        prints 0
      

      【讨论】:

        【解决方案4】:

        让我们看一个简单的例子,假设 s = "the"

        我们会:

        rev(t) ->递增指针

        rev(h)->增量指针

        rev(e) ->递增指针

        rev('\0') (这只会返回)

        然后我们会回到 rev(e) 的主体,它会打印 e

        然后返回 rev(h) 打印 h

        最后回到 rev(t) 打印 t

        按照这个顺序,我们将有:eht(“the”倒序)

        【讨论】:

          【解决方案5】:

          也许把函数写成这样会更清楚:

          void reverse(const char *s)
          {
             if(*s)
             {
               reverse(s+1);
               std::cout << *s;
             }
          }
          

          即每个非空字符将在调用下一个字符后打印(通过调用reverse)

          PD:如果您不修改给定的字符串,请使用“const char*”而不是“char*”。

          【讨论】:

            猜你喜欢
            • 2010-11-28
            • 2020-09-26
            • 2013-05-11
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-06-02
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多