Difference between lifetimes of variables created on stack and heap? - c

i know that heap is used in case of dynamic memory allocation otherwise stack is used.
i have tried Difference between static memory allocation and dynamic memory allocation
i know the difference but confusion is about their lifetimes.

First of all, stacks and heaps are implementation details (the words "stack" and "heap" do not appear anywhere in the C language standard). Instead, the standard talks about storage durations for objects (Section 6.2.4).
As of C2011, there are four storage durations: static, automatic, thread, and allocated.
Objects with static storage duration have lifetimes1 that extend over the lifetime of the program. That is, memory is set aside for them when the program is loaded, and that memory is released when the program exits. Objects declared at file scope (outside of any function) or with the static keyword have static storage duration. Storage for static objects is usually allocated from within the binary image itself (for ELF, this would include the .data, .rodata, and .bss sections); that is, something other than a stack or heap.
Objects with automatic storage duration have lifetimes that extend from the entry of the block in which they're created until the block exits2. If the block is entered recursively, a new object is created. Objects declared within a block without the static keyword have automatic storage duration. Objects with automatic storage duration are usually allocated from a runtime hardware stack, although not all architectures have a stack.
Objects with thread storage duration have lifetimes that extend over the execution of the thread for which they were created. Objects declared with the _Thread_local keyword have thread storage duration. I think thread-local objects are allocated in the same way as auto variables, but that may be wrong; I've never used C2011 native threading, so I can't say for sure.
Objects with allocated storage duration have lifetimes that extend from the time they are allocated with malloc, calloc, or realloc until they are explicitly deallocated with a call to free. Objects with allocated storage duration are usually allocated from the heap (although not all architectures will have a heap as such). Where things get confusing is distinguishing the allocated object from the object that points to it. Given the following code:
int *foo( void )
{
int *bar = malloc( sizeof *bar * 10 );
// do stuff with bar
return bar;
}
void bletch( void )
{
int *blurga = foo();
// do stuff with blurga
free( blurga );
}
We've allocated three objects. In the function foo, we allocate a pointer object (referred to by the variable bar) with automatic storage duration; its lifetime is the lifetime of the function foo. In the function bletch, we allocate another pointer object (referred to by the variable blurga) with automatic storage duration; its lifetime extends over the lifetime of the function bletch.
The third object is a buffer large enough to hold 10 int objects. Its lifetime extends from the malloc call in foo to the free call in bletch; its lifetime is not tied to the lifetime of any function or block.
1. The lifetime of an object is the time within a program's execution that storage is guaranteed to be reserved for that object. Note that the lifetime of an object is distinct from the scope of the identifier that refers to that object. Even though memory for the object may be allocated at block entry, the scope of the identifier that refers to it may be more limited.
Assume the following code:void foo()
{
printf( "entered foo\n" );
int i = 0;
while ( i < 10 )
printf( "%d\n", i++ );
}
The scope of the variable i extends from the end of its declaration until the end of the block; however, the lifetime of the integer object i refers to extends from block entry until block exit.
2. In practice, most compilers will set aside storage for all block-scope variables at function entry, even though some may be local to a block within the function. However, it's best to assume that the lifetime of an auto object only extends to the block in which it is contained.

Stack variables have local scope, meaning they are only valid to de-reference within the pair of {} where they were declared. While a dynamically allocated variable is valid until the point where your program calls free().
A more correct name would be local variables, since local variables may also end up allocated in CPU registers and not always on the stack. Formally, they are called variables with automatic storage duration in the C standard, meaning that the compiler automatically decides which is the best place to allocate them at.

Related

Is it possible to initialize a struct within a function in C without dynamic memory allocation such that it persists after the function returns?

