为什么这种递归在 C++ 中有效?

Why does this kind of recursion work in C++?

我制作了一个递归 C++ 程序,如下所示:

using namespace std;
#include <iostream>

bool recursive(int num)
{
    if (num == 6)
    {
        return false;
    }

    else if (num > 6)
    {
        return true;
    }

    else
    {
        if (recursive(num + 1))
        {
            return true;
        }

        else
        {
            return false;
        }
    }
}


int main()
{
    if (recursive(0))
    {
        cout << "Not found!" << endl;
    }

    else
    {
        cout << "Found..." << endl;
    }
}

它有效,我认为这是(大致)最好的方法。

我的朋友做了一个更简单的递归程序,如下所示:

using namespace std;
#include <iostream>

bool recursive(int num)
{
    if (num == 6)
    {
        return false;
    }

    else if (num > 6)
    {
        return true;
    }

    else
    {
        recursive(num + 1);
    }
}


int main()
{
    if (recursive(0))
    {
        cout << "Not found!" << endl;
    }

    else
    {
        cout << "Found..." << endl;
    }
}

他的作品和我的一样,但我不明白为什么会这样。在我看来,他的 else 块中似乎没有返回任何内容,所以我不明白布尔值是如何返回到原始函数调用的。

出于好奇,我在JavaScript做了一个类似的程序:

function recursive(index)
{
    if (index == 6)
    {
        return true;
    }

    else if (index > 6)
    {
        return false;
    }

    else
    {
        recursive(index + 1);
    }
}

if (recursive(0))
{
    console.log("found");
}

else
{
    console.log("not found");
}

但是JavaScript程序不起作用,这让我觉得这是C++特有的。

为什么我朋友的程序可以运行?它是完全有效的,还是未定义的行为?

这是未定义的行为。由于函数被声明为 return 布尔值,它总是 return 一些东西,但不一定是正确的值。

如果您使用 -Wall 标志进行编译,GCC 等编译器会对此类代码发出警告。

为什么有效?答:没有。

else
{
    recursive(num + 1);
}

您朋友的程序缺少 return 语句。

else
{
    return recursive(num + 1);
}

不 return 从非 void 函数获取值会导致未定义的行为。

在这种情况下,碰巧在您测试的计算机上,递归调用的 return 值自动 "returned" 给调用者——也许是因为它恰好在正确的注册。这纯属偶然。你不能依赖它。在不同的机器上,或者不同的编译器,甚至不同的调用,程序也可能 return 其他东西,或者崩溃,或者做任何你能想象到的事情。

在没有 return 语句的情况下结束函数是 C++ 中的未定义行为。我能做的最好的事情就是 推测 发生了什么,我最好的猜测是对 recursive(index + 1) 的调用,是函数 [=15 之前堆栈中的最后一件事=]s,被选为 return 值。因此,在(非标准、不可移植、不建议一般使用)意义上,代码隐式插入了 return 语句。

当然可以!好吧,不是真的。

地球上的每个编译器(也许不是)都会警告您:

clang: control may reach end of non-void function

gcc: control reaches end of non-void function

MVSC: not all control paths return a value

确实 有效,因为您的朋友很幸运没有让这个程序爆炸、内爆或在您的卧室里制造黑洞。未定义行为就是这样:您无法判断您的程序将如何运行。

标准对此是这样说的:

Flowing off the end of a constructor, a destructor, or a function with a cv void return type is equivalent to a return with no operand. Otherwise, flowing off the end of a function other than main (3.6.1) results in undefined behavior.