dangling pointer and memory leak

Difference between dangling pointer and memory leak

There are a lot of people who asked me the difference between the dangling pointer and memory leak. I have found that some people understand both are the same things.

In this article, I will not only discuss the basic difference between a dangling pointer and a memory leak but also discuss some important points that help you to prevent the memory leak.

Basically, dangling pointer and memory leak are different terms. If a pointer is pointing to memory that is not owned by your program (except the null pointer ) or an invalid memory, the pointer is called a dangling pointer. Generally, daggling pointers arise when the referencing object is deleted or deallocated, without changing the value of the pointers.

In opposite to the dangling pointer, a memory leak occurs when you forget to deallocate the allocated memory. In the C language compiler does not deallocate the memory automatically it is freed by the programmer explicitly. In another word, you can say that a memory leak is a type of resource leak.

Note: once you allocate memory than allocated memory does not allocate to another program or process until it gets free.

Let’s see the dangling pointer and memory leak in-depth to understand the difference between a dangling pointer and a memory leak in C.

 

Dangling pointer in C

In the program, we should not use the dangling pointer. It can be the cause of memory faults. Here I am mentioning few forms of the dangling pointer, I think you should know.

1. If a pointer points to an address that not belongs to your process but knows by the OS, then this type of pointer is a dangling pointer. You should not use such type of pointers is because it leads to a memory fault.

2. Static and automated memory is handled by the compiler but if you allocate the memory in heap memory, the developer needs to free the allocated heap memory. The deleted pointer is another type of dangling pointer is because you have freed the memory but still its pointing to that memory.

For example,

#include<stdio.h>
#include<stdlib.h>

int main()
{
    int *p= NULL;

    //Allocate memory for 5 integer
    p= malloc(sizeof(int)* 5);
    if(p == NULL)
    {
        return -1;
    }

    //free the allocated memory
    free(p);

    //p is dangling pointer
    *p= 2;

    printf("%d",*p);

    return 0;
}

Output:

Undefined behavior.

After deallocating the memory, p becomes the dangling pointer and if you try to access the p, your program could be crash.

 

3. An uninitialized pointer is called a dangling pointer (also called wild pointer) because we don’t know where it points. So we should always initialize the pointer. It is prevented from the undesired result.

int* p; //uninitialized pointer

*p = 10; // Show undefined behaviour

 

4. The stack frame that is allocated to a function is destroyed after returning the control from the function. The common mistake performed by the developer is that to return the address of the stack-allocated variable from the function. If you tried to access the returning address from the pointer, you will get an unpredictable result or might get the same value but it is very dangerous and need to avoid.

Example,

In the below code, Data has not to scope beyond the function. If you try to read the value of Data after calling the Fun() using the pointer may you will get the correct value (5), but any functions called thereafter will overwrite the stack storage allocated for Data with other values and the pointer would no longer work correctly.

So in the below code piData is a dangling pointer that is pointing to a memory that is not available.

#include<stdio.h>

int *Fun()
{
    //Local variable
    int Data = 5;

    //Address of local variable
    return &Data;
}


int main()
{
    //Returning address of the local variable
    int *piData = Fun();

    printf("%d", *piData);

    return 0;
}

 

5. If you try to access the array outside of the array boundary, it also considers dangling pointer because shoe the undesired behavior.

For example,

int arr[5];
arr[8] = 10;

In the above example, allowed indices of the array (arr) are 0 to 4, and arr[8] is outside the array. (show undefined behavior).

 

If you love online courses and want to learn C programming, you can check the course “The C Programming Language in Action” created By Kenny Kerr. The good thing is that TRIAL IS FREE

Rating: 4.6

Grab your free Trial, today

Memory Leak in C

A memory leak is a curse for software because software shows undefined behavior due to the memory leak. The memory leak occurs when programmers forget to deallocate the allocated memory.

Let’s see a program,

In the below program, the programmer forgets to free the allocated memory, it can cause a memory leak.

int main()
{
    char * pBuffer = malloc(sizeof(char) * 10);

    /* Do some work */

    /*Not freeing the allocated memory*/
    return 0;
}

 

 

How to avoid the creation of the dangling pointer in C?

We can easily prevent the creation of a dangling pointer to assign a NULL to the freed pointer. The behavior of the NULL pointer is defined, if you tried to dereference the NULL pointer, then memory fault occurs.

See below example,

#include<stdio.h>
#include<stdlib.h>

int main()
{
    char *pcData = NULL;

    //creating integer of size 10.
    pcData = malloc(sizeof(char)* 10);
    if(pcData == NULL)
    {
        return -1;
    }

    /* piData can be becomes a dangling pointer */
    free(pcData);

    //piData is no longer dangling pointer
    pcData = NULL;

    return 0;
}

 

