To understand what happens, you have to understand how recursion works. Every recursive function requires a test condition to break the recursion and a recursive call. You have if (i < 0)
as your test condition and then your have two recursive calls with printf
between them.
So How Does This Work?
You can think of recursion and winding-up until the exit condition is triggered -- and then an unwinding as the recursive calls return. Let's see how this works here.
The Recursion
When you start with recur(2)
in main
, what path does the logic take to wind-up to the exit condition?
If you simplify the function and concentrate on what happens before your test condition is met, you get something similar to:
void recur (int i) {
if (i < 0)
return;
recur (--i);
/* comes after return */
}
Let's follow it through. On the first call, i = 2
so --1
pre decriment occurs making i = 1
, recur (1)
executes. Next call i = 0
, recur (0)
is called again. Finally, i = -1
, and the first recur(-1)
occurs, so if (i < 0)
executes and return
is called.
Now What? -- The Unwinding...
Look at the above shortened function. When you return
, you are returning from the last call to recur(--i)
so control is now passed to the next command after the first recur(-1)
(shown as /* comes after return */
above) So what are the next commands in the full function?
printf("%d\n", i);
recur (--i);
What was the value of i
when this first occured? (hint: -1
).
So printf
is called and then what comes next? Your second recur(--i)
. There i = -2
, the if (i < 0) return;
is triggered and you unwind out of the second recur(-2)
-- there is no command that follows and that function call is now complete.
Control now unwinds to within the previous call where i
is now 0
, the printf
is called and the second recur(--i)
is entered with i = -1
which simply hits return
again and you unwind one more level to where i = 1
returning again from the first recur(--i)
call, 1
is output.
The second recur(--i)
call is entered where after decrement i = 0
and you now recurse once more into the first where i = -1
again triggering return
which causes contol to pass to printf
with the final -1
printing.
You now recurse into the second recur(--i)
with i = -2
triggering return
and completing the function call and the recursion.
So if you go back through the control of your recursive function with two recursive calls and look at each time printf
was reached you have output -1, 0, 1, -1
.
Still Think Recursive Functions With Multiple Recursive Calls Are A Good Idea?
(they are if you are an Aspirin salesman -- otherwise, they are best avoided unless they are the only reasonable option you have)
The only way to get through something like this is to either (1) make friends with your debugger and single-step through your code keeping a scratch sheet of which call was entered when, or (2) copy and paste the function down the page tracking the state of the recursive call at each level and take it step-by-step.
Always a good learning experience, but if a procedural solution is available, the logic is much more straight-forward and you avoid the function call overhead of every recursive call. Recursive functions have their place, and there are some problems to which they provide very elegant solutions. But you have to be mindful of how many times the recursion will occur as you allocate a separate function stack and space for local variables with every call -- which can lead to StackOverflow.