When solving DSA problems, understanding memory allocation is important because algorithms use variables, function calls, recursion, and dynamic data structures. The two main memory areas are Stack and Heap, each serving a different purpose during program execution.
- Stack Allocation: Used primarily for function calls, local variables, and temporary data. Memory is automatically managed according to function execution.
- Heap Allocation: Used for dynamically allocated data and objects whose lifetime can extend beyond a single function call. Memory management depends on the programming language.
Note: The exact implementation of stack and heap memory can vary depending on the programming language, compiler, runtime, operating system, and hardware.
#include <iostream>
using namespace std;
int main(){
// Stack memory
int x = 10;
// Heap memory
int* y = new int(20);
cout << "Stack value: " << x << endl;
cout << "Heap value: " << *y << endl;
delete y;
return 0;
}
#include <stdio.h>
int main(){
// Stack memory
int x = 10;
// Heap memory
int* y = (int*)malloc(sizeof(int));
*y = 20;
printf("Stack value: %d\n", x);
printf("Heap value: %d\n", *y);
free(y);
return 0;
}
public class Main {
public static void main(String[] args) {
// Stack memory
int x = 10;
// Heap memory
Integer y = new Integer(20);
System.out.println("Stack value: " + x);
System.out.println("Heap value: " + y);
}
}
Memory representation for the above example:

- x is a local variable stored in stack memory.
- y is a pointer/reference variable stored in the stack.
- The dynamically allocated value 20 is stored in heap memory.
- y holds the address of the heap memory and is used to access the value 20.
- In C and C++, heap memory is explicitly released using free() or delete.
- In Java, heap memory is automatically managed by the Garbage Collector when the object is no longer reachable.
- The basic Stack and Heap concept is the same, although the exact memory management differs between languages.
Stack Memory Allocation
Stack allocation refers to reserving memory in the function call stack for active function calls and their associated data. A new stack frame is created when a function is called and is released when that function returns.
How Stack Allocation Works
- A stack frame is created when a function is called.
- The frame stores information such as local variables, parameters, and the return address.
- Memory is released automatically when the function returns.
- Stack allocation is generally fast because it follows a simple last-in, first-out (LIFO) structure.
- Stack memory is limited, so excessive recursion or large local allocations can cause stack exhaustion.
#include <iostream>
using namespace std;
void calculate()
{
int a = 10;
int b = 20;
int sum = a + b;
cout << "Sum: " << sum << endl;
}
int main()
{
calculate();
return 0;
}
import java.util.*;
public class Main {
public static void calculate() {
int a = 10;
int b = 20;
int sum = a + b;
System.out.println("Sum: " + sum);
}
public static void main(String[] args) {
calculate();
}
}
Output
Sum: 30
Explanation:
- The variables a, b, and sum have automatic storage associated with the execution of calculate().
- A stack frame is created when calculate() is called.
- When calculate() returns, its stack frame is released automatically.
Stack Memory in Recursion
Stack memory is especially important in DSA because recursive function calls use the call stack.
#include <iostream>
using namespace std;
void printNumbers(int n) {
if (n == 0)
return;
cout << n << " ";
printNumbers(n - 1);
}
int main() {
printNumbers(3);
return 0;
}
public class Main {
// Function to print numbers from n to 1
static void printNumbers(int n) {
if (n == 0)
return;
System.out.print(n + " ");
printNumbers(n - 1);
}
public static void main(String[] args) {
printNumbers(3);
}
}
Output
3 2 1
Explanation:
- Each recursive call to printNumbers() creates a new stack frame.
- The calls remain on the stack until the base condition is reached.
- The frames are then removed in reverse order as the functions return.
- Excessive recursion can result in stack overflow.
Heap Memory Allocation
Heap allocation provides dynamically managed storage that can remain available independently of a particular function's execution. In C++, memory can be allocated dynamically using operators such as new and released using delete.
#include <iostream>
using namespace std;
int main() {
int* ptr = new int(10);
cout << "Value: " << *ptr << endl;
delete ptr;
return 0;
}
public class Main {
public static void main(String[] args) {
Integer value = new Integer(10);
System.out.println("Value: " + value);
}
}
value = 10
print("Value:", value)
let value = 10;
console.log("Value:", value);
Output
Value: 10
Explanation:
- ptr is a pointer that stores the address of dynamically allocated memory.
- new int(10) creates an integer in dynamic storage and initializes it to 10.
- delete ptr releases the allocated memory.
- Forgetting to release dynamically allocated memory can result in a memory leak.
Note: The heap memory area is different from the heap data structure used in priority queues and other DSA applications.
Stack and Heap in Dynamic Data Structures
Heap memory is particularly useful when creating dynamic data structures whose size can change during program execution.
Common examples include:
- Linked lists
- Trees
- Graphs
- Dynamically allocated objects
- Other dynamically growing structures
Example: Stack and Heap in a Linked List
#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
Node(int value) {
data = value;
next = nullptr;
}
};
int main() {
Node* head = new Node(10);
cout << head->data << endl;
delete head;
return 0;
}
Output
10
Explanation:
- head is a pointer that stores the address of a dynamically allocated Node.
- new Node(10) creates the node in dynamic storage.
- The node can remain allocated until it is explicitly released.
- This type of dynamic allocation is commonly used when implementing linked lists and other dynamic data structures.
Stack Vs Heap AllocationsÂ
| Parameter | Stack | Heap |
|---|---|---|
| Allocation | Typically automatic | Dynamically managed |
| Lifetime | Usually tied to function or scope | Can extend beyond a function call |
| Management | Automatically managed | Explicitly managed in C++ when using new/delete |
| Access | Generally faster | Generally has more allocation overhead |
| Size | Typically more limited | Typically allows larger dynamic allocations |
| Organization | Follows a LIFO call-stack model | Dynamically managed storage |
| Common DSA Use | Function calls and recursion | Linked lists, trees, graphs, dynamic objects |
| Main Risk | Stack overflow | Memory leaks, dangling pointers, fragmentation |