I am currently building a dynamic memory management class in C for a school project. As part of the initialization for my heap I want to initialize a Block struct into the free memory list. I cannot use dynamic memory allocation to do this (as it is against the rules). This design is entirely of my own creation, so my approach may just be flawed. Is it possible to do? Code below will clarify exactly what I am trying to do. Based on my understanding of how C handles variables, the memory location for newBlock will be up for grabs as soon as the function ends which could lead to issues later if it is overwritten.
int mm_init()
{
// Initialize memory. Don't worry about this.
mem_init();
// Initialize the heap.
// Also don't worry about this.
list_init(heap.freeBlocks);
list_init(heap.allocatedBlocks);
// Here is where the question applies.
Block newBlock = //initialize the block.
// freeBlocks is a pointer to a list struct.
list_insert(heap.freeBlocks, &newBlock);
// Don't worry about this either.
return -1;
}
You need to make sure the variable has what's called static storage duration.
Static storage duration means that the object will be allocated in one fell swoop along with other objects with static storage duration at program start and will never be deallocated as long as the program lives.
There are 3 ways to give a C object the static storage duration.
Make it global -- this will make it accessible from other translation units as well
Block newBlock;
int mm_init() {
/* ... */
}
Make it global and mark it static -- this will make the identifier only accessible from the current translation unit
static Block newBlock;
int mm_init() {
/* ... */
}
Make it local and mark it static -- this will prevent the identifier from being accessible outside its enclosing function
int mm_init() {
static Block newBlock;
/* ... */
}

global declaration is in stack or heap?

I need to declare a variable that is not in the stack memory but in the heap, like below
struct mystruct *name;
Should I declare it outside all functions (even outside main()) at the begin of file?
Please note that a variable is never declared "on the heap". Only memory pointed to by a pointer can be allocated on (from) the heap.
In your example, you can declare name indeed outside any function and then it will exist in global memory. You can also delcare the variable inside a function, preceded by the keyword static. This latter will allocate the variable also in global memory, but it will only be visible in the function where you declared it.
To use your pointer variable, you now must alocate memory for it to point to, which you allocate on the heap using malloc.
TL;DR Version
You cannot declare a variable such that the variable itself lives on the heap.
James Michener Version
The C language definition doesn't talk about stacks or heaps; it talks about storage durations.
Objects with auto storage duration (anything declared within a block and without the static keyword) have lifetimes that extend from the beginning of that block and end when the block exits1:
void foo( void )
{
int a = 0; // lifetime of a extends to the end of
// the function
for ( int i = 0; i < 10; i++ ) // lifetime of i and b extend to the end
{ // of the for loop
int b = a + i;
printf( "b = %d\n", b );
}
}
Most implementations allocate storage for auto objects from the hardware stack, because a stack makes that behavior easy to implement2.
Objects with static storage duration (anything declared outside of a function or with the static keyword) have lifetimes that extend from the time the program is loaded into memory until the program exits:
int a = 0; // lifetime of a extends over the lifetime of
// the entire program
int main( void )
{
static int b = 10; // lifetime of b also extends over the lifetime
// of the program, but is only visible within
// main
...
}
Most implementations will set aside storage for static objects within the body of the executable itself (for an executable using the ELF format, such objects will be stored in the .bss, .data, or .rodata sections of the image).
Objects with allocated storage duration (anything allocated with malloc, calloc, or realloc) have lifetimes that extend from the time that they are allocated until they are explicitly deallocated with a call to free.
int *foo( size_t size )
{
int *ptr = malloc( sizeof *ptr * size );
return ptr;
}
void bar( void )
{
int *p = foo( 10 );
// do something with p
free( p );
}
The variables ptr and p only exist for the lifetimes of their respective functions, and they will be typically allocated from the stack. The object both variables point to exists from the time it is allocated with malloc until it is deallocated with free.
Most implementations allocate storage for allocated objects from the heap.
There's really no way for you to declare an object that has allocated storage duration; the only way you can create such an object is via malloc, calloc, or realloc. Whatever object you declare to store the pointer value returned by any of those functions will have either auto or static storage duration.
1. In practice, storage for all local objects is allocated at function entry and released at function exit, regardless of whether the object's lifetime is over the entire function or limited to a block within the function. However, you should never rely on that storage being accessible outside of that object's lifetime. For example, the lifetimes of i and b are limited to the for loop; even though the storage for each may have been allocated at function entry, you should not attempt to access that storage outside of the loop body.
2. C was designed on a machine with a stack, after all.

