为什么递归函数调用需要将值返回给调用函数?

问题描述 投票:0回答:4

在以下递归函数中,

int subtractByOne(int num) {
    printf("%d\n", num);
    if (num == 0)
        return 0;
    return subtractByOne(num - 1);
}

为什么最终的回归是必要的?根据我的理解,基本情况将始终停止递归,并且当控制到达函数的末尾时(在递归调用之后),函数将控制转移给任何调用它而不返回。

我对堆栈帧和返回地址的了解很少,但堆栈应该接收一个独立于实际返回关键字的返回地址,不是吗?

Visual Studio 2015会发出有关控制路径的警告,我理解这一点。但是,在编程课程中,平地机的IDE不会编译类似的代码,教授评论代码是不正确的,而不是只是不好的做法。我当时修复了代码,但从未理解为什么它不正确。

c visual-studio recursion return
4个回答
6
投票

函数定义表示它将返回一个整数。如果不放置最后一个返回,则只有基本情况将返回值0并将控制转移到前一个(调用者)函数,但不会发生其他返回。

在这种情况下,您可能不需要返回值,因此您可以在函数定义中使用void作为return,并完全取消所有返回,但在许多情况下,您将需要返回。一个这样简单的例子是计算1 ... n整数的总和如下:

int sum(int n)
{
   if(n==0)
       return 0;
   return n + sum(n-1);
}

2
投票

在你的例子中它会工作正常。但是,如果函数声明声明函数应该返回值并且return语句是有条件的,编译器将会并且应该警告您。编译器不知道它会起作用。但是,如果编译器抛出错误,那听起来很奇怪。

返回语句根本不是为了实现递归所必需的。这是一个例子。

void printNumbers(int a)
{
    if(a > 0) {
        printf("%d\n", a);
        printNumbers(a-1);
    }
}

int main()
{
    printNumbers(10);
}

0
投票

为什么最终的回归是必要的?根据我的理解,基本情况将始终停止递归,并且当控制到达函数的末尾时(在递归调用之后),函数将控制转移给任何调用它而不返回。

你设计subtractByOne来返回int(这是它的签名),然后你必须在每次调用时返回int类型的值。

我对堆栈帧和返回地址的了解很少,但堆栈应该接收一个独立于实际返回关键字的返回地址,不是吗?

是的,返回地址是代表您“自动”管理的,这就是为什么显式使用return不需要返回调用者,规则就是如果您只是让指令流到达功能块的末尾然后返回发出呼叫者。 return关键字用于从另一个点返回或将值发回给调用者。

实践。我当时修复了代码,但从未理解为什么它不正确。

如果您没有向我们展示错误的代码,那么我们无法解释原因。

现在,

int subtractByOne(int num) {
    printf("%d\n", num);
    if (num == 0)
        return 0;
    return subtractByOne(num - 1);
}

虽然正确不是很有用,因为任何具有正值的调用都会得到0作为回报。


0
投票

为什么递归函数调用需要将值返回给调用函数?

简短回答:递归函数不必返回值

所有函数 - 递归或不递归 - 都有一个或多个returnreturn可能包含也可能不包含值。您可以决定何时编写该功能。所有明确编写的return语句都必须返回正确的类型。

但是,在函数结束时省略返回是合法的(但不好的做法)。但只有从未使用过返回值。

所以下面的代码是合法的:

int subtractByOne(int num) {
    printf("%d\n", num);
    if (num == 0)
        return 0;
    subtractByOne(num - 1);
}

subtractByOne(42);

但是,下面的代码具有未定义的行为,因为使用了返回值,并且函数在函数末尾没有返回值:

int subtractByOne(int num) {
    printf("%d\n", num);
    if (num == 0)
        return 0;
    subtractByOne(num - 1);
}

int a;
a = subtractByOne(42);  // Undefined behavior !
printf("%d", a);

正如您所看到的,可以以合法的方式使用相同的函数,但也可能导致未定义的行为。因此,即使它是合法的,省略非void函数的return语句也是一个坏主意。换句话说 - 始终在非void函数中包含return语句。

顺便说一句 - 总是使用高警告级别进行编译,以便编译器告诉您是否忘记了返回语句。

你的课程中失败的编译器可能会对此严格,因此警告你,你的代码是坏的(但不是非法的)。

编写函数的更好方法是使其成为void函数:

void subtractByOne(int num) {
    printf("%d\n", num);
    if (num == 0)
        return;
    subtractByOne(num - 1);
}
© www.soinside.com 2019 - 2024. All rights reserved.