如何在不使用全局变量的情况下从递归函数中获取结果?

How do I get a result from a recursive function without using a global variable?

我写了一个用递归反转整数(123 变成 321)的函数,我被告知使用全局变量是不好的做法,但我无法弄清楚如何在不使用全局变量的情况下从函数中获取结果使用一个。我尝试在函数内声明变量,但随后得到了不希望的结果。

#include <stdio.h>

int result = 0;

int reverse_num(int num)
{
    int remainder = num % 10;
    
    if (num == 0) return 0;
    
    result *= 10;
    result += remainder;
    
    reverse_num(num / 10);
    
    return result;
}

int main(void)
{
    int num, reversed_num;
    
    printf("Insert number: ");
    scanf("%d", &num);
    
    reversed_num = reverse_num(num);
    
    printf("Inverted number: %d", reversed_num);
    
    return 0;
}

方法有很多种。一种方法涉及在每次递归中找到最重要的十进制数字。

下面是一个低效的例子。

对于从 0 到接近 INT_MAX/10 的某些值工作正常。

#include <stdio.h>

int reverse_num(int num) {
  if (num < 10) {
    return num;
  }
  int pow10 = 10;
  while (num/pow10 >= 10) {
    pow10 *= 10;
  }
  int lead_digit = num/pow10;
  return reverse_num(num % pow10) * 10 + lead_digit;
}

int main() {
  printf("%d\n", reverse_num(123456789));
  printf("%d\n", reverse_num(1));
  printf("%d\n", reverse_num(100));
}

输出

987654321
1
1

对其他人失败 printf("%d\n", reverse_num(123000789)); --> 987321.


改进:递归和高效。

static int reverse_num_helper(int num, int power10) {
  if (power10 < 10) {
    return num;
  }
  return reverse_num_helper(num % power10, power10 / 10) * 10 + num / power10;
}

int reverse_num(int num) {
  int pow10 = 1;
  while (num / pow10 >= 10) {
    pow10 *= 10;
  }
  return reverse_num_helper(num, pow10);
}

int main() {
  printf("%d\n", reverse_num(123000789));
  printf("%d\n", reverse_num(123456789));
  printf("%d\n", reverse_num(123));
  printf("%d\n", reverse_num(1));
  printf("%d\n", reverse_num(100));
}

输出

987000321
987654321
321
1
1
int Reverse(int n,int Len) {
    if (n == 0)
        return 0;
    return std::pow(10, Len-1)*(n % 10) + Reverse(n / 10, Len-1);
}



  //inside main
    Reverse(54321,5);

//Output Should be 12345

要使其与您的原始代码相似,只是没有全局变量,请尝试以下操作:

#include <stdio.h>

#define RESET (-1)

int reverse_num(int num)
{
    static int result = 0;
    int remainder = num % 10;

    if (num < 0) {
        result = 0;
        return 0;
    }
    if (num == 0) return 0;
    result *= 10;
    result += remainder;
    reverse_num(num / 10);
    return result;
}

int main(void)
{
    int num, reversed_num;

    printf("Insert number: ");
    scanf("%d", &num);
    reverse_num(RESET);
    reversed_num = reverse_num(num);
    printf("Inverted number: %d\n", reversed_num);
    return 0;
}

这里,我只是把result变成函数中的一个局部static变量,这意味着即使函数returns它仍然保持它的值(就像一个全局变量,除了它的范围仅在函数内)。问题是,如果你想多次调用它,你需要一种方法来重置 result 值;我通过使用 num 的负值作为要重置的信号量来做到这一点。

@chux 给出的 long-winded 版本可能更清晰一些。

#include <stdio.h>

int count_places(int num);
int reverse_by_places(int num, int num_places);
int ipow(int base, int power);

int reverse_num(int num)
{
    return reverse_by_places(num, count_places(num)) / 10;
}

int ipow(int base, int power)
{
    if (power == 0)
        return 1;
    return base * ipow(base, power-1);
}

int count_places(int num)
{
    int i;
    if (num == 0)
        return 1;

    for (i = 0; num > 0; i++) 
    {
        num /= 10;
    }
    return i;
}


int reverse_by_places(int num, int num_places)
{
    int dividend = num / 10, remainder = num % 10;
    
    if (dividend == 0)
        return remainder * ipow(10, num_places);
    else
        return ((remainder * ipow(10, num_places)) + reverse_by_places(dividend, num_places-1));    
}

int main(void)
{
    int num, reversed_num;
    
    printf("Insert number: ");
    scanf("%d", &num);
    
    reversed_num = reverse_num(num);
    
    printf("Inverted number: %d\n", reversed_num);
    
    return 0;
}

执行此操作的常用方法是 另一个参数 仅用于累加结果。它可以在 C 中通过将您的函数拆分为用户调用的函数和完成所有工作的函数来完成。

int reverse_num_helper(int num, int result)
{
    int remainder = num % 10;
    
    if (num == 0) return result;
    
    result *= 10;
    result += remainder;
    
    return reverse_num_helper(num / 10, result);
}

int reverse_num(int num)
{
    return reverse_num_helper(num, 0);
}

(在 C++ 中,您可以将两者合并为 int reverse_num(int num, int result = 0)。)

注意你的函数本质上没有变化。
我们只做了两个小的修改:

  • num 达到 零时返回 result 而不是零
  • 使用修改后的 result 值调用递归