在C中递归期间,数组会发生什么变化?
在下面的代码中,我尝试在二叉树中打印从根到叶的所有路径。 如果我编写一个递归函数,如下所示:在C中递归期间,数组会发生什么变化?,c,recursion,tree,tree-traversal,C,Recursion,Tree,Tree Traversal,在下面的代码中,我尝试在二叉树中打印从根到叶的所有路径。 如果我编写一个递归函数,如下所示: void printPath(BinaryTreeNode * n, int path[],int pathlen) { //assume base case and initializations taken care of path[pathlen++] = n->data; printPath(root->left,path,p
void printPath(BinaryTreeNode * n, int path[],int pathlen)
{
//assume base case and initializations taken care of
path[pathlen++] = n->data;
printPath(root->left,path,pathlen);
printPath(root->right,path,pathlen);
}
(我特意删除了基本案例和边缘案例处理,以提高可读性)
路径数组会发生什么变化?在每次递归调用过程中,是否只有一个全局副本被修改?pathlen变量是否覆盖了一些path值,使每个堆栈帧都有自己的path本地副本,因为pathlen是每个堆栈帧的本地副本
void printPath(BinaryTreeNode * n, int path[],int pathlen);
编译器实际上是这样看的
void printPath(BinaryTreeNode * n, int *path, int pathlen);
路径数组会发生什么情况?在每次递归调用期间,是否只有一个全局副本被修改
没什么。同样的路径
被传递,因为在C数组中传递只是一个指针复制操作;不,它不是一个全局副本,而是传递给函数第一次调用的参数,并且几乎总是存在于堆栈上
pathlen变量会覆盖一些path值,让人感觉每个堆栈帧都有自己的path本地副本,因为pathlen是每个堆栈帧的本地副本
void printPath(BinaryTreeNode * n, int path[],int pathlen);
由于修改了数组元素的值,而不是指向数组开头的指针,因此不会更改路径
本身所指向的内容(始终是数组)。就像你说的那样,它可能会给人一种感觉(特别是如果你习惯了其他语言中的这种结构),但实际上只有相同的路径被传递
旁白:您似乎没有处理退出条件,目前来看,当您开始修改超出数组边界的元素时,它将是一个无限循环,并且大部分可能是未定义的行为。传递
int[]
变量几乎就像传递int*
变量一样。递归函数的第一次调用传递实int[]
,它只不过是内存中的一个地址,与每次递归调用中使用的地址相同
基本上,如果您放置调试打印,例如
printf("%p\n", path);
在递归函数中,您将看到地址总是相同的,它不会改变,也不会被修改。在调用过程中,唯一推送到堆栈帧上的是数组的地址,尽管如此,它仍然保持不变。欢迎使用数组指针衰减。在传递数组时,会发生两种截然不同的情况:
void foo(int bar[]);
完全等同于
void foo(int* bar);
int baz[7];
foo(&baz[0]);
数组的声明已退化为指向其第一个元素的指针声明int baz[7];
foo(baz);
又完全等同于
void foo(int* bar);
int baz[7];
foo(&baz[0]);
只有两个例外情况不会发生这种数组指针衰减:语句sizeof(baz)
和&baz
发明数组指针衰减是为了允许根据指针算法定义数组下标运算符:语句
baz[3]
被定义为等价于*(baz+3)
。试图向数组中添加3的表达式。但由于数组指针衰减,baz
衰减为一个int*
,在此基础上定义指针算法,并生成指向数组中第四个元素的指针。然后可以取消对修改后的指针的引用,以获取baz[3]
路径上的值。路径只是一个指针变量,因此,无论进行何种复制,它们都必须引用相同的内存地址。这是一个很长的问题:“是否只是在每次递归调用期间修改的一个全局副本,而pathlen变量会覆盖一些path值,因为pathlen对于每个堆栈帧都是本地的,所以每个堆栈帧都有自己的path本地副本?“。你可能想试着重新措辞一下,因为在某个时候你很难理解你在问什么…@barakmanos我试着尽可能地添加comas。这有帮助吗?我正在处理你在“旁白”中提到的要点。我只是选择不在这里分享它,因为它的代码比较短。你能解释一下我对pathlen变量的作用的怀疑吗?基本上,它是负责给我完整的路径镜头的兄弟节点?