Every time you call a method foo from method bar, bar is added to the call stack. The call stack is used to keep track of where the code was before the method was called so it can return there when foo is done.
The following recursive function
int Factorial(int n) {
if (n == 0) { return 1; }
return n * Factorial(n - 1);
}
after several recursions of the call Factorial(5) the call stack would look like this:
Factorial(5) -> Factorial(4) -> Factorial(3) -> Factorial(2) -> Factorial(1)
At this point n is 1, and so the function stops calling the recursive case and instead returns 1. The program then starts winding back up the call stack and the whole thing returns 120.
Without the call stack the program wouldn't know where to go back to when it had finished executing a method.
Now suppose that base case wasn't there, and it was just looked like this:
int Factorial(int n) {
return n * Factorial(n - 1);
}
After several recursions of the call Factorial(5) the call stack would look like this:
Factorial(5) -> Factorial(4) -> Factorial(3) -> Factorial(2) -> Factorial(1) -> Factorial(0) -> Factorial(-1) -> Factorial(-2) -> Factorial(-3) -> Factorial(-4) -> Factorial(-5) -> Factorial(-6) -> Factorial(-7) -> Factorial(-8) -> Factorial(-9) -> Factorial(-10) -> Factorial(-11) -> Factorial(-12) -> Factorial(-13) -> Factorial(-14) -> Factorial(-15) etc…
Because there is no point at which the code stops calling itself it will carry on forever, and the call stack will grow and grow and grow taking up more and more memory until it exceeds the memory it has been allocated and the StackOverflow exception is thrown.
There are 2 ways to stop this from happening, the best depends on the situation.
1 Provide a base case. Make sure there is some condition that is eventually reached which stops the function from calling itself. In the Factorial case it's that n == 1, but it could be that a certain amount of time has passed, that it has recursed a certain number of times, that some result of some computation is within some bounds, whatever. As long as it stops recusing before the stack is too big.
2 Remove the recursion and re-write it without. Any recursive algorithm can be re-written as a non-recursive algorithm. It may not be as clean and elegant, but it can be done. In the factorial argument it may be something like:
int Factorial(int n) {
int result = 1;
for (int i = 0; i < n; i += 1) {
result *= n;
}
return result;
}
If the aim is to continually run the same function again and again, then you can re-write the recursive
void Foo() {
// Some code
Foo();
}
as
void Foo() {
while (true) { // Some code }
}