0% found this document useful (0 votes)
8 views7 pages

Lab 1 Memory Management Explained

The document explains memory management in C, focusing on stack-allocated arrays and dynamic allocation using malloc/free. Stack-allocated arrays are automatically managed, fast, and limited in size, while dynamic allocation allows for flexible memory usage at runtime but requires manual management. Best practices for memory management, including checking malloc return values and avoiding memory leaks, are also discussed.

Uploaded by

iniademola21
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
8 views7 pages

Lab 1 Memory Management Explained

The document explains memory management in C, focusing on stack-allocated arrays and dynamic allocation using malloc/free. Stack-allocated arrays are automatically managed, fast, and limited in size, while dynamic allocation allows for flexible memory usage at runtime but requires manual management. Best practices for memory management, including checking malloc return values and avoiding memory leaks, are also discussed.

Uploaded by

iniademola21
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as DOCX, PDF, TXT or read online on Scribd
You are on page 1/ 7

Lab 1 memory management explained

Stack-Allocated Arrays vs Dynamic


Allocation (malloc/free)
Stack-Allocated Arrays
What are Stack-Allocated Arrays?

Definition: Arrays declared as local variables that are automatically managed by the compiler.

void function_example() {
int arr[5]; // ← This is stack-allocated
// Memory is automatically allocated when function starts
// Memory is automatically freed when function ends
}

Memory Layout Visualization


STACK MEMORY (grows downward)


┌─────────────────┐ ← Higher addresses
│ Function Call │
│ Frame │
├─────────────────┤
│ arr[4] = ? │ ← Address: 1016
│ arr[3] = ? │ ← Address: 1012
│ arr[2] = ? │ ← Address: 1008
│ arr[1] = ? │ ← Address: 1004
│ arr[0] = ? │ ← Address: 1000
├─────────────────┤
│ Other local │
│ variables │
└─────────────────┘ ← Lower addresses (stack pointer)

Characteristics of Stack Arrays

Advantages:

 Fast allocation/deallocation (just moving stack pointer)


 Automatic cleanup (no memory leaks possible)
 Simple syntax (no pointers needed)
 Cache-friendly (contiguous memory)

Limitations:
 Fixed size (must be known at compile time)
 Limited size (stack space is limited, typically 1-8MB)
 Scope-limited (destroyed when function exits)
 Cannot resize during runtime

Example Code
#include <stdio.h>

void stack_array_example() {
// Stack allocation - size must be compile-time constant
int grades[5]; // 5 * 4 = 20 bytes on stack

// Initialize array
for(int i = 0; i < 5; i++) {
grades[i] = (i + 1) * 10; // 10, 20, 30, 40, 50
}

// Print array
printf("Stack array: ");
for(int i = 0; i < 5; i++) {
printf("%d ", grades[i]);
}
printf("\n");

// Memory automatically freed when function exits


}

What happens in memory:

1. Function called → Stack frame created


2. 20 bytes allocated for grades array
3. Array used normally
4. Function exits → Stack frame destroyed, memory automatically reclaimed

Dynamic Allocation (malloc/free)


What is Dynamic Allocation?

Definition: Memory allocated at runtime from the heap, manually managed by programmer.

int* arr = malloc(5 * sizeof(int)); // ← Dynamic allocation


// YOU must call free(arr) when done!

Memory Layout Visualization


HEAP MEMORY (grows upward)


┌─────────────────┐ ← Lower addresses
│ │
│ Free Space │
│ │
├─────────────────┤
│ arr[0] = ? │ ← Address: 5000 (returned by malloc)
│ arr[1] = ? │ ← Address: 5004
│ arr[2] = ? │ ← Address: 5008
│ arr[3] = ? │ ← Address: 5012
│ arr[4] = ? │ ← Address: 5016
├─────────────────┤
│ │
│ Free Space │
│ │
└─────────────────┘ ← Higher addresses

STACK MEMORY
┌─────────────────┐
│ int* arr = 5000 │ ← Pointer variable on stack
│ │ (contains address 5000)
└─────────────────┘

malloc() Function

Syntax: void* malloc(size_t size)

