Black Friday Black Friday
Black Friday ultimate sale! Get up to 80 % extra free points! More information here

Lesson 2 - Dynamic memory allocation in the C language

C and C++ The C language Dynamic memory allocation Dynamic memory allocation in the C language

In the previous lesson, Introduction to pointers in the C language, we introduced the C language pointers. We already know that C lets us manage memory and we learned to pass function parameters by reference. The real C programming will start for us with today's tutorial. We're going to understand how memory allocation works and we'll break out of all length limits of static arrays and strings.

Static and dynamic memory allocation

As we know, our program has to ask the operating system for memory, which is not quite easy, and that's why C is trying to make the most of the work for us.

Statically allocated memory

When our program is being compiled, the compiler can easily determine how much memory it'll needed in a large number of cases. When we create an int variable, C knows it should allocate 32 bits for it. When we create a 100-character array, C again knows that it should reserve 800 bits. If there's no need to add any data when the program is already running, this automatic allocation is enough. This is basically the way we have been programming so far.

Dynamically allocated memory on the stack

It might crossed your mind how memory allocation for local variables (variables defined within functions) works in C. C doesn't know how many times we're going to call a function and therefore how many variables will be needed in the end. This memory is really allocated dynamically at runtime. But everything happens automatically again. Every time we call a function, C asks for memory and, when the function terminates, this memory is freed. This is why functions can't return arrays created in them. This is because, as we already know, arrays are not copied (are not passed as values like e.g. ints), we work with them as if they were pointers. And since the local variables will be destroyed once a function terminates, we'd get a pointer pointing somewhere where no array may no longer exist.

Dynamically allocated memory on the heap

So far, it looks like C does everything for us. So where's the problem? Imagine that you are programming an application that registers items in a warehouse, for example. Do you know in advance how big array you should create for the items? Will there be 100 items, 1000, millions? If we declared a static array of some structures, we'll either waste space or risk that the reserved array won't be enough. And we don't even have to go to extremes, just think about how to store a string exactly as long as the user has entered it.

The problem is that sometimes we don't know how much memory we're going to need until running the program, so C can't allocate it for us. Fortunately, we have functions available that allow us to ask for any amount of memory at runtime.

The terms stack and heap were mentioned in the text. Those are two types of the RAM memory that the program works with. In a simplified way, we can say that working with the stack is faster, but it's limited in size. The heap is primarily designed for larger data, e.g. for the mentioned items of the warehouse. When we ask for memory ourselves, it'll always be allocated on the heap.

Dynamic memory allocation

The key when working with dynamic memory in C is a pair of functions - malloc() and free().

malloc()

malloc() asks the operating system for any amount of memory (we specify how much we need in bytes as the function parameter). The function returns a pointer to the first address where our new memory starts from. We already know that every pointer is of a certain type, in other words it points to data of some type. To make malloc() universal, it returns a pointer to the void type. We should always cast its result to the pointer type we need.

If the memory allocation fails (for example we run out of memory, theoretically it shouldn't happen nowadays, but we should think about this case too), malloc() returns NULL (a pointer to nowhere). When allocating memory, we'll always use the sizeof() function since we never know how large a certain data type is on a particular operating system is (e.g. int can occupy either 16 or 32 bits). sizeof() calls are replaced with constants by the compiler so it doesn't affect the program speed in any way.

free()

Each time we call malloc(), we must call somewhere (even at the end of the program) the free() function to mark the memory as free again. This memory is fully in our hands and no one other than us will free it for us. As soon as we stop using some dynamically allocated memory, we should free it immediately.

Let's allocate memory for 100 ints at runtime:

int main(int argc, char** argv) {
    int *p_i;
    printf("Trying to allocate memory for 100 ints.\n");
    // Allocation of 100 times the size of int
    p_i = (int *) malloc(sizeof(int) * 100);

    // Checking whether the allocation was successful
    if (p_i == NULL)
    {
        printf("Not enough memory.\n");
        exit(1);
    }

    // Freeing the memory
    printf("Freeing the memory.\n");
    free(p_i);
    p_i = NULL; // We null the pointer just to be sure
    return (EXIT_SUCCESS);
}

The output:

c_malloc
Trying to allocate memory for 100 ints.
Freeing the memory.

So far, we don't know how to access the individual ints in the memory yet. We'll explain everything next time. The exit() function terminates our application. As a parameter, we pass an error code which is non-zero if the program didn't finish properly.

Common mistakes when working with pointers

Working with pointers is quite dangerous, as no one is watching us, programmers. Making a mistake in a program is very simple, one doesn't even have to be a beginner. Let's mention a few points that we should be careful about when working with pointers.

  • Not freeing memory - If we forget to free some memory once, nothing will happen in principle. The problem is when we forget to free memory in a function which is called multiple times during the program's runtime. The worst situation is when we forget to free memory in a loop. We will, of course, run out of memory soon or later if we make this error. The application will fall and the user will lose their data and prefer to pay the rival company for a functional application :)
  • Exceeding memory boundaries - Similarly to arrays, pointers don't keep track of what we store in their memory. If we store something larger than the amount of space we reserved, we'll break into the memory of another part of the application. This error may appear anywhere, and we'll be probably looking for it for a long time. This is because the error is not logically related to the location in the program where the memory overflows. Any part of the application can suddenly broke because the memory overflew to it :)
  • Working with already freed memory - It can happen that we free some memory and then try to write something to that address again. At that point, however, we write to memory that doesn't belong to us. See the previous point for aftermaths. Therefore, it's a good practice to store the NULL value to pointers to freed memory to avoid this error :)

In the next lesson, Pointer arithmetic in the C language, we'll learn pointer arithmetic. We'll find out that pointers in the C language are even closer to arrays than we thought.


 

 

Article has been written for you by David Capka
Avatar
Do you like this article?
No one has rated this quite yet, be the first one!
The author is a programmer, who likes web technologies and being the lead/chief article writer at ICT.social. He shares his knowledge with the community and is always looking to improve. He believes that anyone can do what they set their mind to.
Unicorn College The author learned IT at the Unicorn College - a prestigious college providing education on IT and economics.
Activities (4)

 

 

Comments

To maintain the quality of discussion, we only allow registered members to comment. Sign in. If you're new, Sign up, it's free.

No one has commented yet - be the first!