2

I've recently started trying to learn C & was doing an exercise that involved creating a recursive factorial function. Why does the following print out an answer of 24?

#include <stdio.h>

int factorial(int n);

int main(void)
{
    int n = 5;
    printf("%d\n", factorial(n));
    return 0;
}


int factorial(int n)
{
    if (n <= 1)
        return 1;
    else
        return n * factorial(--n);
}

If i change the last line to

return n * factorial(n - 1);

I get the expected 120.

I understand that you can't use n-- b/c it only decreases n after the line is processed but whats wrong with --n & why does it give 24?

Arun Gowda
  • 2,721
  • 5
  • 29
  • 50
pickle323
  • 653
  • 4
  • 12
  • 4
    `--n` changes variable n, `n-1` does not, in your case use `n-1` – Iłya Bursov Mar 23 '18 at 04:30
  • 5
    This program causes undefined behaviour, anything can happen – M.M Mar 23 '18 at 04:35
  • 3
    If you have started learning C, then also note, use of recursion should be limited to instances where a procedural solution does not exist, or would be prohibitively long or difficult to implement. Why? Because every recursive call is a separate function call requiring its own function stack. For `factorial` here it is fine, but if you kickoff a recursion tens or hundreds of thousands deep, or more, you can rapidly exhaust resources. Use them sparingly. – David C. Rankin Mar 23 '18 at 04:36
  • @M.M - you are referring to "What is the value of `n`?" in `return n * factorial(--n);` – David C. Rankin Mar 23 '18 at 04:38
  • 2
    The reference is [C11 Standard - 6.5 Expressions(p2)](http://port70.net/~nsz/c/c11/n1570.html#6.5p2) *"If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined."* – David C. Rankin Mar 23 '18 at 04:42
  • @DavidC.Rankin The behaviour of the entire program is undefined ; I'm not referring to what you claim – M.M Mar 23 '18 at 04:49
  • `printf` wouldn't be undefined as well (except for values `<= 1`), but the unsequenced side effect is a prime example. – David C. Rankin Mar 23 '18 at 04:53

1 Answers1

7

whats wrong with --n & why does it give 24?

The problem is that --n modifies n, so your line

return n * factorial(--n);

may evaluate like:

return (n - 1) * factorial(n - 1);

because the factorial(--n) is evaluated before the n that is the first term of the expression. On the other hand, the first term could be evaluated before the second, and you'd get the result you expect. Or, something entirely different could happen, because (as M.M and David C. Rankin point out in comments) what happens when you try to use a variable and modify it in the same expression is undefined:

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined.

So let's address your title question:

Does (--n) equal (n - 1)?

The values of --n and of n - 1 are the same, but the former expression has the side effect that it modifies n. You should really think of --n as being shorthand for the expression (n = n - 1).

Caleb
  • 124,013
  • 19
  • 183
  • 272
  • Good answer +1, but maybe add some docs describing this behavior in order of operations. And I wonder if Java would behave the same way (it probably would). – Tim Biegeleisen Mar 23 '18 at 04:32
  • 5
    Actually it is undefined behaviour – M.M Mar 23 '18 at 04:34
  • 1
    @M.M That's why I used the word *may*, but perhaps it's better to be explicit. Will edit. – Caleb Mar 23 '18 at 04:44
  • I tested this code ( n * factorial(--n) ) in Java. The result is 120. Same logic but it is different from C and Java. – Junhee Shin Mar 23 '18 at 05:57
  • 1
    @JunheeShin Java apparently has a rule that [subexpressions are evaluated from left to right](https://stackoverflow.com/a/6801431/643383). If that's the case, then you could create a similar situation by reversing the terms: `(factorial(--n) * n)`. – Caleb Mar 23 '18 at 06:01