Another way to avoid the creation of the dangling pointer is to avoid return the address of local variables and array from a function. It is a very common mistake.

#include<stdio.h>

int *foo()
{
    int Data = 6;

    return &Data;
}

int main()
{
    int *piData = NULL;
    
    // Now piData is a dangling pointer.
    piData = foo();

    printf("%d",*piData);

    return 0;
}

 

 

Using the dynamic memory allocation or static variable or array, we can resolve the above problem.

See the example code,

#include<stdio.h>

int *foo()
{
    static int Data = 6;

    return &Data;
}

int main()
{
    int *piData = NULL;

    // Now piData is Not a dangling pointer
    // as it points  to static variable.
    piData = foo();

    printf("%d",*piData);

    return 0;
}

 

 

How to avoid memory leaks in C?

There are many tools available to detect memory leaks. But we can also avoid the memory leak to follow some programming tips. So let see the tips,

 

Every malloc or calloc should have a free function:

It is a golden rule to write the free function after each malloc (calloc) function. Suppose in an application you have required to create an array of characters to store some dynamic data. Because we know that in C programming we use the memory management function (malloc or calloc) to create a dynamic array.

It is a good habit to write the free function just after the malloc or calloc. It prevents the scenario when the developer forgets to write the free function.

int fun(int n)
{
    char *pInfoData = malloc (n *sizeof(char));
    free(pInfoData);

    return 0;
}

 

Now start to write the code between malloc and free function. Like the below expression.

int fun(int n)
{
    char *pInfoData = malloc (n *sizeof(char));

    /* Do some work */

    free(pInfoData);

    return 0;
}

 

Sometimes we have required allocated memory throughout the application, in that situation we have to write the free function in a handler that will invoke at the end of the application. And we have to write the free function just after writing the malloc function to avoid the chance to forget.

For example,

Suppose there is a callback function DeactivateHandler() that is invoked at the end of the application, so we have to write the free function in DeactivateHandler() just after writing the malloc. These techniques reduce the probability to forget to free the memory.

 

Avoid the orphaning memory location

At the time of memory deallocation, we need to free the memory from child to parent which means a child will be free first. If we free the parent first, it can be a cause of memory leak.

For example,

In the below code, the pointer to context structure is freeing first. So the pointer that is pointing to space for the information data become an orphan and it can be a cause of memory leak.

typedef struct
{
    void *pvDataInfo;
    
} sContext;

//Allocate the memory to pointer to context structure
sContext  *pvHandle = malloc(sizeof(sContext));

//Allocate the memory for Information data
pvHandle-> pvDataInfo  = malloc(SIZE_INFO_DATA);

free(pvHandle); // pvDataInfo  orphan

 

Create a counter to monitor allocated memory

It is a good technique to prevent memory leaks. In this technique, we will create two global counters and initialize them with 0. In every successful allocation, we will increment the value of the counter1 (Allocate_Counter ) and after deallocating the memory we will increment the counter2 (Deallocate_Counter). At the end of the application, the value of both counters should be equal.

This method helps you to track the status of allocated memory. To implement this technique we need to create three customize functions, one for memory allocation, and second for memory deallocation, and the last one to check the memory leak.

static unsigned int Allocate_Counter  = 0;
static unsigned int Deallocate_Counter  = 0;


void *Memory_Allocate (size_t size)
{
    void *pvHandle = NULL;
    pvHandle = malloc(size);
    if (NULL != pvHandle)
    {
        ++Allocate_Counter;
    }
    else
    {
        //Log error
    }
    return (pvHandle);
}


void Memory_Deallocate (void *pvHandle)
{
    if(pvHandle != NULL)
    {
        free(pvHandle);
        ++Deallocate_Counter;
    }
}


int Check_Memory_Leak(void)
{
    int iRet = 0;
    if (Allocate_Counter != Deallocate_Counter)
    {
        //Log error
        iRet = Memory_Leak_Exception;
    }
    else
    {
        iRet = OK;
    }
    return iRet;
}

 

Do not work on the original pointer

It is a good habit to work on a copy of the pointer, it preserves the address of allocating memory. If there is any accidental change occurred on the pointer, this technique helps you to get the actual address of allocating memory that is needed at the time of memory deallocation.

int *pBuffer = malloc ( sizeof(char) * n );

//Create copy of the pointer
int *pTmpBuffer = pBuffer;


// Do some work


free (pBuffer);

 

Write the proper comments

I think it is good habits to write the comment in every section of the code. It always reminds you that what you did. It helps you if you read your code after some months or years.

 

Recommended Articles for you: