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.
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() { // Create a list and start with enough space for 10 items // Find out if memory allocation was successful // Add any number of items to the list specified by the amount variable // Display the contents of the list // Free the memory when it is no longer needed return 0; // This function adds an item to a list // If the list is full then resize the memory to fit 10 more items // Add the item to the end of the list |
|
This example comprises three components:
The myList
structure
The myList structure encompasses all information regarding the list, comprising its contents. It comprises three members:
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) |
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.