解释这个递归函数(在C中)

时间:2013-06-14 21:52:33

标签: c recursion

我无法理解这种反向功能是如何工作的。我已经尝试在纸上逐步解决代码所做的事情,但这对我来说没有意义。我对代码所做的最好的(虽然粗略的)解释是:

http://s7.postimg.org/632xhovwr/recursion_confusion.png

#include <stdio.h>
#include <string.h>
#define MAX 1000

void reverse(char s[]);

main()
{
    char str[] = "remotes";

    printf("Before: %s\n",str);
    reverse(str);
    printf("After: %s\n",str);

    system("Pause");
    return 0;
}

void reverse(char s[])
{
    static int i = 0, n;
    char c = s[i];

    if (c != '\0') {
        ++i;
        reverse(s);
        s[n-i] = c;
        --i;
    } 
    else {
        n = i;
    }
}

通常,当递归是代码的最后一步时,我没有使用递归函数的问题,因为你应用递归直到一些终止条件和向后级联。但是当递归调用之前和之后有代码时,会让事情变得更加混乱。

4 个答案:

答案 0 :(得分:5)

您在纸上的分析是正确的 - 诀窍是ni是静态的(每个堆栈帧指的是变量的相同实例),而c分配在堆栈(因此每个堆栈帧都有自己的副本)。

将一些值替换为分析,并使用cc'c''c'''来表示c的不同堆栈帧实例:

// original function call: stack frame 0
c = str[0]
i = 1

 // stack frame 1
 c' = str[1]
 i = 2

  // stack frame 2
  c'' = str[2]
  i = 3

   // stack frame 3
   c''' = str[3]
   i = 4

    // stack frame 4
    n = 4

   // unwinding: stack frame 3
   str[0] = c'''
   i = 3

  // unwinding: stack frame 2
  str[1] = c''
  i = 2

 // unwinding: stack frame 1
 str[2] = c'
 i = 1

// unwinding: stack frame 0 (original function call)
str[3] = c
i = 0

编辑:解决你的评论:不要放弃理解递归!一旦你有一个坚实的句柄并且可以“递归思考”,就可以很容易地编写使你看起来比你聪明的代码(一种非常有用的技能!)。例如,reverse()函数的轻微重构可以创建更小的版本:

void reverse(char s[])
{
    static int i = 0;
    char c = s[i++];
    if (c) {
        reverse(s);
        s[i++] = c;
    }
    i = c ? i : (int)c;
}

所以真的,原作者通过比必要更冗长来帮助你: - )

答案 1 :(得分:2)

您必须考虑i和n是静态变量,这意味着该函数将保持调用值。

以下是这些值的输出:

i: 1/ n: 0
  i: 2/ n: 0
    i: 3/ n: 0
      i: 4/ n: 0
        i: 5/ n: 0
          i: 6/ n: 0
            i: 7/ n: 0

当c变量提示NULL值时,函数会更新n值并开始反转字符串:

            i: 7/ n: 7/ s: semotes
          i: 6/ n: 7/ s: semotes
        i: 5/ n: 7/ s: setotes
      i: 4/ n: 7/ s: setotes
    i: 3/ n: 7/ s: setomes
  i: 2/ n: 7/ s: setomes
i: 1/ n: 7/ s: setomer

答案 2 :(得分:1)

这里我是静态int继续使用递归调用递增,直到s [i] =='\ 0'。另外的s [i]值保存在调用帧中的局部变量'c'中。

当n == i时,反向发生, 当我减少时,局部变量'c'的值被写回

基本上,调用帧中变量“c”的副本会暂时保存这些值。

答案 3 :(得分:0)

为了解释我已经指出三个断点A,B和C的步骤,下表显示了每个阶段的变量。

void reverse(char s[])
{
    static int i = 0, n;
    char c = s[i];
/* A */
    if (c != '\0') {
        ++i;
/* B */
        reverse(s);
/* C */
        s[n-i] = c;
        --i;
/* D */
    } 
    else {
        n = i;
/* E */
    }
}

enter image description here