Five common pointer mistakes in C programming

Pointer is the most important and powerful tool in C language. Pointer resolves many complicated problems easily but if you don’t have the sufficient knowledge of pointers, you will face problems like segmentation fault etc.

In this article, I will describe five common pointer mistakes in C programming which generally occurs.

What is pointer?

A pointer is a variable that stores memory address. If it is a variable, it must have a valid C data type. Yes, every pointer variable has a data type associated with it. Which means an integer pointer can hold only integer variable addresses.

There are numerous advantages of pointers, such as.

  • Pointers are more efficient in handling arrays and structures.
  • We use to return multiple values from a function.
  • We use pointers to get reference of a variable or function.
  • Pointer allows dynamic memory allocation (creation of variables at runtime) in C.
  • Pointers increases execution speed of program.

Common pointer mistakes and how to avoid them

Despite of its advantages, if not used correctly pointers can be severely dangerous to your program. Let us cover some common pointer mistakes in C programming. And learn how to avoid common pointer mistakes.

Uninitialized Pointer

Like all variables initialization, we should always initialize a pointer variable. Behaviour of uninitialized pointers is undefined, hence we should always initialize a pointer prior to use. In C programming terminology an uninitialized pointer is termed as Wild pointer.

Example:

int *crazyPointer; // wild pointer

It is always a good idea to initialize a pointer with NULL (null pointer) at the time of its declaration.

int *calmPointer = NULL;

Access a freed pointer

We use free() function in C programming to release memory allocated by a pointer.

After calling free() function, pointer still point at the same allocated memory address. So, you might succeed but it is illegal and behavior of accessing freed pointer (memory location) is undefined. The freed pointer is also called the dangling pointer.

Example:

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

int main()
{
    int *ptr = NULL;

    // Creating integer of size 5
    ptr = malloc(sizeof(int) * 5);

    // Unable to allocate memory
    if (ptr == NULL)
        return 0;


    // Free the allocated memory
    free(ptr);

    // ptr is dangling pointer
    // Behaviour of this is undefined
    *ptr = 50;

    return 0;
}

Note: It is always good habit to assigned NULL (null pointer) to a freed pointer.

Forget to check the return value of memory management function

Dynamic memory allocation functions, returns pointer to the allocated memory on success otherwise NULL (null pointer). Generally, people forget to check the return value of memory management functions (malloc(), calloc(),.. etc).

These functions return a valid allocated memory on success, on failure they return NULL. So, we should always check the return value of these function. This help you to prevent from segmentation fault.

Example: Bad way to use dynamic memory allocation

// Allocate memory to accommodate an integer
int *ptr = malloc(sizeof(int));

// Assign value to the newly allocated memory 
// This assignment may cause segmentation fault
// Since we are assigning value to a dynamically 
// allocated memory, without check whether it got 
// allocated successfully or not.
*ptr = 10;

Good way to use dynamic memory allocation

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

// Terminate, if memory not allocated successfully
if(ptr == NULL)
   return 0;

// Assign value to newly allocated memory after 
// checking memory allocation
*ptr = 10;

Forget to free dynamically allocated memory

When managing memory manually, you must take care of proper memory allocation and deallocation. You should always free the allocated memory.

If you forget to deallocate the allocated memory, then the allocated memory is not available to another process and it is reserved for the entire life of the program. It is the one of the important cause of the memory leaks.

Example:

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

int main ()
{
    // Allocate 20 bytes memory
    char * ptr = malloc(sizeof(char) * 20);

    /* Do some work */

    // Not freeing the allocated memory
    return 0;
}

To avoid memory leaks, you must deallocate the dynamically allocated memory.
Example: Avoid memory leaks in above program

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

int main ()
{
    // Allocate 20 bytes memory
    char * ptr = malloc(sizeof(char) * 20);

    /* Do some work */

    // Free the allocated memory afters its use
    free(ptr);

    return 0;
}

Freeing the same memory multiple times

We use free() function to deallocate dynamically allocated memory. The behaviour of free() function is undefined, if you try to free memory that is already deallocated (using free() or realloc()).

Freeing memory twice is more dangerous then memory leaks. So, it is good habit to assign NULL to the deallocated pointer because free() function does not perform anything with null pointer.

Example:

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

int main()
{
    // Its always good to initialize pointer with NULL
    int *ptr = NULL;

    // Allocate integer of size 10.
    ptr = malloc(sizeof(int) * 10);

    // Check if memory allocated successfully
    // if (ptr != NULL) is equivalent to if (!ptr)
    if (!ptr)
    {
        printf("Unable to allocate memory");
        return;
    }

    // free dynamically allocated memory
    free(ptr); 

    // Assign NULL to deallocated memory
    ptr = NULL;

    // Free dynamically allocated memory twice
    free(ptr);

    return 0;
}

Happy coding 😉