0% found this document useful (0 votes)
4 views

C++.Module 02

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
4 views

C++.Module 02

Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 15

Stack memory is a region in memory used primarily for managing function calls, local variables,

and the control flow of a program. It operates in a Last-In-First-Out (LIFO) manner, meaning
the last function or variable added is the first to be removed. Stack memory is automatically
managed by the system.

Key Features:

1. Memory Allocation:
o Memory is automatically allocated when a function is called and deallocated when
the function returns.
o No manual intervention is required for memory management.
2. Size:
o Stack memory is relatively small and has a fixed size, typically limited by the
system (usually a few MBs).
o Exceeding the stack's limit results in a Stack Overflow error, which can occur due
to excessive recursion or too many nested function calls.
3. Speed:
o Access to stack memory is fast due to its simple LIFO structure.
4. Scope:
o Variables in stack memory are local to the function they are declared in.
o Once the function completes, the variables are automatically removed from
memory.
5. Memory Layout:
o The stack grows and shrinks as functions are called and return.
o Each function call reserves a block of memory called a stack frame. This stack
frame stores local variables, parameters, and the return address (the point where the
program resumes after the function completes).

Common Use Cases:

• Function parameters and return values.


• Local variables within functions.
• Recursion.
• Control flow structures like loops and conditionals.
• Exception handling.
Purpose:
Heap memory is used for dynamic memory allocation, where the size and lifetime of data are not
known in advance. It is ideal for managing large data structures or objects that need to persist
beyond the scope of function calls.

Key Features:

1. Memory Allocation:
o Memory is allocated explicitly using functions like malloc(), calloc(), or new in
languages like C/C++, and freed using free() or delete.
o In languages like Java and Python, memory is managed through garbage collection,
which automatically reclaims unused memory.
2. Size:
o Heap memory is much larger compared to the stack and is typically limited only by
the system’s available memory.
o It is well-suited for creating large and dynamic data structures such as arrays, linked
lists, trees, and graphs.
3. Speed:
o Access to heap memory is slower than stack memory due to its flexible allocation,
requiring more complex memory management, including searching, fragmentation,
and defragmentation.
4. Scope:
o Variables stored in the heap are globally accessible as long as a pointer or reference
exists. These variables are not restricted to the function in which they were created.
5. Memory Layout:
o Unlike stack memory, heap memory grows and shrinks in a less structured manner,
expanding or contracting based on system resources.
o Manual management of heap memory introduces risks such as memory leaks if
memory is not explicitly deallocated.

Use Cases:

• Data structures like linked lists, trees, and graphs.


• Dynamic arrays where size changes during runtime.
• Object-oriented programming (OOP) where objects are dynamically created and persist
across function calls.
• Memory-intensive applications that need large storage for complex operations.
• File I/O and other operations requiring flexible and long-term data storage.
When to Use Stack vs Heap

1. Stack:
o Use stack memory for small variables with short lifespans, like local variables in
functions.
o Suitable for simple, short-term memory needs.
2. Heap:
o Use heap memory for large or complex data structures that need to persist
beyond the scope of the function that created them.
o Ideal for dynamic data where the size or amount of data is not known at compile
time (e.g., dynamically resizing arrays, linked lists).

Stack and Heap in Different Languages


1. C/C++:
o Stack memory is automatically handled, but heap memory requires manual
allocation and deallocation using malloc()/free() or new/delete.
o It’s crucial to avoid memory leaks by always freeing heap memory after use.
2. Java:
o Stack is used for primitive types and function calls, while heap memory is used for
objects.
o The Java garbage collector automatically reclaims heap memory when no
references to an object remain.
3. Python:
o In Python, all variables are stored on the heap, but the interpreter manages them
internally. There’s no direct access to stack/heap distinction for developers.

Common Issues

1. Stack Overflow:
o Occurs when there are too many nested function calls or when recursion depth
exceeds the stack limit.
o Example: Deep recursion without base case in a recursive function.
2. Memory Leak (Heap):
o Happens when memory is allocated in the heap but not freed after use.
o Over time, it can lead to exhaustion of available memory, causing the program or
system to crash.
3. Dangling Pointer (Heap):
o Refers to a pointer that still points to a location in the heap even after the memory
has been freed, leading to undefined behavior if dereferenced.
Key Differences

