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仍包含该最深层调用所处的值,并且还可能是第一个调用可能返回的值,因此一切正常。
那是怎么回事? 这是不好的做法吗?
答案 0 :(得分:1)
您是正确的,在递归调用return
之前缺少get_node_by_val
个关键字。在这两种情况下,该函数均不使用return
语句退出。由于它不是void
函数,因此具有未定义的行为。
代码的行为符合预期,因为用于返回值的寄存器(或适用于系统ABI的其他任何方式)已在递归调用中设置(实际上在最终的递归调用中),并且调用者未修改直到它返回到自己的调用方,并立即执行。这种行为无法得到保证,依靠它当然是非常不好的做法。
您应该配置编译器以发出有用的警告,以避免此类愚蠢的错误:gcc -Wall -Wextra -Werror
,clang -Weverything -Werror
...