Static memory allocation of array at compile time - c

How compiler determine the size of below array at compile time?
int n;
scanf("%d",&n);
int a[n];
How it is different from dynamic allocation(other than memory is allocated in heap for dynamic array).
If possible please, explain this in terms of activation stack memory image how this array is allocated memory.

The array's size isn't determined at compile time; it's determined at run time. At the time that the array is allocated, n has a known value. In typical implementations where automatic variables are allocated on the program stack, the stack pointer will be adjusted to make room for that many ints. It becomes parts of the stack frame and will be automatically reclaimed when it goes out of scope.
This code was not valid in C90; C90 required that all variables be declared at the beginning of the block, so mixing declarations and code like this was not permitted. Variable-length arrays and mixed code and declarations were introduced in C99.

In C the proper name for the allocation type is automatic. In computing jargon the term stack is sometimes used synonymously.
The storage of a is valid from the point of definition int a[n]; up until the end of the enclosing scope (i.e. the end of the current function, or earlier).
It is just the same as int a[50]; , except that a different number of ints than 50 may be allocated.
A drawback of using automatic arrays (with or without runtime sizes) is that there is no portable way to protect against stack overflow. (Actually, stack overflow from automatic variables is something the C standard does not address at all, but it is a real problem in practice).
If you were to use dynamic allocation (i.e. malloc and friends) then it will let you know if there is insufficient memory by returning NULL, whereas stack overflows are nasty.

Related

Static Allocation - C language [duplicate]

This question already has answers here:
Do I really need malloc?
(2 answers)
Closed 2 years ago.
As far as I know, the C compiler (I am using GCC 6) will scan the code in order to:
Finding syntax issues;
Allocating memory to the program (Static allocation concept);
So why does this code work?
int main(){
int integers_amount; // each int has 4 bytes
printf("How many intergers do you wanna store? \n");
scanf("%d", &integers_amount);
int array[integers_amount];
printf("Size of array: %d\n", sizeof(array)); // Should be 4 times integer_amount
for(int i = 0; i < integers_amount; i++){
int integer;
printf("Type the integer: \n");
scanf("%d", &integer);
array[i] = integer;
}
for(int j = 0; j < integers_amount; j++){
printf("Integer typed: %d \n", array[j]);
}
return 0;
}
My point is:
How does the C compiler infer the size of the array during compilation time?
I mean, it was declared but its value has not been informed just yet (Compilation time). I really believed that the compiler allocated the needed amount of memory (in bytes) at compilation time - That is the concept of static allocation matter of fact.
From what I could see, the allocation for the variable 'array' is done during runtime, only after the user has informed the 'size' of the array. Is that correct?
I thought that dynamic allocation was used to use the needed memory only (let's say that I declare an integer array of size 10 because I don't know how many values the user will need to hold there, but I ended up only using 7, so I have a waste of 12 bytes).
If during runtime I have those bytes informed I can allocate only the memory needed. However, it doesn't seem to be the case because from the code we can see that the array is only allocated during runtime.
Can I have some help understanding that?
Thanks in advance.
How does the C compiler infer the size of the array during compilation time?
It's what's called a variable length array or for short a VLA, the size is determined at runtime but it's a one off, you cannot resize anymore. Some compilers even warn you about the usage of such arrays, as they are stored in the stack, which has a very limited size, it can potencially cause a stackoverflow.
From what I could see, the allocation for the variable 'array' is done during runtime, only after the user has informed the 'size' of the array. Is that correct?
Yes, that is correct. That's why these can be dangerous, the compiler won't know what is the size of the array at compile time, so if it's too large there is nothing it can do to avoid problems. For that reason C++ forbids VLA's.
let's say that I declare an integer array of size 10 because I don't know how many values the user will need to hold there, but I ended up only using 7, so I have a waste of 12 bytes
Contrary to fixed size arrays, a variable length array size can be determined at runtime, but when its size is defined you can no longer change it, for that you have dynamic memory allocation (discussed ahead) if you are really set on having the exact size needed, and not one byte more.
Anyway, if you are expecting an outside value to set the size of the array, odds are that it is the size you need, if not, well there is nothing you can do, aside from the mentioned dynamic memory allocation, in any case it's better to have a little more wasted space than too little space.
Can I have some help understanding that?
There are three concepts I find relevant to the discussion:
Fixed size arrays, i.e. int array[10]:
Their size defined at compile time, they cannot be resized and are useful if you already know the size they should have.
Variable length arrays, i.e. int array[size], size being a non constant variable:
Their size is defined at runtime, but can only be set once, they are useful if the size of the array is dependant on external values, e.g. a user input or some value retrived from a file.
Dynamically allocated arrays: i.e. int *array = malloc(sizeof *arr * size), size may or may not be a constant:
These are used when your array will need to be resized, or if it's too large to store in the stack, which has limited size. You can change its size at any point in your code using realloc, which may simply resize the array or, as #Peter reminded, may simply allocate a new array and copy the contents of the old one over.
Variables defined inside functions, like array in your snippet (main is a function like any other!), have "automatic" storage duration; typically, this translates to them being on the "stack", a universal concept for a first in/last out storage which gets built and unbuilt as functions are entered and exited.
The "stack" simply is an address which keeps track of the current edge of unused storage available for local variables of a function. The compiler emits code for moving it "forward" when a function is entered in order to accommodate the memory needs of local variables and to move it "backward" when the program flow leaves the function (the double quotes are there because the stack may as well grow towards smaller addresses).
Typically these stack adjustments upon entering into and returning from functions are computed at compile time; after all, the local variables are all visible in the program code. But principally, nothing keeps a program from changing the stack pointer "on the fly". Very early on, Unixes made use of this and provided a function which dynamically allocates space on the stack, called alloca(). The FreeBSD man page says: "The alloca() function appeared in Version 32V AT&T UNIX"ยด(which was released in 1979).
alloca behaves very much like alloc except that the storage is lost when the current function returns, and that it underlies the usual stack size restrictions.
So the first part of the answer is that your array does not have static storage duration. The memory where local variables will reside is not known at compile time (for example, a function with local variables in it may or may not be called at all, depending on run-time user input!). If it were, your astonishment would be entirely justified.
The second part of the answer is that array is a variable length array, a fairly new feature of the C programming language which was only added in 1999. It declares an object on the stack whose size is not known until run time (leading to the anti-paradigmatic consequence that sizeof(array) is not a compile time constant!).
One could argue that variable length arrays are only syntactic sugar around an alloca call; but alloca is, although widely available, not part of any standard.

Why can't the size of stack be determined at compile time?

I have read that the size of heap and stack cannot be computed at compile time and needs to be evaluated at runtime.
I can think of this code which allocates heap based on user input and needs the runtime:
int size;
scanf("%d", &size):
void *ptr= malloc(size);
But aren't all the stack variables already present in a function? given their data type (int, char, long etc.) why can't the compiler calculate the size?
With C99, it is possible to create Variable length array (VLA) on the stack. Those arrays will have dynamic size based on runtime parameters, or calculated expressions. In those cases, not possible to calculate stack size until runtime.
For example:
int f(int n) {
// Size based on input
int x[n] ;
// Dynamic size
int m = n+5000 ;
int y[mm] ;
};
Needless to say that if the allocation of a single function can not be calculated, it is not possible to calculate the stack size of a complete program
Stack memory is allocated at the entry of the function. That's why the stack size depends on the sequence of function calls, which is not defined at compile time (e.g. any if, switch can change the function call sequence)
Why can't the size of stack be determined at compile time?
But aren't all the stack variables already present in a function?
2 things that prevent compile time stack size computation:
Variable logic arrays allow for a run-time determined amount of memory usage of the "stack". Other non-standard functions like alloca() do so also.
Recursion allows for a run-time determined depth of function calls and thus a run-time determined amount of memory usage even if each function memory usage was constant. #Weather Vane
Were it not for these 2 and maybe others, code could be analysed at compile time to determine stack usage, max function depth and then possible not even use a "stack" in classic sense, storing all "stack" memory in a fixed space. Some compilers provide for this. e.g.
recursive functions need the stack size to be dynamic I believe.
And also some versions of C allow variable length arrays

I'm little bit confused that whether automatic memory allocation takes place during run time or compile time