What is the purpose of declaring the array as static in the function?

I have created a function (eg: fun()) and called it from the main function.I have also created an array in the function and I am returning the base address of the array to an integer pointer in the main function.If the array is declared as static in the function fun(),the array elements are properly displayed in the main function.If not,some garbage values are being printed.But the vice versa of this is working fine.That is,decalring an array in the main function and printing it in an another function by passing the base address.So what is the use of declaring the array as static?What is the correct explanation for it?
If an object is declared static in a function, it is essentially a global and permanent, and is not re-initialized every time the function is called like other local variables.
If you have a non-static object which is local to a function, and you return its address, by the time the caller does something with the address the object has gone out of scope because you are no longer in the body of the called function, and the region of memory your pointer refers to has undefined data in it, regardless of what you put there before. If the object was static then it does not fall out of scope.
If you have an object local to main, and you call a function from main and pass a pointer to this object, that object is still alive as far as the program is concerned, because you are still "in" the main function, and will return to it when you leave the body of the called function, so there is no problem referring to that region of memory. This has nothing to do with main: try the same thing from a different function.
Incidentally, none of this has anything to do with arrays, and the whole discussion applies to any kind of object.
If array declared as static then the array remains alive even after the execution of the function call and hence you can access the elements of the array.
Actually, static arrays are allocated in a different section of memory and is not allocated in the function stack frame. So it does not matter even if the function call is over, the array is still there.
If you do not declare the array static, then the array "disappears" when you leave the function. In fact, all of the variables that you declare in a function that are not static only exist as long as the function is executing. After return from the function, the variables are de-allocated from the heap. This is called the "scope" of a variable, the area in the code where the variable exists.
In your case, you are returning a pointer to an area where your array once was, when the function was executing, but by the time that the main uses the pointer, the area where the array once was has been overwritten.
Objects can have one of three storage durations: auto, static, or dynamic.
Objects with auto storage duration have storage allocated for them immediately following the point they are defined, and that storage is only held for the duration of the current scope; once that scope is exited, the object ceases to exist. For example:
void foo( int x ) // storage for x is set aside here
{
int bar; // storage for bar is set aside here
if ( x > 0 )
{
int i; // storage for i is set aside here
...
} // storage for i is released here
} // storage for x and bar is released here
The variable i only exists within the scope of the if statement; bar and x only exist within the scope of the function. Once the function exits, none of those variables exist anymore, and any storage allocated for them is now available for someone else to use1.
Objects with static storage duration have storage allocated for them when the program starts, and that storage is held until the program exits. Anything declared at file scope (outside of any function) or with the static keyword has static storage duration:
void foo( int x ) // storage for x is set aside here
{
static int bar; // storage for bar was set aside at program start
...
} // storage for x is released here; storage for bar will
// be released when the program exits
This is the reason you see the behavior you do; when the array is not declared static, the storage for it is released after the function exits, and someone else is free to overwrite it. When you declare it static, that storage is held until the program exits, so noone else can use it.
Objects with dynamic storage duration are allocated manually using malloc, calloc, or realloc, and held until explicitly released with free.
1. In practice, the storage for x, bar, and i is usually set aside at function entry and held until the function exits, but logically speaking you can't expect there to be any storage for i outside the scope of the if statement, meaning any pointers to i would not be valid outside of the if statement.

Allocating an Array of Structs without Malloc?

