int fact(int x)
{
if (x == 1)
return 1;
else
return (x * fact(x-1));
}
My question is how the variables are allotted on the stack during function call and if x = 5 - obviously the return would be 5 * fact(4), but how this 5 * fact(4) is pushed onto the stack how its value is resolved later i.e simple values (not variables) can be pushed and their values can be retrieved back, but how does the compiler treat fact(4).
Can anyone explain how exactly this recursion procedure is implemented by the compiler in detail?
Before 5 * fact(4) is returned fact(4) is called and evaluated on a new stack frame. When the call to fact(4) finishes, it places it's return value where the fact(5) stack frame can reach it (this may be the stack or in a register) and use it to calculate its own return value. So the order of finishing evaluation will be fact(1), fact(2), ..., fact(4), fact(5). Each placing their return values where the next one can retrieve it and use to calculate its own return value.
Related
We use a value n to perform recursion on. We save this value in a variable x. Then the variable x gets added to recursion as a return value. How exactly does this work?
I tried different approaches to check whether you use recursion first for x and then use x to add it to another recursion.
#include <stdio.h>
#include <stdlib.h>
int up(int n)
{
int x;
if(n == 0)
{
return 0;
}
else if(n == 1)
{
return 1;
}
else
{
x = up(n - 2);
return x + up(n - 1);
}
}
int main(void)
{
int n = 20;
int res;
res = up(n);
printf("Result %d\n", res);
return 0;
}
The result is 6765. Since it's a code from school the result should be fine. I just dont get why.
It sounds like you are having an issue grasping the concept of the function scope with recursion. It's generally easiest to think of recursion as a tree/stack.
Stack:
Let's say that n=5 for a simplistic example.
Up(5) is pushed onto the stack.
You then declare that x inside of this function scope is UP(3).
Now UP(3) is pushed onto the stack, and UP(5) is waiting for Up(3) to return.
Stack Order:
Up(3)
Up(5)
Now Up(3) declares x inside of this function to be UP(1) and patiently waits for Up(1) to return. Since x is declared inside of the function, they are local variables only accessible inside of the function that declared them. This means that the X inside of Up(3) is stored in a completely different location in memory as the X inside of Up(5). You will most definitely learn more about this when you research address-spaces and how local variables are stored and the like. But continuing forward!
Stack:
Up(1)
Up(3)
Up(5)
Up(1) returns 1, and thus we pop it off the stack! This means Up(3) can continue running.
Stack:
Up(3)
Up(5)
Up(3) now has x=1 (the return of Up(1) and wishes to return x+Up(2). In order to do that we push Up(2) onto the stack.
Stack:
Up(2)
Up(3)
Up(5)
Continuing this example, Up(2) will add Up(0) to the stack. Up(0) will return 0 so the x inside of the scope for Up(2) is set to 0. Up(2) will then add Up(1) to the stack, which will return 1. Up(2) will return (0+1). Now we can go back to Up(3) by popping Up(2) off the stack. Up(3) has x=1 and wishes to return (1+1). Popping Up(3) off the stack we are left with Up(5) on the stack. X is now set to 2 due to the return of Up(3). Now we add Up(4) to the stack, which adds Up(2),Up(0),Up(1),Up(3),Up(2),Up(0),Up(1) in that order Note(Many of these calls are popped off before new ones are added).
I recommend reading about global scope and function scope. Understanding these concepts are pretty crucial to the basics of understanding recursion. You can already see however that this type of recursion is pretty bruteforced and not optimized at all. For instance, you are calculating Up(2) multiple times for each recursive call created. This leads to a scalability issue when working with larger numbers, as you are repeating the same operation multiple times on the same number. This can be solved with a memoization array and a bit more logic for a smaller Big O runtime, but that may be a bit too far in detail for this question.
The argument bindings are unique for each call. That means that n in up(20) is never mixed with the n in up(19). Since it is not a reference the n - 1 is calculated and passed as a new value in a different place the the old so that when it returns the old n is what it always has been during the additional calls. Local variables are also only existing in the scope and thus every x is different too.
Since this function is pure, thus it's result is the sole product of the algorithm and the argument I think you should go from the base case and up...
The base cases:
up(0) => 0
up(1) => 1
The default cases:
up(2) => up(2-2) + up(2-1) => up(0) + up(1) => 0 + 1
Now I knew the results of 0 and 1 from the base cases up there and you can just replace it with the result. We can go further:
up(3) => up(3-2) + up(3-1) => 1 + 1 => 2
up(4) => up(4-2) + up(4-1) => 1 + 2 => 3
up(5) => up(5-2) + up(5-1) => 2 + 3 => 5
...
Interesting thing about this (Fibonacci) sequence is that if you have the two previous numbers you can generate the next. This makes this sequence an excellent candidate for either tail recursion or a iterative loop, both of which are far superior to the easier to read recursive version.
Here is how much the function could be simplified:
int Fib(int n)
{
return (n<2 ? n : Fib(n-1) + Fib(n-2));
}
This is simple C, not C++
I recently wrote my Grad school Admission test few days back and the following question appeared in the test.
When the below function is invoked with any positive integer as argument, does it terminate? Also does it print anything?
void convert (int n)
{
if (n < 0)
printf ("%d", n);
else
{
convert (n/2);
printf ("%d", n%2);
}
}
According to me, nothing will be printed as the control never reaches inside the if statement and also since the printf statement is placed after the function call under else block. The value of n never reaches below 0 and the function calls itself again and again till the stack overflows. My question is whether the code will abnormally terminate because of stack overflow?
The code will not terminate with a positive integer argument since the base condition n < 0 will never be met.
The recursive call to convert calls it with the argument n / 2, which, as integer division, will inevitably reach zero, but never less than it.
For example, with the argument 10:
call convert(10)
10 < 0 is false; enter the else branch
call convert(10 / 2)
5 < 0 is false; enter the else branch
call convert(5 / 2)
2 < 0 is false; enter the else branch
call convert(2 / 2)
1 < 0 is false; enter the else branch
call convert(1 / 2)
0 < 0 is false; enter the else branch
call convert(0 / 2)
0 < 0 is false; enter the else branch
call convert(0 / 2)
0 < 0 is false; enter the else branch
call convert(0 / 2)
0 < 0 is false; enter the else branch
It will never enter the base case.
Yes, unless your compiler's optimizer does something unusual, this program will abnormally terminate because of stack overflow.
The reason is that the convert() function is recursively called infinitely many times. You knew that already, but the point is this: each recursive entry to convert() pushes a new frame onto the stack. Each frame includes a return address to the previous frame and a local value of n.
Compilers have optimizers but it would take an unusual optimizer to intuit that this function (a) has no side effects and (b) returns no value. It is unlikely therefore that the optimizer would save this code from abnormal termination.
I believe that you have answered this question right.
Meanwhile, a commenter has reminded us of a special case, tail recursion. If the recursive call had ended the function, as return convert(n/2); for example, then the compiler could have reused a single stack frame for all recursive invocations. Reason: by the time the recursive call occurs, the current invocation no longer requires its storage; the object n could safely be overwritten by the new n for the recursive call; only the return address to the original caller would need to be retained. If tail recursion applied, the stack would not grow and, therefore, the program would not terminate, neither abnormally nor otherwise. However, tail recursion does not apply here.
The code will terminate with a stackoverflow or not depending on the compiler output.
There will be no output. because n will never be smaller than 0.
With a naive compiler that does compile the recursion without optimisation, you will get a stackoverflow on most (if not all) implementations.
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
Can you help me explain how this gives 3 as a result?
int main()
{
int k = fun(125, 35);
printf("%d",k);
return 0;
}
int fun(int x, int y){
if (y <= 1) return x;
else if (y > x / y) return fun(y, x / y);
else return fun(x / y, y);
}
The first time your program calls the fun(int x,int y) , it will call fun(125,35).
Since 35>1 and 35>(125/35), thus your function will return fun(y,x/y) i.e. fun(35,3).
Now, since 3>1 but 3<(35/3), thus it will return fun(x/y,y) i.e. fun(11,3). Now, 3>1 and 3=(11/3), so it will return fun(x/y,y) i.e. fun(3,3). Again 3>1 and 3>(3/3), thus it will call fun(3,1). Now y==1, thus the function will return value of x i.e 3.
return fun(y, x / y); returns one value. That value is the result of calling fun with the two arguments y and x / y.
This use of a function within itself is called recursion. The possible values with which fun is called are divided into base cases and general cases. In a base case, the function is computed in a simple way. For example, in this function, when y <= 1, the function returns x.
In general cases, the function is computed by calling itself with different arguments. Usually, the different arguments are reduced or simplified in some way (although convoluted cases in which arguments grow larger or more complicated before eventually reaching bases cases are also possible). In this function, the arguments are reduced by replacing x and y with either y and x/y or with x/y and y. In either case, at least one of the arguments has been made smaller by dividing it by y, which we know is greater than 1 at this point.
Eventually, the function will call itself with the second argument reduced to a value less than or equal to 1, at which point the function will return the first argument, and the entire sequence of calls will wrap up by returning this value.
Why do I have to initialize one of the stacks to -1? Where would top1 point to?
int ar[SIZE];
int top1 = -1;
int top2 = SIZE;
void push_stack1 (int data)
{
if (top1 < top2 - 1)
{
ar[++top1] = data;
}
else
{
printf ("Stack Full! Cannot Push\n");
}
}
The difference is whether you let top1 point to the last used element or the first free element.
With -1 you let it point to the last used element.
With 0 you let it point to the first free element.
There is also symmetry in the use of pre-increment/decrement and post-increment/decrement.
Initializing to -1 implies ++top1 for push and top1-- for pop.
Initializing to 0 implies top1++ for push and --top1 for pop.
No, you wouldn't have to initialize top1 as -1 at all if your code would have been:
int ar[SIZE];
int top1 = 0; // 0 `here`
int top2 = SIZE;
void push_stack1 (int data)
{
// v conditional check with `<=` instead of `<`
if (top1 <= top2 - 1) // even better: `if (top1 < top2)`
{
ar[top1++] = data;
// ^ using "top1++" instead of "++top1"
}
else
{
printf ("Stack Full! Cannot Push\n");
}
}
++something (also known as pre-increment) will increment the value of something, and then return the incremented value.
Whereas, something++ (also known as post-increment) will increment the value of something, but return the original value that something held before being incremented.
But you must note here that whether it is ++top1 or top1++, we are always passing 0 as the first index to ar because the 0 is the first index of any array/list in all the languages.
This is really odd that you started to think that in stack datastructure's implementation - you would have to initialize top with -1. Whick book said that? If any book did, at it's best it can mostly mean that the implementation they showed is following that.
Where would top1 point to? If you directly index into an array object, then yes it would likely try to access a memory which is out of the array bound, which is surely an undefined behavior(Arrays are 0-indexed in C ). But in every scenarios, we see implementation where top is increased first (in case top is initialized with -1)++top and then that value is used to index into array (For the very first time this will result in 0), which is precisely the case here. (Array is mentioned here because it seems that underlying data structure the code you showed uses that).
So top=-1 will initially mean that it is in a empty state and you can say no member is being added to the stack data structure. Here you could have initialized top with 0 also provided that you would have to change your push,pop or isEmpty() and other auxiliary functions associated with this data structure implementation accordingly, as needed.
Also you can check your other function's implementation to get the justification of top=-1 for the implementation with which you are working on.
Also if you are in doubt about what ++ does here and how is it significant - Look what C11 standard has to say about it (N1570Draft)
In section §6.5.3.1¶2
The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation.
++top1 will result in the new incremented value which is 0 in case it was -1 earlier.
Where will the value of n be stored after first call to factorial()?
When n=1 then return 1 is sent, why doesn't res becomes equal to 1 in main function?
#include<stdio.h>
int factorial(int n)
{
if(n<=1)
return 1;
else
return n*factorial(n-1);
}
int main()
{
int res =factorial(3);
printf("%d",res) ;
}
The run-time stack will have four functions in total: main(), factorial(3), factorial(2), and factorial(1). Each of these gets its own variable space. There are three instances of the variable n, one for each call to factorial.
When factorial(1) returns 1, that value isn't returned to main(), because main() is not what called it: factorial(2) called it. That instance performs the operation 2*1 and returns 2. The caller of that instance is factorial(3), which receives the 2, performs the operation 3*2, and returns a value of 6 to its caller, main().
Does that help clear it up? If not, I have two suggestions:
(1) Search this topic on StackOverflow and the internet in general; there are plenty of detailed walk-through examples of factorial.
(2) Insert print statements to trace the flow of data and execution. Within factorial, separate the computation and the return, so you can put a print in between:
catch = factorial(n-1)
result = n * catch
print n, catch, result
return result
Each time a function is called, its parameter and local variables are pushed onto the stack. In the case of a recursive function, there will be a set of the variables on the stack for each active invocation of the function.
In this example, the first call to factorial has n set to 3. Within the function, factorial is called again, this time with n set to 2. It calls itself one more time with n set to 1. In this last call, it returns a value of 1. This gets returned to the prior invocation where n is 2, which then returns 2 * 1 which is 2. This value is returned to the first invocation where n is 3 and returns 3*2 which is 6 back to main.
So the call stack looks like this:
main
|--> factorial(n==3)
|--> factorial(n==2)
|--> factorial(n==1)
return 1
return 2*1
return 3*2
print 6
n is not stored in the way of global or static variables - it's stored on the stack. Calling a function with arguments the arguments are being pushed on the stack.
See what's happening when your running your program:
factorial(3) gets called (in main)
As n is not equal or smaller to 1 factorial(2) is called and the result will be multiplied by n (is 3).
As n is not equal or smaller to 1 factorial(1) is called and the result will be multiplied by n (is 2).
As n is now equal or smaller to 1 the function returns 1
factorial(2) returns 1*2
factorial(3) returns 2*3
res will be 6