Structures and Dynamic Memory
Combine structs with malloc! Create dynamic arrays of structures that grow as needed. Build real data structures.
What You Will Learn
- ✓Allocate structs dynamically
- ✓Use arrow operator (->) with pointers
- ✓Create dynamic arrays of structs
- ✓Build growing lists with realloc
01Why Dynamic Memory with Structures?
🚗 Real-World Example: Car Dealership
Imagine you're building a car dealership program. You don't know how many cars you'll have in advance. Dynamic memory lets you allocate exactly what you need!
❌ Static Array Problem
struct Car cars[100];
✅ Dynamic Solution
struct Car *cars = malloc(n * sizeof(struct Car));
| Feature | Static Struct Array | Dynamic Struct Array |
|---|---|---|
| Size | Fixed at compile time | Set at runtime |
| Can grow? | No | Yes (realloc) |
| Memory | May waste space | Efficient |
| Cleanup | Automatic | Manual (free) |
02Allocating Memory for One Struct
1#include <stdio.h>2#include <stdlib.h>3#include <string.h>45struct Car {6 char brand[50];7 int year;8};910int main() {11 // Allocate memory for one Car12 struct Car *ptr = malloc(sizeof(struct Car));13 14 if (ptr == NULL) {15 printf("Allocation failed!\n");16 return 1;17 }18 19 // Set values using -> (arrow operator)20 strcpy(ptr->brand, "Honda");21 ptr->year = 2022;22 23 // Print values24 printf("Brand: %s\n", ptr->brand);25 printf("Year: %d\n", ptr->year);26 27 // Free memory28 free(ptr);29 return 0;30}Brand: Honda
Year: 2022
💡 Arrow Operator (→)
When you have a pointer to a struct, use ptr->memberinstead of ptr.member. The arrow is shorthand for (*ptr).member.
03Arrays of Structs
You can allocate memory for multiple structs at once, like an array. Use malloc(count * sizeof(struct)).
1#include <stdio.h>2#include <stdlib.h>3#include <string.h>45struct Car {6 char brand[50];7 int year;8};910int main() {11 // Allocate memory for 3 cars12 struct Car *cars = malloc(3 * sizeof(struct Car));13 14 if (cars == NULL) {15 printf("Allocation failed!\n");16 return 1;17 }18 19 // Fill the data (use array notation!)20 strcpy(cars[0].brand, "Ford");21 cars[0].year = 2015;22 23 strcpy(cars[1].brand, "BMW");24 cars[1].year = 2018;25 26 strcpy(cars[2].brand, "Volvo");27 cars[2].year = 2023;28 29 // Print the data30 for (int i = 0; i < 3; i++) {31 printf("%s - %d\n", cars[i].brand, cars[i].year);32 }33 34 free(cars);35 return 0;36}Ford - 2015
BMW - 2018
Volvo - 2023
💡 Array Notation with Pointers
With an array of structs, use cars[i].member (dot notation). Only use arrow -> when accessing through a single pointer.
04Growing Arrays with realloc()
Need more elements later? Use realloc() to resize! Always use a temp pointer to avoid memory leaks if realloc fails.
1#include <stdio.h>2#include <stdlib.h>3#include <string.h>45struct Car {6 char brand[50];7 int year;8};910int main() {11 int count = 2;12 struct Car *cars = malloc(count * sizeof(struct Car));13 14 if (cars == NULL) {15 printf("Allocation failed!\n");16 return 1;17 }18 19 // Initialize first 2 cars20 strcpy(cars[0].brand, "Toyota");21 cars[0].year = 2010;22 strcpy(cars[1].brand, "Audi");23 cars[1].year = 2019;24 25 // Need one more car -> grow to 326 int newCount = 3;27 struct Car *tmp = realloc(cars, newCount * sizeof(struct Car));28 29 if (tmp == NULL) {30 free(cars); // Free original if realloc fails31 printf("Realloc failed!\n");32 return 1;33 }34 cars = tmp; // Use the reallocated block35 36 // Initialize new element37 strcpy(cars[2].brand, "Kia");38 cars[2].year = 2022;39 40 // Print all cars41 for (int i = 0; i < newCount; i++) {42 printf("%s - %d\n", cars[i].brand, cars[i].year);43 }44 45 free(cars);46 return 0;47}Toyota - 2010
Audi - 2019
Kia - 2022
⚠️ New Space is Uninitialized!
When realloc() expands memory, the new space contains garbage values. Always initialize new elements before use!
05Real-Life Example: Dynamic List
Here's a practical example: a list that grows automaticallywhen you add items. This is how many real programs manage dynamic data.
1#include <stdio.h>2#include <stdlib.h>34struct List {5 int *data; // Points to memory6 int count; // Items in list7 int capacity; // Total space8};910void addItem(struct List *list, int item) {11 // Grow if full12 if (list->count == list->capacity) {13 int newCap = list->capacity + 5;14 int *tmp = realloc(list->data, newCap * sizeof(int));15 if (tmp == NULL) return;16 list->data = tmp;17 list->capacity = newCap;18 }19 list->data[list->count] = item;20 list->count++;21}2223int main() {24 struct List myList;25 myList.count = 0;26 myList.capacity = 5;27 myList.data = malloc(5 * sizeof(int));28 29 if (myList.data == NULL) return 1;30 31 // Add 12 items (will grow automatically!)32 for (int i = 0; i < 12; i++) {33 addItem(&myList, (i + 1) * 10);34 }35 36 // Print all items37 for (int i = 0; i < myList.count; i++) {38 printf("%d ", myList.data[i]);39 }40 41 free(myList.data);42 return 0;43}10 20 30 40 50 60 70 80 90 100 110 120
📝 How It Works
- 1.Start with space for 5 items
- 2.When full,
realloc()adds 5 more slots - 3.List grows: 5 → 10 → 15 as needed
- 4.This is called a "dynamically growing array"
06Summary
🎯 Key Takeaways
- •One struct:
malloc(sizeof(struct Car)) - •Array of structs:
malloc(n * sizeof(struct Car)) - •Pointer to struct: Use arrow
ptr->member - •Array notation: Use dot
cars[i].member - •Growing: Use temp pointer with realloc()
- •Always: Check NULL, free() when done
struct Car *car = malloc(sizeof(struct Car));
if (car == NULL) return 1;
strcpy(car->brand, "Honda");
car->year = 2022;
free(car);
08Next Steps
Learn to read and write files in C: