2
#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[])。我在一定程度上理解指针算术,但是通过在这里和那里插入printfs,我已经确定该函数递增到数组末尾,然后返回到开头,只在向下的过程中打印。但是,我不明白它是如何做到的;通过查看实际代码,我设法理解的是,如果*a不是NULL,则在下一个索引处再次调用 reprint。

4

5 回答 5

6

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

也许这听起来很傻,但是手动跟踪程序执行(或使用调试器)。一旦它进入 reprint 函数,它会在之后调用它自己,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;
}
于 2012-06-10T10:05:13.853 回答
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");

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

于 2012-06-10T10:12:44.447 回答
1

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

于 2012-06-10T10:08:04.967 回答
1

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

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

注意此时,所有 5 次 reprint 调用都在“等待”它返回,因此在 reprint 递归调用之后没有一个 printf 尚未被调用。另请注意,所有 5 个调用都有自己的“a”指针。这是必不可少的。

现在,由于 reprint 的最后一次调用不再调用 reprint,它只会返回。倒数第二个重印,即具有指向字符串“I”的“a”的重印,然后可以在调用重印之后继续执行下一条语句,即“I”的 printf。完成此操作后,此函数也将返回。倒数第三个重印,带有 'a' 指向字符串“don't”的那个也可以继续并打印“don't”,等等......

于 2012-06-10T10:25:31.437 回答
0

而 *a != 0 (NULL) 使用 a+1 发出对 reprint 的调用,这意味着 char 数组中的下一个位置,直到最后一个元素 (NULL) 被调用,函数才返回它的返回地址,即行: printf("%s",*a); 并且在这个帧中 *a 是“I”,然后函数完成执行并再次回到它的'返回到它的'返回地址同一行,在这个激活帧中 *a 是“不”,依此类推,直到返回地址是 printf("\n"); 执行然后完成 main 的行

于 2012-06-10T10:36:30.097 回答