在下面的代码中,我尝试在二叉树中打印从根到叶的所有路径。 如果我写一个递归函数如下:
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 变量是否会覆盖一些路径值,让人感觉每个堆栈帧都有它&#39 ; 路径的本地副本,因为 pathlen 是每个堆栈帧的本地副本吗?
答案 0 :(得分:2)
传递int[]
变量几乎就像传递int*
一样。第一次调用递归函数会传递真实的int[]
,它只不过是内存中的一个地址,它与每个递归调用中使用的地址相同。
基本上,如果您放置调试打印,例如
printf("%p\n", path);
在你的递归函数中,你会看到地址总是相同的,它不会改变也不会被修改。在调用期间唯一被推入堆栈帧的是数组的地址,但仍然保持不变。
答案 1 :(得分:2)
欢迎使用array-pointer-decay。当你传递一个数组时,会发生两件不同的事情:
当您声明一个函数来获取一个数组参数时,您实际上是在定义一个带有指针参数的函数。 I. e。,声明
void foo(int bar[]);
完全等同于
void foo(int* bar);
数组的声明已经衰减为指向其第一个元素的指针。
每当你使用一个数组时,它也会衰变成指向它的第一个元素的指针,所以代码
int baz[7];
foo(baz);
再次完全等同于
int baz[7];
foo(&baz[0]);
只有两个异常,其中不会发生此数组指针衰减:语句sizeof(baz)
和&baz
。
这两个效果一起产生了数组通过引用传递的错觉,即使C只是按值传递指针。
发明了数组指针衰减,允许根据指针算法定义数组下标运算符:语句baz[3]
被定义为等同于*(baz + 3)
。尝试将3添加到数组的表达式。但由于数组指针衰减,baz
衰减为int*
,定义了指针算术,并产生指向数组中第四个元素的指针。然后可以取消引用修改后的指针以获得baz[3]
的值。
答案 2 :(得分:1)
void printPath(BinaryTreeNode * n, int path[],int pathlen);
编译器真的像这样看
void printPath(BinaryTreeNode * n, int *path, int pathlen);
路径数组会发生什么?是否只是在每次递归调用期间修改的一个全局副本
无。传递相同的path
,因为在C数组中传递只是一个指针复制操作;不,它不是一个全局副本,而是一个传递给函数第一次调用的参数,几乎总是存在于堆栈中。
并且pathlen变量会覆盖一些路径值,让人觉得每个堆栈帧都有自己的路径本地副本,因为pathlen是每个堆栈帧的本地副本吗?
由于您修改了数组元素的值而不是指向数组开头的指针,因此path
本身指向的内容(始终是数组)没有任何变化。就像你说的那样它可能给人一种感觉(特别是如果你已经习惯了其他语言的构造),但实际上只有相同的路径被传递。
旁白:您似乎无法处理退出条件,因为当您开始修改外部元素时,它似乎是一个无限循环,并且可能是未定义的行为数组的界限。