Feature Stack Memory Heap Memory


Temporary variables, function
Purpose Dynamic memory allocation
calls
Organization LIFO No specific order
Allocation Automatic Explicit
Deallocation Automatic Explicit
Access Direct Indirect
Size Smaller Larger
Function parameters, local Data structures, dynamic arrays, object-
Use Cases
variables, recursion oriented programming

Visual Representation

Figure: Memory layout


Stack Memory also called Static Memory or Compile Time Memory.
Heap Memory also called Dynamic Memory or Runtime Memory.
Compile Time Error: int a = 10 -> (Since ‘;’ is missing).
Runtime Error: a = 10; b = a/0; (Because division by zero is mathematically undefined).

Compile Ok! Run Ok! Output


প্রোগ্রোম কম্পোইল করলল সবককছু Stack প্মলমোকরলে অ্যোললোলকইট হয়।
Disadvantages of Stack Memory:
o জোয়গো যেটুকু দরকোর েেটুকু আলগ প্েলকই, অ্েথোৎ কম্পোইল টোইলম অ্যোললোলকইট কলর প্েয়।
o ফলল রোে টোইলম প্মলমোকর বোড়োলেো/কমোলেোর মলেো প্কোলেো কোজ করো যোয় েো।
o কোজ প্েষ হলয় প্গলল প্মলমোকরর দখলকৃে জোয়গো প্ছলড় প্দয়।

main()
{
int *a = func();
} এখোলে, main()-এর ‘a’ শুধু func()-এর ‘a’-এর
‘a[0]’-এর অ্যোলেস পোলব, ডোটো পোলব েো। কোরণ,
int* func()
func()-এর কোজ প্েষ হলয় প্গলল Stack প্মলমোকর
{
int a = {2, 5, 6}; প্েলক এর সব ডোটো মু লছ যোলব।

return a;
}

o Array ভ্যোকলউ করটোেথ কলর েো, করটোেথ কলর অ্যোলেস।

Stack প্মলমোকরর এই অ্সু কবধোগুললো সলভ্ কলর Heap প্মলমোকর। Heap প্মলমোকরর ডোটো অ্লটোলমটিককল করমু ভ্ হয় েো;
আমোলদরলক মযোেু য়োকল করমু ভ্ করলে হয়।
Use malloc(), calloc(), or new (based on the language) to allocate memory dynamically in the heap,
accessible via pointers or references. stdlib.h header file is needed to include for malloc and calloc.

C Example (malloc): Memory Allocation


ptr_with_data_type = (cast_data_type*) malloc(number_of_variables * sizeof(data_type));
▪ Purpose: Allocates a specified amount of memory from the heap but does not initialize it.
▪ Use Case: When you need to allocate a block of memory of a specific size at runtime and
manage initialization manually.

int* array = (int*) malloc(5 * sizeof(int)); // Allocate memory


for (int i = 0; i < 5; i++) array[i] = i * 10; // Initialize data
free(array); // Free memory

C Example (calloc ): Contiguous Allocation


ptr_with_data_type = (cast_data_type*) calloc(number_of_variables, sizeof(data_type));
▪ Purpose: Allocates memory for a specified number of elements & initializes all the bits to 0
▪ Use Case: When you need to allocate memory and have it initialized to zero, useful for arrays
or structures that require zero-initialized data.

// Allocate memory and initialize to 0


int* array = (int*) calloc(5, sizeof(int));
for (int i = 0; i < 5; i++) array[i] = i * 10; // Initialize data
free(array); // Free memory

C Example (realloc ): Re-allocation


earlier_ptr = realloc(ptr, number_of_variables * sizeof(data_type));
▪ Purpose: Resizes an existing block of allocated memory. It can grow or shrink the allocated
memory, and may move the memory block if needed.
▪ Use Case: When you need to dynamically adjust the size of a previously allocated memory
block (e.g., expanding a dynamic array as new elements are added).

int* array = (int*) malloc(5 * sizeof(int)); // Allocate initial memory


for (int i = 0; i < 5; i++) array[i] = i * 10; // Initialize data

array = (int*) realloc(array, 10 * sizeof(int)); // Reallocate memory for 10


elements
for (int i = 5; i < 10; i++) array[i] = i * 10; // Initialize new elements

