有人可以帮我解释一下这个递归函数吗?

时间:2012-06-10 09:59:39

标签: c arrays pointers printing recursion

#include <stdio.h>
#include <stdlib.h>

void reprint(char *a[]) {
    if(*a) {
            printf("%d ",a);
            reprint(a+1);
            printf("%s ",*a);
    }
}

int main() {
    char *coll[] = {"C", "Objective", "like", "don't", "I", NULL};
    reprint(coll);
    printf("\n");
    return EXIT_SUCCESS;
}

正如经验丰富的人所知,这会反过来打印数组。我不太明白怎么做!

我需要帮助了解reprint(char *a[])的作用。我理解指针算术到一定程度,但是从插入printf这里到那里,我已经确定函数递增到数组结束,然后回到开始,只在打印时向下打印。但是,我不明白它是如何做到的;通过查看实际代码我已经设法理解的是,如果*a不是NULL,那么请在下一个索引再次调用reprint。

5 个答案:

答案 0 :(得分:6)

理解函数输出的关键是它将在递归之前打印指针,并在递归之后打印实际的字符串。这就是给你两次经历的印象。

这可能听起来很愚蠢,但可以手动执行程序(或使用调试器)。一旦它进入重新打印功能,它将在printf("%d ",a);之后对自己进行调用,因此它将首先“爬”到一直到NULL。只有这样才会遇到printf("%s ",*a);系列。

像这样修改您的程序,它应该可以帮助您了解正在发生的事情。

#include <stdio.h>
#include <stdlib.h>

static int callcounter = 1;

void reprint(char *a[]) {
    printf ("Entering reprint for the %d time\n",callcounter++);
    if(*a) {
            printf("%p ",a);
            reprint(a+1);
            printf("%s ",*a);
    }
    printf ("Exiting reprint\n");
}

int main() {
    char *coll[] = {"C", "Objective", "like", "don't", "I", NULL};
    reprint(coll);
    printf("\n");
    return EXIT_SUCCESS;
}

答案 1 :(得分:3)

对函数的递归调用会在堆栈上留下指向函数剩余部分的指针。在递归调用完成后,Yoy可能会将其视为要做的事情列表。

最初,此堆栈可能被视为空。在一系列调用之后,您将获得如下所示的堆栈:

    1st call: reprint ("C", "objective", "like", "don't", "I", NULL);
    2nd call: reprint ("objective", "like", "don't", "I", NULL);printf("C");
    3rd call: reprint ("like", "don't", "I", NULL);printf("objective");
                                                   printf("C"); 
    ...
    6th call: reprint(NULL); printf("I");printf("don't");printf("like");
                             printf("objective");printf("C");

现在堆栈会自行展开,每个字符串都以正确的顺序输出。

答案 2 :(得分:1)

递归使用堆栈。堆栈是具有LIFO行为的数据结构。在实际打印单词之前,reprint将被调用6次。

答案 3 :(得分:1)

理解这种类型的递归的关键是知道堆栈是如何工作的。

首先:每次reprint()用(a + 1)调用自身,然后将+ 1推入堆栈。这意味着被调用的reprint()获取char **的副本作为参数。调用重印的'a'没有被触及。就像你说的那样,这一直持续到传递的char **为NULL,即数组中的最后一个元素。然后,测试'if(* a)'变为false,重印不再被称为更深。

此时请注意,所有5次重新打印调用都在“等待”它返回,因此在重新调用重新打印之后没有调用printf。另请注意,所有5个调用都有自己的'a'指针。这很重要。

现在,由于最后一次再版的电话不再打电话给再版,它只会回来。从第二个到最后一次重新打印,具有指向字符串“I”的'a'的那个,然后可以在重新打印的调用之后继续下一个语句,即“I”的printf。完成此操作后,此函数也会返回。第三次到最后一次重印,带有'a'指向字符串“do not”的那个也可以继续并打印“不要”等等......

答案 4 :(得分:0)

而* a!= 0(NULL) 发出重印的调用是以+ 1发出的,这意味着char数组中的下一个位置, 直到最后一个元素(NULL)被调用, 该函数只返回它的返回地址即行: printf(“%s”,* a); 在这个框架中* a是“我”, 然后该函数完成执行并再次返回其'返回'返回地址相同的行,在此激活帧中* a是“不”,依此类推,直到返回地址为printf(“\ n”); 执行然后完成主

的行