I have a struct defined in this way.
typedef struct COUNTRY {
char Code[3];
char Country[30];
int Population;
float Expectancy;
struct Country *Pointer;
} COUNTRY;
I have seen an array of structs allocated like this:
COUNTRY *countries = calloc(128, sizeof(COUNTRY));
or maybe like this:
COUNTRY *countries = malloc(128 * sizeof(COUNTRY));
But what does this do:
COUNTRY countries[128] = {};
Because I am still able to write to each entries' fields in all cases. Is the third option just bad form? It seems better to me because you can put that line up with the rest of your variable declarations outside of main(). Otherwise, you can only calloc() or malloc() inside of main() or other function.
Am I doing something wrong?
This:
COUNTRY countries[128];
simply defines an object whose type is "array of 128 COUNTRY elements".
The = {} is an initializer -- but empty initializers are illegal in C (I think gcc supports them as an extension). A portable alternative is:
COUNTRY countries[128] = { 0 };
which initializes all members of all elements to zero (0 for integers, \0' for characters, 0.0 for floating-point, NULL for pointers, and recursively for sub-elements). But since you specified the number of elements in the array (as 128), the initializer has no effect on how the array object is allocated.
If the declaration occurs inside a function definition, the array object has automatic storage duration, which means that it ceases to exist when execution reaches the end of the enclosing block. Such objects are commonly allocated on "the stack".
If it occurs outside any function definition (at file scope) or if it has the keyword static, then it has static storage duration, which means that it continues to exist for the entire execution of the program.
Objects allocated with malloc or calloc have allocated storage duration, which means that they continue to exist until they're explicitly deallocated by a call to free(). Such objects are commonly allocated on "the heap". (I'm ignoring realloc(), which complicates the description a bit.)
The first two statements will allocate array of structs on the heap, while the last one will initialize the array of structs on the stack.
It is not a bad form, it is just a matter where you want your data to be stored - on the stack ( freed automatically when your variable goes out of the scope, stack usually have significantly smaller size then heap, so you could overflow it if you place big data structures there), or on the heap (lifetime of data is not related to the scope, you need to manually free your memory).
It seems better to me because you can put that line up with the rest of your variable declarations outside of main().
If you need statically allocated object with the lifetime of the program, use this approach, there's nothing wrong with it. Please note that in this particular case, variable is not stored on the stack, but in the .data segment of your program (check this question for more details: How are global variables stored?).
The last form is 'stack allocated' or 'statically allocated'. Like calloc, all of the fields will be zeroed out.
Inside a function it is 'stack allocated' and that memory will go away when the function returns.
Outside any function, at file scope, it is statically allocated and a global piece of memory allocated before main() starts.
malloc/calloc are used when you don't know how many you need at compile time. For example in a linked list, you need to allocate/deallocate nodes on the fly. When you use an array, you the know exactly how many you need at compile time.
What also differs is where the memory is taken from. If you declare an array in a function, the memory will be taken from the stack. In the case of malloc/calloc, the memory is set aside in the heap.
= {};
is GNU C extension and is the same as:
= {0};

which variable parts are stored to the stack in this code?

I have this following code and I don't really understand which variable parts in the test_function are stored onto the stack segment?
In the book it says "The memory for these variables is in the stack segment", so I presume it is when the variables are actually initialized to a value. Right?
void test_function(int a, int b, int c, int d) {
int flag; //is it this
char buffer[10];// and this
//or
flag = 31337; //this and
buffer[0] = 'A'; //this. Or all of it?
}
int main() {
test_function(1, 2, 3, 4);
}
The various C standards do not refer to a stack, what it does talk about is storage duration of which there are three kinds(static, automatic, and allocated). In this case flag and buffer have automatic storage duration. On the most common systems objects that have automatic storage duration will be allocated on the stack but you can not assume that universally.
The lifetime of automatic objects starts when you enter the scope and ends when you leave the scope in this case your scope would be the entire function test_function. So assuming there is a stack then buffer and flag in most situations that I have seen there will be space allocated on the stack for the objects when you enter the function, this is assuming no optimization of any sort.
Objects with automatic storage duration are not initialized explicitly so you can not determine their initial values you need to assign to them first.
For completeness sake, the various storage durations are covered in the C99 draft standard section 6.2.4 Storage durations of objects paragraph 1 says(emphasis mine):
An object has a storage duration that determines its lifetime. There are three storage
durations: static, automatic, and allocated. Allocated storage is described in 7.20.3.
Lifetime for automatic objects is covered paragraph 5 which says :
For such an object that does not have a variable length array type, its lifetime extends
from entry into the block with which it is associated until execution of that block ends in
any way.[...]
flag, buffer, and a,b,c,d will be on the stack (well compiler may just remove all the code and call it dead code since it's unused).

Resources