free(array); // Free memory


C++ Example (new):
ptr_with_data_type = new data_type[number_of_variables];
▪ Purpose: Allocates memory for objects or arrays in C++. It also initializes objects if
constructors are defined.
▪ Use Case: Used in C++ for dynamic memory allocation, especially for objects, and can
invoke constructors.

int* array = new int[5]; // Allocate memory


for (int i = 0; i < 5; i++) array[i] = i * 10; // Initialize data
delete[] array; // Free memory

A complete Example (in C++):


#include <bits/stdc++.h>
using namespace std;

int main()
{
cout << new int << endl;

int *ip = new int;

*ip = 11;

cout << ip << endl;


cout << *ip << endl << endl;

float *fp = new float;

*fp = 11.5467;

cout << fp << endl;


cout << *fp << endl;

return 0;
}

Memory Management Notes:

• In C, always pair malloc()/calloc() with free() to avoid memory leaks.


• In C++, always pair new with delete (or delete[] for arrays) to free avoid memory leaks.
• Failure to free dynamically allocated memory results in memory leaks.
Key Points:

• calloc(): Allocates and initializes memory to 0.


• malloc(): Allocates memory without initialization.
• realloc(): Adjusts the size of previously allocated memory.
• new: Allocates memory for objects/arrays in C++, and calling constructors.
• free() (C) or delete[] (C++): Free memory after usage to prevent memory leaks.
• Access heap memory through pointers or references.

❖ Heap প্মলমোকরলক সরোসকর অ্যোলেস করো যোয় েো, Stack প্মলমোকরলক করো যোয়।
❖ Heap প্মলমোকর অ্যোলেস করটোেথ কলর, েোই ডোটো টোইপ অ্েুযোয়ী পলয়ন্টোর কডলেআ করলে হয়।
❖ অ্যোলরই সোইজ বোড়োলে হলল, ককিংবো ফোিংেে প্েলক অ্যোলরই করটোেথ করলে হলল Heap প্মলমোকর অ্যোলেস করলে হয়।

int *a = new int; new int;

Stack Heap

a 1X02A
int *ip = new int[5]; new int;

Stack Heap

ip 1X02A

#include <bits/stdc++.h>

using namespace std;


float *farr = new float[5];

int main()
for (int i = 0; i < 5; i++)
{
{
int *iarr = new int[5];
cin >> farr[i];
}
iarr[0] = 3;
iarr[1] = 4;
for (int i = 0; i < 5; i++)
iarr[2] = 5;
{
iarr[3] = 6;
cout << farr[i] << " ";
iarr[4] = 7;
}

cout << iarr[0] << endl;


return 0;
cout << iarr[1] << endl;
}
cout << iarr[2] << endl;
cout << iarr[3] << endl;
cout << iarr[4] << endl << endl;
To increase the size of an array dynamically in C++, we can use dynamic memory allocation with
the new keyword and manually manage the array resizing. C++ does not have a direct equivalent
to realloc() from C, so we'll need to follow these steps:

1. Allocate a new larger array.


2. Copy the contents from the old array to the new array.
3. Delete the old array.
4. Continue using the new larger array.

#include <bits/stdc++.h>

using namespace std;

int main()
{
int *arr0 = new int[5];

for (int i = 0; i < 5; i++)


{
cin >> arr0[i];
}

for (int i = 0; i < 5; i++)


{
cout << arr0[i] << " ";
}

int *arr1 = new int[7];

for (int i = 0; i < 5; i++)


{
arr1[i] = arr0[i];
}

cout << endl;

arr1[5] = 9;
arr1[6] = 10;

for (int i = 0; i < 7; i++)


{
cout << arr1[i] << " ";
}
delete[] arr0;
cout << endl;

for (int i = 0; i < 5; i++)


{
cout << arr0[i] << " ";
}

delete[] arr1;

return 0;
}

Note:
1. To delete a single variable: delete variable_name;
2. To delete an array: delete[] array_name;
The function allocates the array and returns a pointer to it. The caller function is responsible for
deallocating the array.
#include <bits/stdc++.h>
using namespace std;

int* func()
{
int *arr = new int[5];

for (int i = 0; i < 5; i++)


{
cin >> arr[i];
}

return arr;
}
int main()
{
int *ip = func();

for (int i = 0; i < 5; i++)


{
cout << ip[i] << " ";
}

delete[] ip;
cout << endl;

for (int i = 0; i < 5; i++)


{
cout << ip[i] << " ";
}

return 0;
}

Key Points:

• Dynamic Allocation: Memory for the array is allocated inside the function using new.
• Return by Pointer: The function returns a pointer to the dynamically allocated array.
• Freeing Memory: It is essential to call delete[] in the calling function (i.e., in main())
to release the allocated memory when it is no longer needed.
The ternary operator is a shorthand way to write simple if-else statements. It is also known as
the conditional operator because it evaluates a condition and returns one of two values based on
whether the condition is true or false.

Syntax:

condition ? expression_if_true : expression_if_false;

Example:
#include <bits/stdc++.h>

using namespace std;

int main()
{
int x;

cin >> x;

(x % 2 == 0) ? cout << "Even" : cout << "Odd";

return 0;
}

Key Points:

• The ternary operator is a concise way to write simple conditional statements.


• It can be nested, though this is generally discouraged for readability.
• It is useful when you want to assign a value or return a result based on a condition without
writing full if-else blocks.
Dynamic memory allocation is necessary when the size or lifetime of memory needed by your
program is not known at compile-time or when flexibility is required in managing memory during
runtime. Here are specific situations where dynamic memory allocation is useful or necessary:

1. Variable Size Data Structures

• Scenario: You need data structures (like arrays, lists, etc.) whose size is not fixed or known
in advance.
• Example: Creating an array where the size is determined by user input.
o In static memory allocation, arrays have a fixed size.
o With dynamic memory allocation, you can allocate memory based on the input
size, e.g., allocating memory for an array of n elements, where n is determined at
runtime.

2. Managing Large Data Sets

• Scenario: You need to handle large amounts of data that exceed the capacity of stack
memory.
o Stack memory has limited size, and large allocations on the stack can lead to stack
overflow.
o Heap memory, managed via dynamic allocation, provides more space and allows
for handling larger data structures (like large arrays, matrices, etc.).

3. Lifespan of Objects Beyond Function Scope

• Scenario: You need objects or data to persist beyond the scope of a function or block.
o Local variables are stored in the stack and are destroyed once the function call
ends.
o With dynamic allocation, the memory allocated in the heap can persist and be
accessed even after the function where it was allocated has returned.

4. Linked Data Structures

• Scenario: Data structures like linked lists, trees, or graphs require dynamic memory
allocation because their size can grow or shrink as elements are added or removed.
o These structures are dynamic in nature, and memory must be allocated as nodes are
created and deallocated when nodes are deleted.

5. Flexible Resizing of Data Structures

• Scenario: You want to resize a data structure like an array dynamically during the
execution of the program.
o In static memory allocation, arrays cannot be resized. However, using dynamic
memory allocation with realloc() (in C) or manually reallocating memory (in
C++), you can grow or shrink the size of an array during runtime.

6. Reducing Memory Waste

• Scenario: When the exact amount of memory needed varies, dynamic memory allocation
allows you to allocate exactly the memory required, avoiding memory waste that can
happen with statically allocated, overestimated arrays or buffers.
o Example: You can allocate memory based on the exact size of a file being
processed, instead of pre-allocating a large buffer for potential file sizes.

7. Memory-Intensive Applications

• Scenario: Applications like image processing, databases, or real-time systems often


require large amounts of memory for storing and manipulating data.
o These types of programs benefit from dynamic memory allocation to optimize
memory usage and adjust to varying loads.

8. Custom Memory Management

• Scenario: When you need to implement custom memory management techniques (like
pooling or caching), dynamic memory allocation is essential.
o You can allocate memory only when required and deallocate it when not in use to
optimize the performance of your program.

Examples of Where Dynamic Memory Allocation is Needed:

• Dynamic Arrays: Arrays that grow/shrink during program execution.


• Linked Lists, Trees, and Graphs: Data structures that evolve in size based on user input
or operations.
• Buffer Management: Allocating memory buffers for reading data from files, network,
etc., with sizes that vary during runtime.
• Database Management Systems: Handling large datasets where memory needs to be
dynamically managed.

You might also like