19

This causes a Stack Overflow error. I just need help explaining why this one crashes compared to the correct one which is similar. I have used the debugger, but it is still unclear to me.

public static void main(String[] args) {
    countForwards(5);
}
public static void countForwards( int num ) {
    if (num >= 0){
        countForwards(num--);
    }
    System.out.print(num + " ");
}

I know this is the solution but I don't understand why it is different

public static void countForwards( int num ) {
    if (num >= 0){
        countForwards(num - 1);
    }
    System.out.print(num + " ");
}
JCCS
  • 591
  • 8
  • 22

4 Answers4

44

countForwards(num--) passes the original value of num to the recursive call, which means the recursion never ends.

countForwards(--num) would allow the recursion to end.

After seeing all the traffic this question got, I thought it would be worth it to expand the answer a little.

As paxdiablo commented, even though countForwards(--num) allows the recursion to terminate, it behaves differently than countForwards(num-1).

Both variants would cause the following series of recursive calls :

countForwards(5)
countForwards(4)
countForwards(3)
countForwards(2)
countForwards(1)
countForwards(0)
countForwards(-1)

but they will output a different series of numbers when the recursion unwinds :

num - 1 -- num
-1 -1
0 -1
1 0
2 1
3 2
4 3
5 4

The reason for the difference is that num-1 doesn't change the value of num while --num decrements num.

Eran
  • 387,369
  • 54
  • 702
  • 768
  • 8
    Work the same? No, it wouldn't. In the context of what gets passed down recursively, you're correct. But in terms of what `num` is set to _after_ the recursive call (such as printing it out), not so. `recur(num-1)` won't change `num` at all but `recur(--num)` _will._ – paxdiablo Apr 23 '15 at 05:20
  • 2
    That people will often confuse `x--` with `x - 1` is one reason to avoid `--` (and `++`) in production code. – Lawtonfogle Apr 23 '15 at 13:58
  • 5
    @Lawtonfogle If you avoid using any language that can be misunderstood, you are going to have a very difficult career. I don't think that's a very good reason to not use pre/post increment/decrement. – Aaron Dufour Apr 23 '15 at 14:09
  • @AaronDufour Avoiding commonly misunderstood or abused features of a language when there is a reasonable replacement ends up saving time overall. Increasing code readability and maintainability is worth sacrificing use of language features, at least in the realms where I work. – Lawtonfogle Apr 23 '15 at 14:47
  • @Lawtonfogle: I'd take a middle stance here. `x++;` by itself is perfectly fine; no one is going to misinterpret that as `x+1;` because the latter is pointless nonsense. – Kevin Apr 23 '15 at 15:14
17

num-- uses a postfix operator -- which means that original value i.e. num is passed and its value is decremented after it is passed.

The interesting thing about a postfix operator i.e. the one we are using in this example is that operation is performed and then the value is incremented or decremented. Please refer to official documentation about operators in java

class PrePostDemo {
    public static void main(String[] args){
        int i = 3;

        i++;
        // prints 4
        System.out.println(i);

        ++i;               
        // prints 5
        System.out.println(i);

        // prints 6
        System.out.println(++i);

        // prints 6
        System.out.println(i++);

        // prints 7
        System.out.println(i);
    }
}
Howdy_McGee
  • 10,422
  • 29
  • 111
  • 186
Prasad Kharkar
  • 13,410
  • 5
  • 37
  • 56
6

Post-Decrement

Post-Decrement takes the form variable-name operator. This tells the compiler to first use the original value and afterawrds decrement it, so if we have something like this:

for (int i = 10; i > 0; i--) 
{ 
   System.out.println(i); 

}

The output will be as follows

1: 10
2: 9 
3: 8 
4: 7 
5: 6
6: 5 
7: 4
8: 3 
9: 2
10: 1 

Pre-Decrement

Pre-Decrement takes the form operator variable-name and is used when you want to decrement before you use the value. The same code above would terminate at 0 instead of 1. This is because the function decremented the value before it used the value.

How does this apply to recursive calls?

Each recursive call is it's own stack, so when you pass num-- to the recursive function, you're literally passing the original value of num, and when the child call terminates (in this case never) the parent call will then decrement num. Since you don't have another base case which correctly terminates the call, it results in infinite recursion.

Slothrop
  • 142
  • 7
5

Actually it is happening due to post decrement operator in the method.

   public static void countForwards( int num ) {
    if (num >= 0){

        countForwards(num--);
    }
    System.out.print(num + " ");
}

Now when the function is calling the countForwards again it is always taking value of num as 5 due to post decrement in the method, please try to change as pre-decrement

    public static void countForwards( int num ) {
    if (num >= 0){

        countForwards(--num);
    }
    System.out.print(num + " ");
}

This will be work because value is first decremented and then that value is using method.

as function is calling again and these are primitive and stores in the stack. Thats why it is showing stack overflow.

    public static void countForwards( int num ) {
if (num >= 0){
    countForwards(num - 1);
}
System.out.print(num + " ");

}

This is working because this is an expression which try to solve first itself and then the function can use the value of that expression. I hope it will answer your question.

Sagar Rout
  • 651
  • 1
  • 12
  • 29