3

I came across the following question:

#include <stdio.h>

int f(int &x, int c)
{
    c  = c - 1;
    if (c == 0) return 1;
    x = x + 1;
    return f(x, c) * x;
}
int main()
{
    int p = 5;
    printf("%d", f(p, p));
}

As far as I have worked out, the recursion calls should work, and with each recursion call, value of c should reduce by 1 and value of x should increase by 1 . However, if I calculate it that way, the answer comes out to be 3024. However, on executing, the output comes out to be 6561. I am not really sure how this answer is coming.

I have the link to the article from where this question is taken, but I fail to understand how x will remain constant as is described in this link: https://www.geeksforgeeks.org/c-references-question-1/

Can someone help me with the working behind this code?

6
  • Try stepping through with a debugger, or adding output statements (ideone.com/uoO3Ak) to watch the value of c and x each recursive function call. Commented Jun 29, 2021 at 11:31
  • 4
    Wouldn't the return value depend on whether f(x, c) or x gets evaluated first in return f(x, c) * x? Commented Jun 29, 2021 at 11:31
  • This is undefined behavior, because x is modified in one operand of the multiplication and read in the other operand. Commented Jun 29, 2021 at 11:43
  • 5
    This question which has been answered before in stackoverflow.com/questions/38933101/… Commented Jun 29, 2021 at 11:44
  • @MathiasJ That's operator precedence in the sense of figuring out where implicit parentheses go, it doesn't tell you anything about which order the operands get evaluated in. Commented Jun 29, 2021 at 11:46

1 Answer 1

1

There can be any result, due to Undefined behavior.

Since the x is passed by reference, the last assign will matter. Thus, we have:

9*9*9*9*1=6561

We delay the evaluation of the f(x, c) * x, where all the subsequent recursive calls will have access to the x. We increment the x this way until the c is equal to 0, means we increment the x up to it being 9.

When we hit the base case (the c == 0), the current call returns 1, while the x is already 9.

Then we evaluate the multiplication 1 * x * x * x * x, where x is equal to 9. Thus, the 6561.

Flawless explanation? Not so much.

The fun part is that there is no concept of left-to-right or right-to-left evaluation in C++:

Order of evaluation of any part of any expression, including order of evaluation of function arguments is unspecified (with some exceptions listed below). The compiler can evaluate operands and other subexpressions in any order, and may choose another order when the same expression is evaluated again.

Means, that though this logic gets a pass this time, it may won't be this way next time for me or if you run it yourself.

Sign up to request clarification or add additional context in comments.

5 Comments

The UB should be more visibility called out. Geekforgeek is harmful enough as it is, if we start copying their code without calling out UB...
@Jeffrey was afraid that the "set up and punchline" would not work out. Wait a minute.
Love the bold! much better.
As the duplicate gets into, I don't think this is actually undefined behavior, but the evaluation of the operands is indeterminately sequenced so there's multiple possible values it could return. Still a big difference between "it can return exponentially many possibilities" and "literally any program behavior is acceptable".
@NathanPierson yeah, if it was possible to follow the logic, it leans towards being a case of what's called as unspecified behavior.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.