Consider this example
Code:
#include <stdio.h>
#include <stdlib.h>
int data[10] = { 0,1,2,3,4,5,6,7,8,9 };
char large[1000];
int main ( ) {
void *p = malloc(100);
printf("%d %d\n", data[0], large[0]);
free(p);
}
$ gcc foo.c
$ size a.out
text data bss dec hex filename
1600 672 1032 3304 ce8 a.out
When the OS is told to load and run the program, it examines this information about your program.
text is where your program code resides. 1600 bytes(*) is allocated by the OS and initialised with the program code from the file. In most OS's, this is made read-only/executable after initialisation.
data is where initialised data (such as the array called data) resides. This too is copied from the file.
bss is also for data, but for anything which is default initialised to all zeros (such as the array called large). Only the size is stored in the file, as it's pointless to read a whole bunch of zeros when all the OS has to do is memset.
Behind the scenes, you also get a stack and a heap for runtime use (calling functions, allocating memory).
So at the point your main starts executing, the OS has allocated and initialised memory for your program code, your global data, given you a stack and created a heap for future dynamic memory allocations.
This you immediately make use of by calling malloc.
(*) sizes are typically rounded up to some multiple of the page size.