【问题标题】:Returning the function itself as a return value将函数本身作为返回值返回
【发布时间】:2018-02-05 14:16:36
【问题描述】:

我有一个关于返回函数本身的值的简单问题。当然,函数是递归的。 例如:

int CountDigs(int n)
{
  int dig=n%10;
  if(n < 10) return 0;
  if( (n/10)%10 > dig )
    return CountDigs(n/10)+1;
  return CountDigs(n/10);
}

我通常返回一个数字或一个变量,所以这是我第一次看到这个。有人可以请解释“+1”的值存储在内存中的位置,为什么我不应该创建一个存储摘要的变量?

更具体地说,我为相同的解决方案而疯狂:

int counting_function(int n)
{
    int sum;
    if (n>=9)
    return 0;
    sum = counting_function (n/10);
    if (n%10 < n/10%10)
    {
        sum++;
        return sum;
    }
    return sum;
}

【问题讨论】:

  • 您的函数不会返回自身。它返回调用自身的结果,或与之相关的值。这是完全不同的事情。
  • 您不是在返回函数,而是在返回函数返回的值。 resultint result = CountDigs(n/10)+1; return result; 相同
  • 您的函数不收敛:counting_function(0); 永远不会完成:0 小于 9,因此函数以 0/10=0 等递归调用。实际上,任何低于 9 的数字永远不会完成,任何超过 8 的数字都会立即完成。
  • 这是重复的吗?
  • @AdrianMaire 哈哈,我没注意到,这是键盘错误。

标签: c recursion


【解决方案1】:

return 语句返回一个值时,该值由表达式指定。该表达式可以是一个简单的表达式,例如常量或变量名,但不一定是这样。它可以是任何合适类型的有效表达式。

有人可以解释一下“+1”的值在内存中的存储位置,

这取决于编译器,但加 1 的结果可能存储在系统内存中。它很可能永远不会离开 CPU。

为什么我不应该创建一个存储摘要的变量?

将结果存储在变量中,然后使用变量名作为return 表达式,本质上并没有错。在某些情况下,这可能更清楚。然而,即便如此,该值可能实际上并未存储到系统内存中。但是,如果 将其存储到系统内存中,那么这将比不存储更多时间。

这里要理解的关键是return 语句指定一个 直接返回,而不是间接返回。在大多数情况下,对于大多数编译器来说,这样的返回值是通过 CPU 寄存器而不是系统内存传递给调用者的,尤其是您表示熟悉的情况。

【讨论】:

  • 我在我的硬件中因为在使用递归调用时使用了“不必要的”变量而受到了 4 分的惩罚。原因是“每次调用函数时,都会为变量分配另一个内存块,可以被刺穿”。
  • @OfekPintok:如果您想找回这 4 个点,请检查汇编程序输出并检查源代码中是否确实发出了这样的临时变量。如果不是,请去找你的老师,告诉你它已经被优化掉了。
  • @OfekPintok,当我说“没有什么 inherently 错误”时,我的意思是无论哪种方式,该函数都会产生相同的结果,并且添加变量并不昂贵。我发现引入变量的版本不如没有引入变量的版本清晰,但我并没有弄错。我无法详细说明应用于你的练习的评分标准,但我会注意到关于分配多余内存的评论反映了可能性,而不是概率。在这种特殊情况下,您的 sum 变量可能只驻留在寄存器中。
【解决方案2】:

return 语句采用 表达式 并将其用作函数的返回值。

表达式可以是单个变量、调用函数的返回值、字面量值,或上述任意组合以及将它们放在一起的任意数量的运算符。

无需将表达式存储在变量中并将该变量传递给return。任何适当类型的表达式都可能在那里。

【讨论】:

    【解决方案3】:

    返回值的去向取决于调用约定。在 x86 中,它们通常放置在寄存器 EAX 中(如果需要更多空间,则放置在 EDX 中)。编译器不需要显式变量命名 - 这些最终被分解为内存地址和寄存器,在这种情况下(再次取决于您的调用约定),数学在一些寄存器中完成,结果被放置在 EAX在弹出调用堆栈时使用。

    【讨论】:

    • 这根本不是问题的答案。它与调用约定无关。顺便说一句,C 语言不知道调用约定。
    • 他引用了返回值在内存中的位置,所以我试图了解他的要求。
    • 其他答案比这个好。您只是在解释大多数编译器对 x86 代码所做的非常特殊的情况。但不是我的反对票。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-02
    • 2011-08-30
    • 2015-11-24
    • 1970-01-01
    • 1970-01-01
    • 2013-07-06
    • 1970-01-01
    相关资源
    最近更新 更多