简体   繁体   English

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

[英]Can somebody please explain this recursive function for me?

#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;
}

As the more experienced will know, this prints the array in reverse. 正如经验丰富的人所知,这会反过来打印阵列。 I don't quite understand how! 我不太明白怎么做!

I need help understanding what reprint(char *a[]) does. 我需要帮助了解reprint(char *a[])作用。 I understand pointer arithmetic to a degree, but from inserting printf s here and there, I've determined that the function increments up to the array end, and then back down to the start, only printing on the way down. 我理解指针算术到一定程度,但是从插入printf到此处,我已经确定函数递增到数组结束,然后回到开始,只在向下打印。 However, I do not understand how it does this; 但是,我不明白它是如何做到的; all I've managed to understand by looking at the actual code is that if *a isn't NULL , then call reprint again, at the next index. 通过查看实际代码我已经设法理解的是,如果*a不是NULL ,则在下一个索引再次调用reprint。

The key to understanding the function's output is that it will print the pointer before recursing, and the actual string after recursing. 理解函数输出的关键是它将在递归之前打印指针,并在递归之后打印实际的字符串。 That's what gives you the impression of going through twice. 这就是给你两次经历的印象。

Maybe this sounds silly, but follow the program execution manually (or use a debugger). 也许这听起来很愚蠢,但可以手动执行程序(或使用调试器)。 Once it enters the reprint function, it will hit a call to itself after the printf("%d ",a); 一旦它进入重新打印功能,它将在printf("%d ",a);之后调用自身printf("%d ",a); so it will first "climb" all the way to the NULL. 所以它将首先“爬”到NULL。 Only then will it encounter the printf("%s ",*a); 只有这样才会遇到printf("%s ",*a); series. 系列。

Modify your program like this, it should help you understand what's going on. 像这样修改您的程序,它应该可以帮助您了解正在发生的事情。

#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;
}

Recursive call to a function leaves a pointer to the remaining part of the function on a stack. 对函数的递归调用会在堆栈上留下指向函数剩余部分的指针。 Yoy may think of it as a list of things to do after the recursive call is complete. 在递归调用完成后,Yoy可能会将其视为要做的事情列表。

Initially this stack may be considered empty. 最初,此堆栈可能被视为空。 After a sequence of calls you get a stack that looks like this: 在一系列调用之后,您将得到一个如下所示的堆栈:

    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");

Now the stack unwinds itself and each string is being output in the correct sequence. 现在堆栈会自行展开,每个字符串都以正确的顺序输出。

Recursion uses the stack. 递归使用堆栈。 Stacks are a datastructure with LIFO behaviour. 堆栈是具有LIFO行为的数据结构。 reprint will be called 6 times before actually printing the word. 在实际打印单词之前,将reprint 6次。

The key to understanding this type of recursion is to know how stacks work. 理解这种类型的递归的关键是知道堆栈是如何工作的。

First: each time reprint() calls itself with (a+1), then a+1 is pushed onto the stack. 第一:每次reprint()用(a + 1)调用自身,然后将+ 1推入堆栈。 This means the called reprint() gets a copy of the char** as an argument. 这意味着被调用的reprint()获取char **的副本作为参数。 The calling reprint's 'a' is not touched. 调用重印的'a'没有被触及。 Like you said, this goes on until the passed char ** is NULL, ie the last element in the array. 就像你说的那样,这一直持续到传递的char **为NULL,即数组中的最后一个元素。 Then the test 'if (*a)' becomes false and reprint will not be called any deeper. 然后测试'if(* a)'变为false并且不再调用再版。

Note at this point, all 5 calls to reprint are 'waiting' for it to return, so none of the printf's after the recursive call to reprint haven't been called yet. 注意,此时,所有5次重新打印调用都在“等待”它返回,因此在重新调用重新打印之后没有调用printf。 Also note that all 5 calls have their own 'a' pointer. 另请注意,所有5个调用都有自己的'a'指针。 This is essential. 这很重要。

Now, since the last call of reprint doesn't call reprint anymore, it will just return. 现在,由于最后一次重印的电话不再打电话给再版,它只会回来。 The second to last reprint, the one which has an 'a' pointing to the string "I", can then continue with the next statement after the call to reprint, which is the printf of "I". 从第二个到最后一次重新打印,具有指向字符串“I”的'a'的那个,然后可以在重新打印的调用之后继续下一个语句,即“I”的printf。 Once this is done, this function also returns. 完成此操作后,此函数也会返回。 The third to last reprint, the one with 'a' pointing to the string "don't" can then also continue and prints "don't", etc... 第三次到最后一次重印,带有'a'指向字符串“不”的那个也可以继续并打印“不要”等等......

while *a != 0 (NULL) a call to reprint is issued with a+1 which means the next place in the char array, until the last element (NULL) is called, the function just gets back to it's return address which is the line: printf("%s ",*a); 而* a!= 0(NULL)对重新打印的调用是以+ 1发出的,这意味着char数组中的下一个位置,直到最后一个元素(NULL)被调用,该函数才会返回到它的返回地址,即行:printf(“%s”,* a); and in this frame *a is "I", then the function finishes execution and goes again to its' back to its' return address the same line, in this activation frame *a is "don't" and so on until the return address is the printf("\\n"); 并且在这个框架中* a是“I”,然后该函数完成执行并再次返回其'返回其'返回地址相同的行,在此激活框架中* a是“不”,依此类推,直到返回address是printf(“\\ n”); line which executes and then finishes main 执行然后完成主要的行

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM