Common Memory/Pointer Related bug in C Programs

Dereferencing an unknown memory location : C programmers mostly use scanf() function to take input, but sometimes a small mistake can bring a bug or even crash whole program.
The syntax for scanf() is scanf(“%d”, &a);. It might be possible to miss a & and write &a as a so now scanf(“%d”, a); is dereferencing to an unknown location.
Now either the program may terminate with an exception or it may correspond to a valid location(not related to current program but to some other program) and may get overwritten which may cause unknown effect later.

filter_none

edit
close

play_arrow

link
brightness_4
code

// A C program to demonstrate that missing
// an & in scanf() may cause memory problems.
#include <stdio.h>
  
int main()
{
    int a;
    scanf("%d", a);
    printf("%d", a);
    return 0;
}

chevron_right


Reading an uninitialized Memory. In C, beginners generally use malloc() to provide run time memory but with malloc() the memory block do not get initialized and one may access .

filter_none

edit
close

play_arrow

link
brightness_4
code

// A C program to demonstrate that missing
// an & may cause memory problems.
#include <stdio.h>
  
int main()
{
    int* p = (int*)malloc(sizeof(int) * 4);
    int i;
  
    // p[] contains some garbage value so
    // below loop does not make any sense.
    for (i = 0; i < 4; i++)
        p[i] += 100;
}

chevron_right


A solution is to use calloc() instead which initialize block to 0.

Buffer overflow : This is a very common mistake that occur in C and this become even more common due to presence of a faulty function in C itself i.e. gets() function which is used to take string as input. It does not check the memory provided to store string in the program due to which if a user enter string of greater size then gets() with overwrite memory location after the string and cause overflow.

filter_none

edit
close

play_arrow

link
brightness_4
code

void read()
{
    char str[20];
    gets(str);
    printf("%s", str);
    return;
}

chevron_right


The code suffers from Buffer Overflow as gets() doesn’t do any array bound testing. gets() keeps on reading until it sees a newline character. To avoid Buffer Overflow, fgets() should be used instead of gets() as fgets() makes sure that not more than MAX_LIMIT characters are read.



filter_none

edit
close

play_arrow

link
brightness_4
code

#define MAX_LIMIT 20
void read()
{
    char str[MAX_LIMIT];
    fgets(str, MAX_LIMIT, stdin);
    printf("%s", str);
    return;
}

chevron_right


Memory leaks This situation arises when the used heap memory is not de-allocated due to which the main memory get eventually filled up and free memory become less.

filter_none

edit
close

play_arrow

link
brightness_4
code

/* Function with memory leak */
#include <stdlib.h>
  
void f()
{
    int* ptr = (int*)malloc(sizeof(int));
  
    /* Do some work */
  
    return; /* Return without freeing ptr*/
}

chevron_right


We should use free() after malloc() if memory is not used anymore.

filter_none

edit
close

play_arrow

link
brightness_4
code

/* Function without memory leak */
#include <stdlib.h>
  
void f()
{
    int* ptr = (int*)malloc(sizeof(int));
  
    /* Do some work */
  
    free(ptr); // Deallocate memory
    return;
}

chevron_right


Bug due to precedence Less understanding of operator and their precedence can produce a bug especially with pointers like

filter_none

edit
close

play_arrow

link
brightness_4
code

// C program to demonstrate bug introduced due
// to precedence.
#include <stdlib.h>
  
int demo()
{
    int a = 10;
    int* p = &a;
  
    // intention was to increase the value of a
    *p++;
}

chevron_right


Precedence of * (dereference/indirection operator not multiplication) and postfix ++ are not same but prefix ++ and * has same, and hence, first the value of p will increase and will point to a bad memory area and then dereference and will overwrite that location or program may get terminated. Please see Difference between ++*p, *p++ and *++p for details.

Sending address of non-existing variable Returning address of a local variable causes problems,

filter_none

edit
close

play_arrow

link
brightness_4
code

#include <stdlib.h>
  
int fun()
{
    int x = 10;
    return &x;
}
int main()
{
    int* p = fun();
    *p = 20;
}

chevron_right


When function fun() is called variable a is created but as soon function returns, it get destroyed. Since function is returned its address p will point to a memory area in stack area and if another function is called then a change by pointer p may result in error.

Pointer arithmetic Pointer arithmetic can be confusing let’s take an example suppose integer is of 4 Bytes.

filter_none

edit
close

play_arrow

link
brightness_4
code

int main()
{
    int x[10] = { 0 }, i = 0, *p;
  
    // p point to starting address of array x
    p = &x[0];
    while (i < 10) {
        *p = 10;
  
        // intention was to point to integer at x[1]
        p = p + 4;
        i++;
    }
}

chevron_right


Although it seems correct as integer is of 4 byte and p is at starting location so adding 4 to it will cause p to point at next integer in array n but pointer arithmetic work according to size of its data type so adding 1 to a pointer of integer then sizeof(int) will get added to it same applies for pointer to any other data type.

filter_none

edit
close

play_arrow

link
brightness_4
code

int main()
{
    int x[10] = { 0 }, i = 0, *p;
    p = &x[0]; // p point to starting address of array x
    while (i < 10) {
        *p = 10;
        p++; // means p = p + sizeof(int)
        i++;
    }
}

chevron_right


Passing array as parameter When we pass an array to a function, it is always treated as a pointer in the function. That’s why we should never use sizeof on array parameter. We should rather always pass size as a second parameter.

filter_none

edit
close

play_arrow

link
brightness_4
code

#include <stdio.h>
  
// arr is a pointer even if we have
// use square brackets.
void printArray(int arr[])
{
    int i;
  
    /* sizeof should not be used here to get number 
    of elements in array*/
    int arr_size = sizeof(arr) / sizeof(arr[0]); 
    for (i = 0; i < arr_size; i++) {
        printf("%d ", arr[i]);
    }
}
  
int main()
{
    int arr[4] = { 1, 2, 3, 4 };
    printArray(arr);
    return 0;
}

chevron_right


Below is the corrected code

filter_none

edit
close

play_arrow

link
brightness_4
code

#include <stdio.h>
  
// arr is a pointer even if we have
// use square brackets.
void printArray(int arr[], int arr_size)
{
    int i;
    for (i = 0; i < arr_size; i++) {
        printf("%d ", arr[i]);
    }
}
  
int main()
{
    int arr[] = { 1, 2, 3, 4 };
    int arr_size = sizeof(arr) / sizeof(arr[0]); 
    printArray(arr, arr_size);
    return 0;
}

chevron_right


Reference :
Computer Systems :A programmer’s Perspective



My Personal Notes arrow_drop_up


If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Improved By : xdsarkar



Article Tags :
Practice Tags :


Be the First to upvote.


Please write to us at contribute@geeksforgeeks.org to report any issue with the above content.