What it does:

1. Allocates size bytes from heap


2. Returns pointer to first byte
3. Memory contents are undefined (garbage values)
4. Returns NULL if allocation fails

Example:

// Allocate space for 5 integers


int* arr = malloc(5 * sizeof(int));
// └─────┘ └───────────┘
// function parameter
// (20 bytes on most systems)

free() Function

Syntax: void free(void* ptr)

What it does:

1. Returns memory to heap for reuse


2. Does NOT change pointer value
3. Accessing freed memory = undefined behavior
4. Calling free(NULL) is safe (does nothing)

Example:

free(arr); // Return memory to heap


arr = NULL; // Good practice: set pointer to NULL

Complete Dynamic Allocation Example


#include <stdio.h>
#include <stdlib.h>

void dynamic_array_example() {
int size;
printf("Enter array size: ");
scanf("%d", &size);

// Step 1: Allocate memory dynamically


int* arr = malloc(size * sizeof(int));

// Step 2: Check if allocation succeeded


if (arr == NULL) {
printf("Memory allocation failed!\n");
return;
}

printf("Successfully allocated %d bytes\n", size * (int)sizeof(int));

// Step 3: Use the array normally


for (int i = 0; i < size; i++) {
arr[i] = i * i; // Store squares: 0, 1, 4, 9, 16...
}

// Step 4: Print the array


printf("Dynamic array: ");
for (int i = 0; i < size; i++) {
printf("%d ", arr[i]);
}
printf("\n");

// Step 5: CRITICAL - Free the memory


free(arr);
arr = NULL; // Prevent accidental reuse

printf("Memory freed successfully\n");


}
Key Differences Comparison
Aspect Stack Arrays Dynamic Arrays (malloc)
Size Fixed at compile time Determined at runtime
Syntax int arr[5] int* arr = malloc(...)
Speed Very fast Slightly slower
Memory Stack (limited) Heap (much larger)
Cleanup Automatic Manual (must call free)
Lifetime Function scope only Until you call free()
Risk Stack overflow Memory leaks, double free

Memory Management Best Practices


1. Always Check malloc() Return Value
int* arr = malloc(size * sizeof(int));
if (arr == NULL) {
fprintf(stderr, "Memory allocation failed!\n");
exit(1);
}

2. Match Every malloc() with free()


int* arr = malloc(100 * sizeof(int));
// ... use array ...
free(arr); // REQUIRED!
arr = NULL; // Good practice

3. Don't Access After free()


free(arr);
arr[0] = 5; // ❌ UNDEFINED BEHAVIOR - Don't do this!

4. Don't Double-free
free(arr);
free(arr); // ❌ UNDEFINED BEHAVIOR - Don't do this!

5. Set Pointers to NULL After free()


free(arr);
arr = NULL; // ✅ Good practice - prevents accidental reuse
When to Use Which?
Use Stack Arrays When:

 Size is known at compile time


 Array is small (< few KB)
 Temporary/local use only
 Performance is critical

Example:

void process_grades() {
int class_grades[30]; // Known class size
// Process grades...
} // Automatic cleanup

Use Dynamic Arrays When:

 Size determined at runtime


 Large arrays needed
 Array outlives function scope
 Need to resize during execution

Example:

int* load_file_data(const char* filename) {


int size = get_file_size(filename);
int* data = malloc(size * sizeof(int));
// Load data...
return data; // Caller responsible for free()
}

Common Errors and Debugging


Memory Leak Example
void memory_leak_bug() {
int* arr = malloc(1000 * sizeof(int));
// ... use array ...
// ❌ Forgot to call free(arr)!
// Memory is now leaked
}

Double Free Example


void double_free_bug() {
int* arr = malloc(10 * sizeof(int));
free(arr);
free(arr); // ❌ CRASH! Double free
}

Use After Free Example


void use_after_free_bug() {
int* arr = malloc(10 * sizeof(int));
free(arr);
arr[0] = 5; // ❌ UNDEFINED BEHAVIOR
}

Understanding these concepts is crucial for C programming and forms the foundation for more
complex data structures like linked lists, trees, and graphs.

You might also like