I know that the memory is allocated at compile time to auto variables like int a; and are stored in stack but in case of a variable array whose input is taken from the user, for eg
#include<stdio.h>
main()
{
int n;
printf("enter the size of array");
scanf("%d",&n);
int a[n];
.......
}
the memory is allocated at run time. So my question is, is the automatic allocation is case dependent or not. THANKS
In your example, it is unclear where "a" is defined. So, I'll take a stab at answering this by making assumptions on that.
If the array is declared as a global array, it resides in the bss segment, and memory is allocated as the segments are loaded into memory.
If the array is on the stack, and the size of the array is known at compile-time, the stack pointer is moved to allocate space for the array. You can see this if you disassemble the code.
If the array is on the stack, but space is allocated based on an argument to the function you have a VLA(variable length array). These are commonly converted to "alloca" calls by the compiler. In this case the stack pointer is just moved to allocated "n" bytes on the stack.
If the array is on the heap, the allocations are performed by the heap allocator in use.
The code that handles the automatic allocation is created at compile-time. The actual allocation takes place in run-time. You'll have machine code such as "push variable on stack" or "put variable in register", but this code is of course doing nothing until the program is executed. All stack allocations are done in run-time. They may or may not be of a deterministic nature.
In the case of a VLA, the instruction "move stack pointer n steps" is created at compile time, but the variable n is set in run-time and the stack pointer is then moved accordingly, to allocate memory.
The only kind of allocation that takes place at compile-time is allocation of objects with static storage duration - meaning allocation of file scope variables and static variables. Room for these are reserved in the data segments usually named .data and .bss on most systems.
Examples can be found here.

Is it necessary to use new for dynamic memory allocation?

In C, we can input the size of an array (at runtime) from the user by the concept of dynamic memory allocation. But we can also use
int n;
scanf("%d",&n);
int a[n];
So what is the need of using pointers for dynamic memory allocation using new?
What you have shown is called variable length array supported from C99.
Yes based on the input you are allocating memory. What if you want to extend the allocated memory.
Don't you need pointers now? In order to do realloc() . This is one scenario I can think of but we need pointers for dynamic memory allocation.
C doesn't have new so my answer is specific to C which has malloc() and family functions
If you have a function to allocate memory dynamically say
int *alloc_memory()
{
int n;
scanf("%d",&n);
int a[n];
// Fill values to array and do
return a;
}
Now this will lead to undefined behavior as the allocated memory just has scope of the function. Pointers are useful for this purpose
int *alloc_memory()
{
int n;
scanf("%d",&n);
int *p = malloc(sizeof(int) * n);
// Fill values
return p;
}
The point is VLA doesn't provide the flexibility which dynamic memory allocation by pointers provide you.
Variable length array came into existence after C99 standard. Before that, there was no concept for VLA. Please note, moving forward, since C11, this has been changed to an optional feature.
OTOH, dynamic memory allocation using malloc()## and family was there from long back.
That said, the VLA is still an array and usually, an array and a pointer are not the same. Array holds type and size information, while a pointer does not have any size information.
Also, FWIW, the array size can be defined at runtime, but that does not change the scope and lifetime as compared to normal arrays. Just using VLA approach does not change the lifetime of an otherwise automatic array to global or something else.
## There is no new keyword in C. GLIBC provides malloc() and family of APIs to handle dynamic memory allocation.
Using a VLA is conceptually similar to calling alloca to allocate automatic mmory.
A few differences between a Variable Length Array (VLA) and dynamically allocated memory using malloc:
1) The VLA is an automatic variable that will cease to exist when your function returns. Whereas dynamically allocated memory with malloc will exist until free is called or your program exits.
2) For data types other than arrays, such as structs, you probably want allocated with malloc.
3) The VLA is typically stored on the stack (although this is not strictly required by the C99 specification), whereas dynamically allocated memory with malloc is stored on the heap.
You are not doing any "dynamic memory allocation", i.e. allocation of memory with dynamic lifetime. You are using "variable-length arrays" in C99. But it's still a local variable, with "automatic storage duration", which means the variable's lifetime is the scope in which it was declared.

Dynamic Array using const int

This is also a valid code to declare dynamic arrays.
malloc needs pointers, this doesn't. Is this a better method?
printf("enter the size of array")
scanf("%d",&x)
const int size
size = x
int array[size]
It is hard to say if one is better than the other, a better question would be what are the advantages of each, you need to decided based on your requirements but using malloc and using variable length arrays(VLA) are not the same.
There are some major differences.1) A VLA will usually be allocated on the stack although that is an implementation decision, the standard just says there are automatic. The stack is more limited than the the heap which is where a malloc'ed array will go and so you can easily overflow your stack. 2) You need to free a malloc'ed array a VLA is an automatic variable and will not exist outside of the scope it is declared in. 3) VLA is part of the C99 standard and so code using VLA will not be portable.

Resources