Curriculum
Course: C basic
Login

Curriculum

C basic

C Introduction

0/1

C Get Started

0/1

C Comments

0/1

C Constants

0/1

C Operators

0/1

C Break and Continue

0/1

C User Input

0/1

C Memory Address

0/1

C Structures

0/1
Text lesson

C Memory Example

Real-Life Memory Management Example

We’ve developed a program showcasing dynamic memory, enabling the creation of a list of any desired length.

Unlike regular arrays in C, which have a fixed size, dynamic memory allows us to generate lists of variable lengths.

Example

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
};

void addToList(struct list *myList, int item);

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));

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

  // Add any number of items to the list specified by the amount variable
  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;
}

// This function adds an item to a list
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++;

 

Pointers to structures: In this example, there’s a pointer to the structure myList. Utilizing a pointer to the structure necessitates using the arrow syntax (->) to access the structure’s members, instead of directly accessing them.

Example explained

This example comprises three components:

  • A structure named myList that encapsulates the data of a list.
  • The main() function containing the program logic.
  • A function addToList() responsible for appending an item to the list.

The myList structure

The myList structure encompasses all information regarding the list, comprising its contents. It comprises three members:

  • data – A pointer to dynamically allocated memory holding the list’s contents.
  • numItems – Indicates the count of items within the list.
  • size – Specifies the capacity of the allocated memory to accommodate items.

We utilize a structure to facilitate the seamless transmission of all this information to a function.

The main() function

The main() function commences by initializing the list with a capacity for 10 items:

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

myList.numItems is initialized to 0 since the list begins empty.

myList.size monitors the allocated memory. It’s set to 10 to reserve space for 10 items.

Next, we allocate memory and store a pointer to it in myList.data.

Following this, we implement error checking to verify the success of memory allocation.

// Find out if memory allocation was successful
if (myList.data == NULL) {
  printf(“Memory allocation failed”);
  return 1; // Exit the program with an error code

If no issues arise, a loop adds 44 items to the list using the addToList() function.

// Add any number of items to the list specified by the amount variable
amount = 44;
for (int i = 0; i < amount; i++) {
  addToList(&myList, i + 1);

In the provided code, &myList represents a pointer to the list, while i + 1 signifies the number intended for addition to the list. The selection of i + 1 is made to initialize the list from 1 instead of 0, although any desired number can be chosen.

Once all items are added to the list, the subsequent loop prints its contents.

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

Upon completion of printing the list, we free the memory to mitigate the risk of memory leaks.

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

The addToList() function

The addToList() function appends an item to the list, accepting two parameters:

void addToList(struct list *myList, int item) 
  • A pointer indicating the list.
  • The value intended for addition to the list.

Initially, the function checks if the list has reached its capacity by comparing the number of items in the list to its size. If the list has reached its full capacity, it reallocates memory to accommodate an additional 10 items.

// 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) );

Finally, the function appends the item to the end of the list. The index at myList->numItems always points to the list’s end as it increments by 1 with each new addition.

// Add the item to the end of the list
myList->data[myList->numItems] = item;
myList->numItems++; 

Why do we reserve 10 items at a time?

Optimization involves striking a balance between memory usage and performance. While it’s possible to allocate more memory than necessary, reallocating memory too often can lead to inefficiencies. It’s essential to find the equilibrium between allocating excessive memory and reallocating too frequently.

In this example, we opted for the number 10, but the choice depends on the anticipated amount of data and its frequency of change. For instance, if we’re aware in advance that we’ll have precisely 44 items, we can allocate memory for exactly 44 items and do so just once.