Moshiur Rahman
Moshiur Rahman

Reputation: 133

Does every function get its own stack in c?

I recently learned about stacks, so I was experimenting to see what the stack size is and what happens when it overflows. I found out that on Unix the default stack size is 8 MiB, and that supports my findings since I cannot declare a string having size greater than or equal to 8 MiB in my main function. However, when I declare a variable in main() it affects other functions. For example:

#include <stdio.h>

void foo(void)
{
    long int size = 1024*1024*2;
    char str[size];
    str[size - 1] = 'a';
    printf("%c\n", str[size - 1]);
}

int main(int argc, char** argv)
{
    long int size = 1024*1024*6;
    char str[size];
    str[size - 1] = 'a';
    printf("%c\n", str[size - 1]);
    foo();
    return 0;
}

This code results in segmentation fault but if I make the string size 5 MiB in main() then there is no segmentation fault. Does that mean my C program cannot allocate more than 8 MiB of RAM for local variables (of all functions)? If so, what IS the point of stacks?

Upvotes: 5

Views: 3438

Answers (4)

Abhishek Bhagate
Abhishek Bhagate

Reputation: 5786

No, each function doesn't get its own independent stack space. There's only one stack in your program and there's an limited finite amount of stack space available to you.

How Stack works

This LIFO behavior is exactly what a function does when returning to the function that called it.

Flow in the Stack

  1. The caller pushes the return address onto the stack
  2. When the called function finishes its execution, it pops the return address off the call stack (this popped element is also known as stack frame) and transfers control to that address.
  3. If a called function calls on to yet another function, it will push another return address onto the top of the same call stack, and so on, with the information stacking up and unstacking as the program dictates.

All of the above process happens in the same stack memory. Each function does have its own space in the stack but every function gets its space allocated in the same stack. This is called the Global Call Stack of your program. It is used to store local variables which are used inside the function.

However, dynamically allocated space is stored on the heap. Heap is used to store dynamic variables. It is a region of process’ memory. malloc(), calloc(), resize() all these inbuilt functions are generally used to store dynamic variables.

As for the stack overflow issue, the call stack size is limited. Only a certain amount of memory can be used. If many function calls happen, the stack space would eventually run out which would give you a stack overflow error which would most likely cause your program to crash.

If there are a lot of variables in your function or some variables which needs a huge amount of space in your program, then the stack space will eventually run out and it would cause a stack overflow. E.g. the following would probably give stack overflow in most cases and cause your program to crash:

int main() {
   int A[100000][100000];
}

Hope this clears your doubt !

NOTE:

In an multi-threaded environment, each thread gets its own call stack space separately instead of having the same Global Call Stack. So, in an multi-threaded environment, the answer to your question will be YES.

Upvotes: 7

Caleb
Caleb

Reputation: 125007

Does that mean my c program cannot allocate more than 8MB of ram for local variables (of all functions) ?

Yes and no. Yes, your program can't use more space for local variables than the available stack space, whatever that is. But no, you're not limited to 8MB for all functions, you're only limited to that much total stack space for functions that are currently executing. A program might contain thousands of functions, but only a relative handful of those will be invoked at any given moment.

When your program calls a function, space is reserved on the stack for the function's return value and it's local variables. If that function calls another function, space will then be reserved for that next function's return value and local variables. When each function returns, the return value is read and the local variables and return value are popped off the stack. So functions only use stack space while they're executing.

If so, what's the point of stacks ?

The point is to provide the space needed for local variables, to facilitate returning a value to the caller, and to make allocating that space fast and efficient. Functions don't typically need huge amounts of storage for local variables, so 8MB is typically more than enough.

If you find that you need to allocate a large amount of memory, there are memory allocation functions that make that easy. Let's say you need to create a multi-megabyte string as in your example. You'd typically use a function like malloc() or calloc() to create that object on the heap instead of on the stack, and the only local variable you'd need is a pointer to the allocated memory.

Upvotes: 2

0___________
0___________

Reputation: 67721

C language standard does not know anything about the stack. How function are called, how parameter are passed and where automatic storage objects are stored is up to implementation.

Most of the implementation will actually have only one stack but I will give you some very common exeptions.

  1. RTOSes. Many RTOS-es implement tasks as normal functions. Functions which are separate tasks will have separate stacks.
  2. Many multitasking libraries (like pthread) will give threads (which are functions) separate stacks.
  3. Many hardware designs have more than one stack - for example very popular ARM Cortex uCs - having two separate hardware stacks.

etc etc.

Upvotes: 1

Ben Zotto
Ben Zotto

Reputation: 71048

The "stack" is one, shared space in memory, and true to its name, every nested function invocation "pushes" a new "frame" (set of space for local variables) onto that shared stack. Yes, the total size of the stack's space in memory is shared between all functions which are (currently) executing, and if the total used space during the run of you program exceeds what the OS has set aside for it, you will cause an (ahem) "stack overflow" crash.

The point is to provide work space for each function's invocation. Typically, the amount of space used by any particular function on the stack is quite small-- perhaps some integers or a couple smallish arrays, etc. Think tens or hundreds of bytes, not usually kilobytes or certainly megabytes. This is mostly just idiomatic and you get used to what makes sense to have on the stack and what doesn't when you've worked with enough code of your own and others'. It would be exceptionally unusual in production code to have something megabytes large as an actual local variable.

In practice, the primary cause of stack overflow errors in the real world is accidental infinite recursion-- when you end up calling through into the same functions over and over without a recursive base case. Those stack frames may each be small, but if the call chain is unbounded eventually you'll overflow.

When you want to use actual larger pieces of memory, large string buffers, etc, you'll typically allocate them from a different shared chunk of memory referred to as "the heap". You can allocate (with malloc and its cousins) what you need and then free that when done. The heap's memory space is global to your program, and is not constrained or related to particular function invocations.

Upvotes: 1

Related Questions