Just a quick note to clarify that the factorial of zero or one always equals one, Thats reason I am returning one in these casesThe fowchart you show cannot return anything but one, maybe you should correct it first.
I believe the function should be called four times, with each call returning a value. It would look something like this:Look at your flowchart again. Where does it return anything other than one?
int fact(int n)
{
if (n <= 1)
return 1;
return n * fact2(n - 1);
}
int fact(int n)
{
if (n <= 1)
return 1;
return n * fact(n - 1);
}
It's fine for things like tree and graph algorithms (functional programming) but I'd fire anyone that used it in a critical embedded applications operational logic.When I first learned about recursion, I thought it was the coolest thing ever. When I settled into my career in compiler development, I understood why. It was the sharpest tool in my box.
Just walk through it the same way I walked through the factorial problem. It's the exact same process.I understand Fibonacci sequence, I'm having difficulty grasping the recursive mechanism used in this code.
C:#include <stdio.h> int fib(int n) { if (n <= 1) return n; return fib(n - 1) + fib(n - 2); // Recursive case } int main() { printf("Fibonacci sequence: "); for (int i = 0; i < 6; i++) { printf("%d ", fib(i)); } return 0; }
- When i = 0, the value is 0.
- When i = 1, the value is 1.
- When i = 2, the value is 1.
- When i = 3, the value is calculated as fib(2) + fib(1)
Could you kindly provide some help into how the recursion works in this context, especially when i = 3 and beyond?
Just a word on terminology. Many books and articles describe a recursive function as "a function that can call itself". While technically valid, it can be confusing so think of it more as "a function that can call a copy of itself", while not technically correct it is easier for some people to grasp because ordinarily functions always call other distinct functions. @WBahn talks about this above.Hello Everyone
I am trying understand the flow of recursive functions in the context of C language,
I've attempted to create a flowchart to visualize the execution of a recursive function, but I'm uncertain about certain aspects and would greatly appreciate your expertise to clarify them.
View attachment 314196
There are not typically compilers running on critical embedded processors. Though I do have one in my ballroom lighting server (PIC24, 512K program, 64K ram). I can write and send programs from my phone’s browser. And yes, it does use recursion.It's fine for things like tree and graph algorithms (functional programming) but I'd fire anyone that used it in a critical embedded applications operational logic.
I don't have a problem with using recursion at the proper place and time. It's a convenient and elegant solution to a class of problems when you can have a unbounded stack. When you don't or have critical safety issues, use iteration. Recursion can always be replaced with basic iteration. Recursion and iteration are equally expressive.There are not typically compilers running on critical embedded processors. Though I do have one in my ballroom lighting server (PIC24, 512K program, 64K ram). I can write and send programs from my phone’s browser. And yes, it does use recursion.
Note, I said 'unbounded' stack, NOT, NO, STACK.Replacing recursion with iteration usually involves implementing a stack. Show me an algorithm for tree traversal (say, inorder) without using either iteration or a stack.
Which can also be done with a recursive function. You just have check the depth. In compilers, the depth is usually related to the depth of nesting in the program, which really never gets out if control in a real program. The embedded compiler I referred to would have hit other limits long before depth of recursion could be a problem.Note, I said 'unbounded' stack, NOT, NO, STACK.
This is basic data structures stuff. Recursion and iteration are equally expressive (but not always equally elegant) but there are other than mathematical and computer science restrictions on software being designed for things that can hurt or kill people and destroy valuable property.Which can also be done with a recursive function. You just have check the depth. In compilers, the depth is usually related to the depth of nesting in the program, which really never gets out if control in a real program. The embedded compiler I referred to would have hit other limits long before depth of recursion could be a problem.


To understand the reason why functions need to be duplicated, you need to know how variables are allocated memory in a data stack and the consequences of this allocation.
The MPLAB XC8 compiler uses a compiled data stack when the default stack model is selected. With this type of stack, local, stack-based variables (auto and parameter variables, as well as compiler-allocated temporary storage) are allocated a fixed address in data memory, much like the allocation of global objects. Since direct memory-access instructions can be used to read and write objects allocated in this way, this model can be used for all 8-bit PIC devices and yields very efficient code. The one problem this type of allocation presents is that functions that define local objects are not reentrant.
A reentrant function can have multiple instances of itself active at the same time. The common usage of reentrant functions is with recursion, where a function calls itself or calls a function that will ultimately lead to itself being called. So if the function foo() calls the function bar() and bar() calls foo(), then foo() (and bar() for that matter) need to be reentrant for this code to execute correctly.
For a function to be reentrant, each instance of itself must use its own copy of any local variables. However, since a compiled stack allocates local objects at a fixed address, the local variables of one instance of a function would be at the same address as the local variables used by another, so there would be a corruption of the function's local variables.
A function must also be reentrant if it is called from separate call graphs in a program. A call graph is a tree of function calls that constitute one sequential part of a program, much like a thread. Main-line code constitutes one call graph, and the code executed for an interrupt, another. If foo(), for example, has been written so that it does not use recursion, you can safely use this function anywhere in your program. But if foo() is called from main-line code and also from interrupt code, this could result in both instances being active at the same time, specifically, if foo() was executing in main-line code when an interrupt was triggered, then execution of that instance of foo() would be suspended and a second instance would be executed by the interrupt, corrupting the variables of the original instance.
If your project is set up to use the compiled stack, recursion is not supported. If you attempt to recursively call a function you will get the following error message:
recursive function call to "_foo"
There is a concept called tail recursion, where the implicit stack is not required and so stack capacity is not an issue.I don't have a problem with using recursion at the proper place and time. It's a convenient and elegant solution to a class of problems when you can have a unbounded stack. When you don't or have critical safety issues, use iteration. Recursion can always be replaced with basic iteration. Recursion and iteration are equally expressive.