Is there any hard-wired limit on recursion depth in C - c

The program under discussion attempts to compute sum-of-first-n-natural-numbers using recursion. I know this can be done using a simple formula n*(n+1)/2 but the idea here is to use recursion.
The program is as follows:
#include <stdio.h>
unsigned long int add(unsigned long int n)
{
return (n == 0) ? 0 : n + add(n-1);
}
int main()
{
printf("result : %lu \n", add(1000000));
return 0;
}
The program worked well for n = 100,000 but when the value of n was increased to 1,000,000 it resulted in a Segmentation fault (core dumped)
The following was taken from the gdb message.
Program received signal SIGSEGV, Segmentation fault.
0x00000000004004cc in add (n=Cannot access memory at address 0x7fffff7feff8
) at k.c:4
My question(s):
Is there any hard-wired limit on recursion depth in C? or does the recursion depth depends on the available stack memory?
What are the possible reasons why a program would receive a reSIGSEGV signal?

Generally the limit will be the size of the stack. Each time you call a function, a certain amount of stack is eaten (usually dependent on the function). The eaten amount is the stack frame, and it is recovered when the function returns. The stack size is almost almost fixed when the program starts, either from being specified by the operating system (and often adjustable there), or even being hardcoded in the program.
Some implementations may have a technique where they can allocate new stack segments at run time. But in general, they don't.
Some functions will consume stack in slightly more unpredictable ways, such as when they allocate a variable-length array there.
Some functions may be compiled to use tail-calls in a way that will preserve stack space. Sometimes you can rewrite your function so that all calls (Such as to itself) happen as the last thing it does, and expect your compiler to optimise it.
It's not that easy to see exactly how much stack space is needed for each call to a function, and it will be subject to the optimisation level of the compiler. A cheap way to do that in your case would be to print &n each time its called; n will likely be on the stack (especially since the progam needs to take its address -- otherwise it could be in a register), and the distance between successive locations of it will indicate the size of the stack frame.

1)Consumption of the stack is expected to be reduced and written as tail recursion optimization.
gcc -O3 prog.c
#include <stdio.h>
unsigned long long int add(unsigned long int n, unsigned long long int sum){
return (n == 0) ? sum : add(n-1, n+sum); //tail recursion form
}
int main(){
printf("result : %llu \n", add(1000000, 0));//OK
return 0;
}

