在递归调用自身的函数中省略“ return”语句

时间:2019-05-06 20:13:25

标签: c recursion

typedef struct s_node {
    int val;
    struct s_node *left_child;
    struct s_node *right_child;
} NODE;

NODE *get_node_by_val(NODE *root, int searched_val) {
    if (root != NULL) {
        if (root->val == searched_val)
            return root;
        else if (root->val > searched_val)
            get_node_by_val(root->left_child, searched_val); /**/
        else if (root->val < searched_val)
            get_node_by_val(root->right_child, searched_val); /**/
    } else
        return root;
}

今天我们正在谈论二进制搜索树。上面的get_node_by_val在这样的树中搜索NODE与给定的val匹配的searched_val。递归。

竞争点是第12和14行,标记为/**/

乍一看,或者至少在我看来,它们都应该在return语句之前。如果没有return语句,我的猜测是确实搜索了子树,但是返回的值没有任何作用。在某个时候,将返回对get_node_by_val的某些调用(NULL或指向匹配节点的指针),并且此值将传递给调用者,但是在向下递归时可能会发生这种情况。调用者必须将该值传递回其调用者,依此类推,一直到第一个调用者。但是,如果没有return语句,则只有返回方的“直接上方”的调用方才能获取该信息。

或者这就是我的猜测。

问题在于此代码已生效(今天早些时候在课堂上发生过,还没有在家里再次尝试过。)

为什么?怎么样?

我没有根据的猜测如下:最深的递归调用(返回的那个)将其返回值放在EAX上。它上面的所有调用都不会返回任何内容-直到第一个调用者返回之前,EAX一直保持不变(不返回任何内容)。 最后,调用者(第一次调用get_nove_by_val的调用者)看到EAX仍包含该最深层调用所处的值,并且还可能是第一个调用可能返回的值,因此一切正常。

那是怎么回事? 这是不好的做法吗?

1 个答案:

答案 0 :(得分:1)

您是正确的,在递归调用return之前缺少get_node_by_val个关键字。在这两种情况下,该函数均不使用return语句退出。由于它不是void函数,因此具有未定义的行为。

代码的行为符合预期,因为用于返回值的寄存器(或适用于系统ABI的其他任何方式)已在递归调用中设置(实际上在最终的递归调用中),并且调用者未修改直到它返回到自己的调用方,并立即执行。这种行为无法得到保证,依靠它当然是非常不好的做法。

您应该配置编译器以发出有用的警告,以避免此类愚蠢的错误:gcc -Wall -Wextra -Werrorclang -Weverything -Werror ...