Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why, or when, do you need to dynamically allocate memory in C?

Dynamic memory allocation is a very important topic in C programming. However, I've been unable to find a good explanation of what this enables us to do, or why it is required.

Can't we just declare variables and structs and never have to use malloc()?

As a side note, what is the difference between:

ptr_one = (int *)malloc(sizeof(int)); 

and

int *ptr_one = malloc(sizeof(int)); 
like image 879
user2517777 Avatar asked Aug 13 '13 19:08

user2517777


People also ask

Why do we need dynamic memory allocation in C?

Dynamic memory allocation is a process that allows us to do exactly what we're looking to do above, to allocate memory while our program is running, as opposed to telling the computer exactly how much we'll need (and for what) ahead of time.

When should you dynamically allocate memory?

When we do not know how much amount of memory would be needed for the program beforehand. When we want data structures without any upper limit of memory space. When you want to use your memory space more efficiently.


2 Answers

You need to use dynamic memory when:

  • You cannot determine the maximum amount of memory to use at compile time;
  • You want to allocate a very large object;
  • You want to build data structures (containers) without a fixed upper size;

You don't always know how much memory you will need to set aside at compile time. Imagine processing a data file (a time series of temperatures, say), where the number of records in the file isn't fixed. You could have as few as 10 records or as many as 100000. If you want to read all that data into memory to process it, you won't know how much memory to allocate until you read the file. If the file is structured so that the very first value is the number of records, you could do something like this:

size_t recs = 0; double *temps = NULL;  FILE *fp = fopen ( filename, "r" ); if ( fp ) {   if ( fscanf( fp, "%zu", &recs ) == 1 )   {     temps = malloc( sizeof *temps * recs );     if ( temps )     {       // read contents of file into temps     }   } } 

Sometimes you need to allocate a very large object, something like

int ginormous[1000][1000][1000]; 

Assuming a 4-byte integer, this array will require 4GB. Unfortunately, stack frames (where local variables are kept on most architectures) tend to be much smaller than that, so trying to allocate that much memory may lead to a run-time error (and typically does). The dynamic memory pool (a.k.a. the heap) is typically much larger than the stack, much less any one stack frame. so for something that obnoxious you'd need to write something like

int (*ginormous)[1000][1000] = malloc( sizeof *ginormous * 1000 ); 

It's still possible for a request like that to fail; if your heap is fragemented enough, you may not have a single contiguous block large enough to hande the request. If necessary, you could do a piecemeal allocation; rows won't necessarily be adjacent in memory, but it's more likely you'll be able to grab all the memory you need:

int ***ginormous = malloc( sizeof *ginormous * 1000 ); if ( ginormous ) {   for ( size_t i = 0; i < 1000; i++ )   {     ginormous[i] = malloc( sizeof *ginormous[i] * 1000 );     if ( ginormous[i] )     {       ginormous[i][j] = malloc ( sizeof *ginormous[i][j] * 1000 );       if ( ginormous[i][j] )       {         // initialize ginormous[i][j][k]       }     }   } } 

And finally, dynamic memory allows you to build containers that can grow and shrink as you add or remove data, such as lists, trees, queues, etc. You could even build your own real "string" data type that can grow as you append characters to it (similar to the string type in C++).

like image 144
John Bode Avatar answered Oct 04 '22 06:10

John Bode


Dynamic allocation is required when you don't know the worst case requirements for memory. Then, it is impossible to statically allocate the necessary memory, because you don't know how much you will need.

Even if you know the worst case requirements, it may still be desirable to use dynamic memory allocation. It allows for the system memory to be used more efficiently by multiple processes. All processes could statically commit their worst case memory requirements, but that puts a cap on how many running processes can exist on the system. If it is never the case that all processes use the worst case at the same time, then the system memory constantly runs underutilized, which is a waste of resources.

As to your side question, you should not cast the result of a call to malloc() in C. It can hide the bug of a missing declaration (implicit declarations were permitted prior to C.99), and results in undefined behavior. Always prefer taking the result of malloc() without a cast. malloc() is declared to return void *, and in C, a conversion between void * and another pointer type is always permitted (modulo type qualifiers like const).

like image 41
jxh Avatar answered Oct 04 '22 05:10

jxh