Dynamic Memory Allocation With malloc In C

Memory allocation on the fly can be done using the malloc function call. This is usually done when a dynamic amount of memory is required that cannot be decided prior to program execution. Malloc is the way to achieve this. The programmer must be diligent in allocating the correct amount of memory, type cast it appropriately, and remember to free it after usage. Otherwise this memory may be leaked during execution.

This article will outline the usage of malloc, how to free that memory after the fact, and how to avoid dangling pointers and invalid memory access.

How Do I Allocate Memory?

Most people are familiar with allocating an array of 10 integers:

int data[10];

But what if we actually need 12 integers or 15, what then? This is where malloc comes in. Its defintion is:

void *malloc(size_t size);

malloc return a void *, meaning we can cast this memory to whatever type we need. It takes a size as its argument, in this case the number of bytes we need. Here is an example of allocating 12 integers. If you want more examples of using fprintf follow this link.

#include <stdio.h>
#include <stdlib.h>
 
int main()
{
        int *data_ptr;
        data_ptr = (int *)malloc(sizeof(int) * 12);
 
        if(data_ptr == NULL){
                fprintf(stderr, "Could not allocate memory.\n");
                return -1;
        }
 
        data_ptr[0] = 5;
        data_ptr[1] = 3;
 
        fprintf(stdout, "%u\n",data_ptr[0]);
 
        // Cleanup our allocated memory
        free(data_ptr);
        data_ptr = NULL;
 
        return 0;
}

There a few things to note in this example:

  1. Malloc returns NULL on error. This must be checked! Do not just point randomly.
  2. I reference our pointer using the same syntax as if I allocated the memory statically.
  3. During our cleanup I call free. free() returns no error, and takes the pointer in which memory was allocated to.
  4. I set the pointer to NULL after I free the memory. This ensure no dangling pointer.

Allocating memory can be done for any type required, as behind the scenes you are simply allocating bytes. In the example above we used the sizeof function. This is imperative that we use this function, because in some cases a long is 8 bytes on one system where a long on another system is only 4 bytes. When we use sizeof we let the system tell us how the size of the type, and thus we multiply it by how many of those we need. In our example we needed 12 integers, without having to know the actual byte size behind the scenes.

If you want to do something more complicated, you can try dynamically allocate structures using malloc.

C ‘sizeof’ Operator Explanation and Examples

The sizeof operator is used immensely in C. I use it every time I allocate memory dynamically. For the longest time I thought it was a function, and always found it strange that it was never defined in a manual page. Further investigation showed me that sizeof is an operator that is specific to your compiler (which makes sense) when you think about how a program is built. During compile time, the compiler determines the type passed in and will return the size of that type in bytes.

sizeof is a unary operation, meaning it takes only one operand or argument.

Here is an example program using sizeof for differing data types, including a structure with an array.

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
 
struct data_len {
        char data1;
        int data2;
        long data3;
        double data4;
        int data5[10];
};
 
int main(int argc, char **argv)
{
        // Examples of the sizeof operator.
        fprintf(stdout, "%zu\n%zu\n%zu\n%zu\n%zu\n%zu\n",
                        sizeof(char),
                        sizeof(int),
                        sizeof(double),
                        sizeof(long),
                        sizeof(unsigned int),
                        sizeof(struct data_len)
                        );
 
        return 0;
}

The output:

$ ./sizer
1   // char
4   // int
8   // double
4   // long
4   // unsigned int
60  // structure of sizes char + int + long + double + (int x 10)

This is a handy and necessary operator to have, especially for figuring out how many bytes you need when allocating memory on the fly. Even more importantly, a long on a 32bit architecture differs from a long on a 64bit machine so if you statically decided that a long was 4 bytes and allocated memory based on that then moved your code to a 64bit architecture your calculations would be off. This is where buffer overflows can occur. If you had allocated based on a long being 4 bytes then went to a 64bit architecture (where a long is 8 bytes), every reference to the long would automatically fill the other 4 bytes and your data would be overflowing into who knows where.

A cool trick with sizeof is it can be used to find the length of an array. At first you might think well..I know what the length of the array is since I declare it. But if you are making an array dynamically, you won’t know what the size of that array is until you have allocated the space. What you can do in C is:

int *dptr, len;
 
// Allocate as many integers as passed in from the command line
dptr = (int *)malloc(sizeof(int) * atoi(argv[1]));
 
len = sizeof(dptr) / sizeof(dptr[0]);

This length check is only safe to do, as long as dptr is defined within the same scope as the calculation. Otherwise, if you pass dptr to a function, depending on your architecture, the len may be calculated on a pointer rather than the object itself and thus give you the wrong values.

A common mistake that arises with the use of sizeof, is when sizeof() evaluates on a pointer to say an array, rather than the array itself. If we have two strings, with one as a const char *str_ptr and the other as const char str[] = “howdy” then do a sizeof on both, the const char *str_ptr will always return 1, but if we did a sizeof(arr), then we will get back 6 bytes because we have six characters including the endline character. You have to pass in the actual array rather than a pointer to one.

What cool tricks have you done with sizeof?