There is no theoretical limit to recursion depth in C. The only limits are those of your implementation, generally limited stack space.
(Note that the C standard doesn't actually require a stack-based implementation. I don't know of any real-world implementations that aren't stack based, but keep that in mind.)
A SIGSEGV can be caused by any number of things, but exceeding your stack limit is a relatively common one. Dereferencing a bad pointer is another.

The C standard does not define the minimum supported depth for function calls. If it did, which is quite hard to guarantee anyway, it would have it mentioned somewhere in section 5.2.4 Environmental limits.

Related

Segmentation fault about data type?

I find out that my code only works with n <= 43429. If n>43429, it causes a segmentation fault. Did I wrong with the data type or anything?
here is my code and debug result:
enter image description here
#include<stdio.h>
#include<windows.h>
double recursive(long n);
int main(){
printf("\nEnter n:");
long n; scanf("%ld", &n);
printf("\n%.2lf", recursive(n));
getch();
return 0;
}
double recursive(long n){
if(n<=1) return 1;
else return (double)1/n + recursive(n-1);
}
Every recursive call requires space on the call stack (often referred to as just "the stack"). The stack has a fixed maximum size. If you use up all of the space in the stack, the program crashes. Your OS and/or your compiler default to making the stack big enough for 43429 recursive calls, but not more.
There is usually a way to request more space for the stack, but not from within the program. On Windows you specify the needed size in the "module .def file". I am not familiar with the IDE you are using, but that should translate to a knob in the project configuration somewhere.
Alternatively, this would be a good time to learn how to convert recursion to iteration. Your program is almost tail recursive so it's an easy case.
I don't know how you managed to get Windows to report this crash using the phrase "Segmentation fault", but that's not important right now.

Does recursive functions have some limitations? eg: how many layers does the function require?

Made a recursive function which gives how many terms are there in a collatz sequence given a starting number, this is the code n=13 for exemple :
int collatz(long n,long o)
{
if (n!=1) {
if(n%2==0)
return collatz(n/2,o+1);
else
return collatz((n*3)+1,o+1);
} else
printf("%ld\t",o);
}
void main()
{
collatz(13,0);
}
the function runs as expected; however with some integers such as "n=113383" something overflows (I guess) and returns :
Process returned -1073741571 (0xC00000FD) execution time : 4.631 s
Press any key to continue.
Excuse my non technical explanation, many thanks !
There is no limitation to recursion depth in the C standard itself. You might cause a stack overflow, but the stack size is different in different environments. I think Windows has 1MB and Linux 8MB. It also depends on the size of the stack frame for the function, which in turn depends on how many variables it has and which type.
In your case, you have two long variables which probably is 8 bytes each. You also have the string "%ld\t" which is 5 bytes, which might end up on the stack, but I'm not sure. On top of that you have the overhead of two pointers to the function return address and to the previous stack frame and they are 8 bytes each on a 64 bit system. So the stack frame for your function will roughly be 32 bytes or so. Maybe a little bit more. So on a Linux system I'd guess that your function would crash at a depth of around 200'000.
If this is a problem, consider rewriting the function to a non-recursive variant. Look at Blaze answer for how that can be done for your case. And as andreee commented below:
Additional note: You can increase the stack size under Linux with ulimit -s (also possible: ulimit -s unlimited) and in MSVC you can set the /F compilation flag to increase the stack size of your program. For MinGW, see this post.
What happens here is a stack overflow. This happens because every call of the function creates a new stack frame, and if there are too many, the stack's memory runs out. You can fix it by using iteration instead of recursion.
Also, long might not be able to hold the numbers that the collatz sequence produces for a starting value of 113383 (it didn't for me with MSVC). Use long long instead, that is at least 64 bits big. All in all, it could look like this:
void collatz(long long n)
{
long o;
for (o = 0; n > 1; o++) {
if (n % 2 == 0)
n /= 2;
else
n = n * 3 + 1;
}
printf("%ld\t", o);
return;
}
int main()
{
collatz(113383);
return 0;
}
Note how instead of recursion we now have a for loop.

Recursive function, passing arguments - segmentation fault

I am writing a program for multiplying big numbers using a karatsuba algorithm.
There is a recursive function.
Right before the recursive call I print string values and they are ok. Then, inside this function at the beginning I print the passed arguments again (I should get exactly the same results as before recursive call, earlier printf()) and I get segmentation fault.
This happen not on first function execution, but after many recursive calls.
My code:
void karatsuba(char *result, char *first, char *second)
{
printf(" %s %s\n", first, second);
<somewhere here conditional return to end recursion>
...
...
printf(" %s %s\n", temp_first, temp_second);
karatsuba(temp, temp_first, temp_second);
...
...
}
What do can cause segmentation fault in that case?
UPDATE:
Thank you all for your answers. Stack overflow is propably the reason.
I created a static counter incremented at the start of recursive function and decremented at each of function ends and printed it. At the segmentation fault its value indicated depth of 46778.
Then, I increased stack size as Graham Borland pointed to 32MB. Now, counter indicated depth of 159126 calls, so increasing stack size made it better.
Sum of data in this function is 140B. Multiplying this value by stack depth gives me 21MB, which is less than 32MB.
After all, this number of recursive calls is too big. Doing calculation on paper I go maximum into <10 recursive calls for my data. Propably infinite recursion. :(
You are likely to be busting the stack. Depending on the platform, you may be able to increase the stack available to your process. For example, on a Unix-like platform, entering this at the bash prompt before running your program:
ulimit -s 32768
will increase the stack to 32MB.
The most probable reason is:
Stack Overflow
Infinite recursion??

Maximum size array program in C?

with the following code, I am trying to make an array of numbers and then sorting them. But if I set a high arraysize (MAX), the program stops at the last 'randomly' generated number and does not continue to the sorting at all. Could anyone please give me a hand with this?
#include <stdio.h>
#define MAX 2000000
int a[MAX];
int rand_seed=10;
/* from K&R
- returns random number between 0 and 62000.*/
int rand();
int bubble_sort();
int main()
{
int i;
/* fill array */
for (i=0; i < MAX; i++)
{
a[i]=rand();
printf(">%d= %d\n", i, a[i]);
}
bubble_sort();
/* print sorted array */
printf("--------------------\n");
for (i=0; i < MAX; i++)
printf("%d\n",a[i]);
return 0;
}
int rand()
{
rand_seed = rand_seed * 1103515245 +12345;
return (unsigned int)(rand_seed / 65536) % 62000;
}
int bubble_sort(void)
{
int t, x, y;
/* bubble sort the array */
for (x=0; x < MAX-1; x++)
for (y=0; y < MAX-x-1; y++)
if (a[y] > a[y+1])
{
t=a[y];
a[y]=a[y+1];
a[y+1]=t;
}
return 0;
}
The problem is that you are storing the array in global section, C doesn't give any guarantee about the maximum size of global section it can support, this is a function of OS, arch compiler.
So instead of creating a global array, create a global C pointer, allocated a large chunk using malloc. Now memory is saved in the heap which is much bigger and can grow at runtime.
Your array will land in BSS section for static vars. It will not be part of an image but program loader will allocate required space and fill it with zeros before your program starts 'real' execution. You can even control this process if using embedded compiler and fill your static data with anything you like. This array may occupy 2GB or your RAM and yet your exe file may be few kilobytes. I've just managed to use over 2GB array this way and my exe was 34KB. I can believe a compiler may warn you when you approach maybe 231-1 elements (if your int is 32bit) but static arrays with 2m elements are not a problem nowadays (unless it is embedded system but I bet it is not).
The problem might be that your bubble sort has 2 nested loops (as all bubble sorts) so trying to sort this array - having 2m elements - causes the program to loop 2*1012 times (arithmetic sequence):
inner loop:
1: 1999999 times
2: 1999998 times
...
2000000: 1 time
So you must swap elements
2000000 * (1999999+1) / 2 = (4 / 2) * 10000002 = 2*1012 times
(correct me if I am wrong above)
Your program simply remains too long in sort routine and you are not even aware of that. What you see it just last rand number printed and program not responding. Even on my really fast PC with 200K array it took around 1minute to sort it this way.
It is not related to your os, compiler, heaps etc. Your program is just stuck as your loop executes 2*1012 times if you have 2m elements.
To verify my words print "sort started" before sorting and "sort finished" after that. I bet the last thing you'll see is "sort started". In addition you may print current x value before your inner loop in bubble_sort - you'll see that it is working.
Dynamic Array
int *Array;
Array= malloc (sizeof(int) * Size);
The original C standard (ANSI 1989/ISO 1990) required that a compiler successfully translate at least one program containing at least one example of a set of environmental limits. One of those limits was being able to create an object of at least 32,767 bytes.
This minimum limit was raised in the 1999 update to the C standard to be at least 65,535 bytes.
No C implementation is required to provide for objects greater than that size, which means that they don't need to allow for an array of ints greater than
(int)(65535 / sizeof(int)).
In very practical terms, on modern computers, it is not possible to say in advance how large an array can be created. It can depend on things like the amount of physical memory installed in the computer, the amount of virtual memory provided by the OS, the number of other tasks, drivers, and programs already running and how much memory that are using. So your program may be able to use more or less memory running today than it could use yesterday or it will be able to use tomorrow.
Many platforms place their strictest limits on automatic objects, that is those defined inside of a function without the use of the 'static' keyword. On some platforms you can create larger arrays if they are static or by dynamic allocation.

A couple of questions on recursive functions in C language

This is a function to get sum of the digits of a number:
int sumOfDigits(int n)
{
int sum=0; //line 1
if(n==0)
return sum;
else
{
sum=(n%10)+sumOfDigits(n/10); //line 2
// return sum; //line 3
}
}
While writing this code, I realized the scope of the local variables is local to each individual recursion of the function. So am I right in saying that if n=11111, 5 sum variables are created and pushed on the stack with each recursion? If this is correct then what is the benefit of using recursion when I can do it in normal function using loops, thus overwriting only one memory location? If I use pointers, recursion will probably take similar memory as a normal function.
Now my second question, even though this function gives me the correct result each time, I don't see how the recursions (other than the last one which returns 0) return values without uncommenting line 3. (using geany with gcc)
I'm new to programming, so please pardon any mistakes
So am I right in saying that if n=11111, 5 sum variables are created and pushed on the stack with each recursion?
Conceptually, but compilers may turn some forms of recursion into jumps/loops. E.g. a compiler that does tail call optimization may turn
void rec(int i)
{
if (i > 0) {
printf("Hello, level %d!\n", i);
rec(i - 1);
}
}
into the equivalent of
void loop(int i)
{
for (; i > 0; i--)
printf("Hello, level %d!\n", i);
}
because the recursive call is in tail position: when the call is made, the current invocation of rec has no more work to do except a return to its caller, so it might as well reuse its stack frame for the next recursive call.
If this is correct then what is the benefit of using recursion when I can do it in normal function using loops, thus overwriting only one memory location? If I use pointers, recursion will probably take similar memory as a normal function.
For this problem, recursion is a pretty bad fit, at least in C, because a loop is much more readable. There are problems, however, where recursion is easier to understand. Algorithms on tree structures are the prime example.
(Although every recursion can be emulated by a loop with an explicit stack, and then stack overflows can be more easily caught and handled.)
I don't understand the remark about pointers.
I don't see how the recursions (other than the last one which returns 0) return values without uncommenting line 3.
By chance. The program exhibits undefined behavior, so it may do anything, even return the correct answer.
So am I right in saying that if n=11111, 5 sum variables are created
and pushed on the stack with each recursion?
The recursion is 5 levels deep, so traditionally 5 stack frames will be eventually created (but read below!), each one of which will have space to hold a sum variable. So this is mostly correct in spirit.
If this is correct then what is the benefit of using recursion when I
can do it in normal function using loops, thus overwriting only one
memory location?
There are several reasons, which include:
it might be more natural to express an algorithm recursively; if the performance is acceptable, maintainability counts for a lot
simple recursive solutions typically do not keep state, which means they are trivially parallelizable, which is a major advantage in the multicore era
compiler optimizations frequently negate the drawbacks of recursion
I don't see how the recursions (other than the last one which returns
0) return values without uncommenting line 3.
It's undefined behavior to comment out line 3. Why would you do that?
Yes, the parameters and local variables are local to each invokation and this is usually achieved by creating a copy of each invokation variables set on the program stack. Yes, that consumes more memory compared to an implementation with a loop, but only if the problem can be solved with a loop and constant memory usage. Consider traversing a tree - you will have to store the tree elements somewhere - be it on the stack or in some other structure. Recursion advantage is it is easier to implement (but not always easier to debug).
If you comment return sum; in the second branch the behavior is undefined - anything can happen, expected behavior included. That's not what you should do.

Resources