我无法理解带有递归的printf的行为

时间:2019-06-23 10:16:54

标签: c recursion

我无法理解为什么我的代码输出是2,2,3,而且当我删除u ++时,它的输出是2,5,5我正在Windows 7上使用带有gcc的code_block

我尝试空运行我的代码,但其输出与我计算的结果不同

int f(int);
int u = 1;

int main()
{
    int n = 3;

    //scanf("%d", &n);

    f(n);

}

int f(int n)
{
    if (n == 0)
    {
        return 2;
    }

    else
        printf("  %d \n", f(n - 1));
    u++;
}

我期望2,1,0可能是我错了,但我不明白为什么输出是2,2,3,而当我删除u ++时,这会给我带来很大的困惑

3 个答案:

答案 0 :(得分:1)

n != 0路径中,您的函数未明确返回值,并且返回的值是不确定的。

我也不清楚为什么n==0时为什么返回2-您对此值不做任何操作,而且似乎是任意的。

考虑一下:

int f( int n )
{
    if( n != 0 )
    {
        n-- ;
        printf( "  %d \n", n );
        n = f( n ) ;        
    }

    return n ;
}

这既简单(没有else块),又具有明确定义的返回值的单出口。

答案 1 :(得分:-2)

通过以下方式进行跟踪:

  1. 您致电f(3)
  2. f(3)调用printf("%d", f(2))-必须在调用f(2)之前评估printf
  3. f(2)调用printf("%d", f(1))-必须在调用f(1)之前评估printf
  4. f(1)调用printf("%d", f(0))-必须在调用f(0)之前评估printf
  5. f(0)返回2
  6. 使用结果printf进行第4步的f(0)调用,结果为2-这是输出中的第一个2
  7. u递增,现在保留2
  8. f(1)退出而没有返回值-您在此处调用了未定义的行为,从现在开始任何都是可能的。可能发生的情况是u++的结果已存储在用于从函数返回值的同一寄存器中。
  9. 使用未定义的printf的结果进行步骤3的f(1)调用。
  10. u++递增,现在为3。
  11. f(2)退出而不返回值。
  12. 使用未定义的printf的结果进行步骤2的f(2)调用。同样,可能发生的情况是u++的结果已存储在用于从函数返回值的同一寄存器中。

这就是为什么在取出u++语句时看到不同的结果的原因。

注意-我说这是基于过去观察到的真实行为的可能解释;但是,未定义行为的关键属性是未定义-它不必保持一致或可重复。每次运行的输出可能会有所不同,而无需重建代码。您看到该输出的原因可能完全不同。关键要解决的是,您的代码中有一个错误(必须在f时不从n > 0返回值)。

问题是,f()会返回什么n > 0??一旦弄清楚了,就为该值添加一个明确的回报。例如,如果f()应该返回n,则您需要类似

int f( int n )
{
  if ( n == 0 )
  {
    return 2;
  }

  /**
   * Don’t really need an "else" here
   */
  printf( " %d\n", f( n - 1 ));
  u++;
  return n;
}

您还需要添加一个检查,以确保n不小于0,否则您的代码将递归直到您碰到INT_MIN并下溢,然后猜测行为在带符号整数下溢(和溢出)上也未定义。

答案 2 :(得分:-3)

这是解决方案:

int f(int);
int main() {
    int n;
    scanf("%d", &n);
    f(n);
}

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

您应该避免使用全局变量,并且不需要变量u。