fbpx

Optimizing Memory Usage in C with Dynamic Allocation Techniques

Optimizing Memory Usage in C with Dynamic Allocation Techniques


INTRODUCTION

C is a structured programming language with specific rules governing array usage, on which pertains to the size of an array. In array the items are stored in contiguous memory locations.

Let us consider an array with a size of 9. If you only need to store 5 elements, the remaining 4 indices occupy unnecessary memory. Thus, there may be a need to reduce the array’s size from 9 to 5.

Conversely, if you have an array of 9 elements that are all filled and you need to add 3 more elements, you will require additional space. In this case, the array’s size needs to be increased from 9 to 12 to accommodate the new entries.

So there entered dynamic memory allocation.

  • Dynamic memory allocation: Dynamic memory allocation is used to allocate and   the de-allocate memory.
  • Types of dynamic memory allocation

                – Malloc

                – Calloc

                – Realloc

                – Free

  • Malloc:
  • malloc():Allocates a specified number of bytes in memory and returns a pointer to the starting byte.

Syntax of Malloc:

The syntax for malloc in C is:

 void *malloc(size_t size);

Explanation of Syntax

  • Size=The number of bytes to allocate.
  • The return value of malloc is a void * pointer that points to the start of the allocated memory block. If the memory allocation fails due to insufficient memory, it will return NULL.

//This program illustrates how to allocate the memory  and initialize the value.

#include <stdio.h>

#include <stdlib.h>

 

int main() {

    int *array = (int *)malloc(5 * sizeof(int)); // Allocates 20 bytes

 

    if (array == NULL) {

        // Handle allocation failure

        printf(“Memory allocation failed\n”);

        return 1;

    }

 

    // Print the address of the allocated memory

    printf(“Address of allocated memory: %p\n”, (void*)array);

 

    //for example, initializing the array

    for (int k= 0; k < 5; k++) {

        array[i] = k * 10; // Initializing values

    }

 

    // Print the values and addresses of each element

    for (int m= 0; m< 5; m++) {

        printf(“array[%d] = %d at address %p\n”, m, array[m], (void*)&array[m]);

    }

 

    // Free the allocated memory

    free(array);

 

    return 0;

}

  • calloc(): Allocates memory for an array of elements, initializes all bytes to zero

syntax for calloc:

    int *myArray = calloc(numItems, sizeof(int));numitems(count of items)

Example program

———————

#include <stdio.h>

#include <stdlib.h>

 

int main() {

    int n = 5;

    int *arr11 = (int*) calloc(n, sizeof(int)); // Allocates memory for 5 integers

 

    if (arr1 1== NULL) {

        printf(“Memory allocation failed\n”);

        return 1;

    }

 

    // Print initialized values

    for (int  pri = 0; pri < n; pri++) {

        printf(“%d “, arr1[pri]); // Should print “0 0 0 0 0”

    }

 

    free(arr1); // Don’t forget to free the allocated memory

    return 0;

}

 

realloc(): Resizes a previously allocated memory block.

Example program

#include <stdio.h>

#include <stdlib.h>

 

int main() {

    int n = 5;

    // Allocate initial memory for an array of 5 integers

    int *array1 = (int*) malloc(n * sizeof(int));

 

    if (array1 == NULL) {

        printf(“Initial memory allocation failed\n”);

        return 1;

    }

 

    // Initialize the array

    for (int initial = 0; initial < n; initial ++) {

        arr1[i] = initial + 1; // arr1 will be {1, 2, 3, 4, 5}

    }

 

    // Print initial values

    printf(“Original array: “);

    for (int pri = 0; pri < n; pri++) {

        printf(“%d “, array1[pri]);

    }

    printf(“\n”);

 

    // Resize the array to hold 10 integers

    n = 10;

    int *temp = (int*) realloc(array1, n * sizeof(int));

   

    if (temp == NULL) {

        printf(“Memory reallocation failed\n”);

        free(arr1); // Free original memory if realloc fails

        return 1;

    }

    arr1 = temp; // Update arr1 to point to the newly allocated memory

 

    // Initialize new elements

    for (int r= 5; r < n; r++) {

        arr1[r] = r + 1; // arr1 will now be {1, 2, 3, 4, 5, 6, 7, 8, 9, 10}

    }

 

    // Print resized values

    printf(“Resized array: “);

    for (int z= 0; z < n; z++) {

        printf(“%d “, arr1[z]);

    }

    printf(“\n”);

 

    free(arr1); // Free the allocated memory

    return 0;

}

 

  • free(): Deallocates memory that was previously allocated, making it available for future allocations.

Syntax:   void free(void* ptr);

    • ptr: A pointer to the memory block that you want to free. This pointer must have been returned by a previous call to malloc, calloc, or realloc.
  • No Return Value: The free function does not return a value.
  • Effect on Pointer: After calling free, the pointer still exists but points to a memory location that is no longer valid. It is a good practice to set the pointer to NULL after freeing it to avoid accidental access to freed memory.
  • Freeing Memory: Only memory allocated with malloc, calloc, or realloc should be freed. Attempting to free a pointer that was not allocated dynamically or that has already been freed can lead to undefined behavior.

Example of Using free:

Here’s an example demonstrating the use of malloc, free, and the importance of handling pointers correctly:

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

int main() {
int n = 5;
int *a= (int*) malloc(n * sizeof(int));

if (a == NULL) {
printf(“Memory allocation failed\n”);
return 1;
}

// Initialize the array
for (int i = 0; i < n; i++) {
a[i] = i + 1; // a will be {1, 2, 3, 4, 5}
}

// Print the array
printf(“Array: “);
for (int i = 0; i < n; i++) {
printf(“%d “, a[i]);
}
printf(“\n”);

// Free the allocated memory
free(a);
a = NULL; // Set the pointer to NULL after freeing

// Attempting to access arr1 after free would be undefined behavior
// Uncommenting the next line will cause issues
// printf(“After free: %d\n”, a[0]);

return 0;