Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/c/66.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在C中递归期间,数组会发生什么变化?_C_Recursion_Tree_Tree Traversal - Fatal编程技术网

在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

  • 这两种效果一起造成了数组通过引用传递的错觉,即使C只通过值传递指针



    发明数组指针衰减是为了允许根据指针算法定义数组下标运算符:语句
    baz[3]
    被定义为等价于
    *(baz+3)
    。试图向数组中添加3的表达式。但由于数组指针衰减,
    baz
    衰减为一个
    int*
    ,在此基础上定义指针算法,并生成指向数组中第四个元素的指针。然后可以取消对修改后的指针的引用,以获取
    baz[3]

    路径上的值。路径只是一个指针变量,因此,无论进行何种复制,它们都必须引用相同的内存地址。这是一个很长的问题:“是否只是在每次递归调用期间修改的一个全局副本,而pathlen变量会覆盖一些path值,因为pathlen对于每个堆栈帧都是本地的,所以每个堆栈帧都有自己的path本地副本?“。你可能想试着重新措辞一下,因为在某个时候你很难理解你在问什么…@barakmanos我试着尽可能地添加comas。这有帮助吗?我正在处理你在“旁白”中提到的要点。我只是选择不在这里分享它,因为它的代码比较短。你能解释一下我对pathlen变量的作用的怀疑吗?基本上,它是负责给我完整的路径镜头的兄弟节点?