Memory Management Example in C: Dynamic List Creation

Explore a real-life example of memory management in C programming. Learn how to use dynamic memory allocation to create a flexible, dynamic list that can adjust in size, unlike regular fixed-length arrays.



Memory Management Example in C

Real-Life Memory Management Example

This example demonstrates how to create a program that can manage a dynamic list of any length. Unlike regular arrays in C, which have a fixed length, dynamic memory allows us to create lists that can grow as needed.

Struct Definition

We start by defining a structure for our list:

Struct Definition

struct list {
  int *data;      // Points to the memory where the list items are stored
  int numItems;   // Indicates how many items are currently in the list
  int size;       // Indicates how many items fit in the allocated memory
};

Function to Add Items to the List

The following function adds items to the list:

Function: addToList()

void addToList(struct list *myList, int item) {
  // If the list is full then resize the memory to fit 10 more items
  if (myList->numItems == myList->size) {
    myList->size += 10;
    myList->data = realloc(myList->data, myList->size * sizeof(int));
  }
  // Add the item to the end of the list
  myList->data[myList->numItems] = item;
  myList->numItems++;
}

Main Function

The main function initializes the list and adds items:

Main Function Example

#include 
#include 

int main() {
  struct list myList;
  int amount;

  // Create a list and start with enough space for 10 items
  myList.numItems = 0;
  myList.size = 10;
  myList.data = malloc(myList.size * sizeof(int));

  // Check if memory allocation was successful
  if (myList.data == NULL) {
    printf("Memory allocation failed");
    return 1; // Exit the program with an error code
  }

  // Add items to the list
  amount = 44;
  for (int i = 0; i < amount; i++) {
    addToList(&myList, i + 1);
  }

  // Display the contents of the list
  for (int j = 0; j < myList.numItems; j++) {
    printf("%d ", myList.data[j]);
  }

  // Free the memory when it is no longer needed
  free(myList.data);
  myList.data = NULL;

  return 0;
}
Output

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 

Understanding the Code

This example consists of three parts:

  1. A structure named myList that holds the data for our list.
  2. The main() function that initializes and manages the list.
  3. A function addToList() that adds an item to the list.

The myList Structure

The myList structure contains:

  • data: A pointer to the dynamic memory that holds the list contents.
  • numItems: Indicates how many items are currently in the list.
  • size: Indicates how many items can fit in the allocated memory.

The main() Function

The main() function initializes the list with space for 10 items:


myList.numItems = 0;
myList.size = 10;
myList.data = malloc(myList.size * sizeof(int));

It checks if the memory allocation was successful:


if (myList.data == NULL) {
  printf("Memory allocation failed");
  return 1; // Exit the program with an error code
}

If successful, it enters a loop to add items:


for (int i = 0; i < amount; i++) {
  addToList(&myList, i + 1);
}

The addToList() Function

The addToList() function checks if the list is full. If it is, it reallocates memory to fit 10 more items:


if (myList->numItems == myList->size) {
  myList->size += 10;
  myList->data = realloc(myList->data, myList->size * sizeof(int));
}

Then, it adds the item to the end of the list:


myList->data[myList->numItems] = item;
myList->numItems++;

Why Reserve 10 Items at a Time?

Reserving memory is a balancing act between memory usage and performance. Allocating memory too frequently can be inefficient. By reserving 10 items at a time, we optimize for both memory usage and performance. However, if we know we will need a specific number of items, we can allocate memory accordingly.