Skip to Content
Course content

54: Dynamic Allocation with malloc and calloc

Click on the "Edit" button in the top corner of the screen to edit your slide content.

Up until now, you've likely been declaring your arrays with a fixed size, like int scores[100];. In a controlled classroom environment, that works fine. But in the real world, you rarely know exactly how much data you're dealing with before the program actually starts running. I've seen countless junior devs try to solve this by just picking a "magic number"—declaring an array of 10,000 elements "just in case."

The Danger of the Magic Number

If you declare a massive static array, you're gambling. If only ten users sign up for your service, you've wasted a huge chunk of memory for no reason. Worse, if 10,001 users sign up, your program will either crash or, even more dangerously, start writing data into memory it doesn't own, leading to those nightmare-inducing segmentation faults. Static allocation happens on the stack, and the stack is relatively small. If you try to allocate a massive array there, you'll blow the stack before your main function even gets a chance to run.

// The naive way: guessing the size
int scores[1000]; // What if we have 1001 players? What if we have 2?

Asking for Exactly What You Need

This is where we move to the heap. Instead of telling the compiler "I need space for 1000 ints," we tell the operating system at runtime, "I need exactly this much space." We do this with malloc (memory allocation). It takes a single argument: the total number of bytes you want. Since different systems have different sizes for integers, we always multiply the number of elements by sizeof(type).

The catch is that malloc returns a void*—a generic pointer. You'll see some people cast this pointer to the desired type, but in C, that's generally unnecessary and can actually hide bugs. I prefer to just assign it directly to a typed pointer.

int num_players;
printf("How many players? ");
scanf("%d", &num_players);

// Request exactly enough space for the players provided
int *scores = malloc(num_players * sizeof(int));

if (scores == NULL) {
    // Always check for NULL. If the OS is out of memory, malloc fails.
    fprintf(stderr, "Memory allocation failed!\n");
    return 1;
}

Clean Slates vs. Raw Speed

Now, here is a nuance that often trips people up: malloc doesn't clear the memory it gives you. It gives you a raw block of RAM that might still contain "garbage" data from whatever program used that memory last. If you try to read from a malloc'd array before writing to it, you'll get random, unpredictable numbers.

If you need your memory to be zeroed out from the start, you can use calloc (contiguous allocation). It takes two arguments: the number of elements and the size of each element. I usually reach for calloc when I'm creating something like a frequency counter or a lookup table where starting at zero is a requirement. The trade-off is a tiny bit of performance; zeroing out memory takes time, though in 99% of applications, you'll never notice the difference.

// malloc: Fast, but contains garbage
int *raw_data = malloc(10 * sizeof(int));

// calloc: Slightly slower, but everything is initialized to 0
int *clean_data = calloc(10, sizeof(int));

The Debt You Always Have to Pay

The biggest difference between stack memory and heap memory is that the heap is not self-cleaning. When a function ends, its local variables vanish. But memory allocated with malloc or calloc stays there until you explicitly tell the OS you're done with it. If you lose the pointer to that memory without freeing it, you've created a memory leak. Do this inside a loop in a long-running server, and you'll eventually eat all the available RAM on the machine.

I make it a habit to write the free() call the very moment I write the malloc() call. It keeps the "debt" visible so you don't forget to pay it back.

free(scores);
scores = NULL; // Good practice to prevent "dangling pointers"



📋 Practical Task

Exercise: Dynamic Student Grade Tracker

Write a program that manages student grades using dynamic memory allocation. Your program should follow these requirements:

  • Prompt the user to enter the number of students in a class.
  • Use malloc to allocate an array of float values based on that number.
  • Use a loop to allow the user to input the grade for each student.
  • Calculate and print the class average.
  • Properly free the allocated memory before the program exits.
  • Include a check to ensure malloc did not return NULL.
Rating
0 0

There are no comments for now.

to be the first to leave a comment.