Memory Distribution in C/C++

int globalVar = 1;
static int staticGlobalVar = 1;
void Test()
{
static int staticVar = 1;
int localVar = 1;
int num1[10] = {1, 2, 3, 4};
char char2[] = "abcd";
const char* pChar3 = "abcd";
int* ptr1 = (int*)malloc(sizeof(int) * 4);
int* ptr2 = (int*)calloc(4, sizeof(int));
int* ptr3 = (int*)realloc(ptr2, sizeof(int) * 4);
free(ptr1);
free(ptr3);
}
Questions:
-
Multiple Choice (Options: A. Stack, B. Heap, C. Data Segment (Static Area), D. Code Segment (Constant Area)):
- Where is
globalVar? ___ - Where is
staticGlobalVar? ___ - Where is
staticVar? ___ - Where is
localVar? ___ - Where is
num1? ___ - Where is
char2? ___ - Where is
*char2? ___ - Where is
pChar3? ___ - Where is
*pChar3? ___ - Where is
ptr1? ___ - Where is
*ptr1? ___
- Where is
-
Fill in the blanks:
sizeof(num1)= ____sizeof(char2)= ____strlen(char2)= ____sizeof(pChar3)= ____strlen(pChar3)= ____sizeof(ptr1)= ____
-
What is the difference between
sizeofandstrlen?
Explanation:
- Stack: Stores non-static local variables, function parameters, return values, etc. The stack grows downwards.
- Memory Mapping Segment: An efficient I/O mapping mechanism used to load shared dynamic libraries. It can also be used for inter-process communication via shared memory.
- Heap: Used for dynamic memory allocation at runtime. The heap grows upwards.
- Data Segment: Stores global and static data.
- Code Segment: Contains executable code and read-only constants.
Dynamic Memory Management in C: malloc/calloc/realloc/free
void Test()
{
int* p1 = (int*)malloc(sizeof(int));
free(p1);
// What is the difference between malloc, calloc, and realloc?
int* p2 = (int*)calloc(4, sizeof(int));
int* p3 = (int*)realloc(p2, sizeof(int) * 10);
// Do we need to free(p2) here?
free(p3);
}
C++ Memory Management
C memory management can still be used in C++, but it has limitations and can be cumbersome. Therefore, C++ introduces its own memory management using new and delete operators.
1. new and delete for Built-in Types
void Test()
{
// Dynamically allocate a single int
int* ptr4 = new int;
// Dynamically allocate a single int initialized to 10
int* ptr5 = new int(10);
// Dynamically allocate an array of 3 ints
int* ptr6 = new int[3];
delete ptr4;
delete ptr5;
delete[] ptr6;
}

Note: Use
newanddeletefor single-element allocation/deallocation, andnew[]anddelete[]for arrays. Ensure they are used in matching pairs.
2. new and delete for User-Defined Types
#include <iostream>
using namespace std;
class A
{
public:
A(int a = 0)
: _a(a)
{
cout << "A():" << this << endl;
}
~A()
{
cout << "~A():" << this << endl;
}
private:
int _a;
};
int main()
{
// The key difference between new/delete and malloc/free is that new/delete
// call the constructor and destructor for user-defined types.
A* p1 = (A*)malloc(sizeof(A)); // Only allocates memory
A* p2 = new A(1); // Allocates memory and calls constructor
free(p1); // Only frees memory
delete p2; // Calls destructor and frees memory
// For built-in types, they behave almost identically
int* p3 = (int*)malloc(sizeof(int));
int* p4 = new int;
free(p3);
delete p4;
A* p5 = (A*)malloc(sizeof(A) * 10);
A* p6 = new A[10];
free(p5);
delete[] p6;
return 0;
}
Note:
newcalls the constructor anddeletecalls the destructor for user-defined types, whereasmallocandfreedo not.
Differecnes Between Dynamic Memory Allocation in C and C++
1. For Built-in Types
There is no significant difference between new/delete and malloc/free when dealing with built-in types.
2. For User-Defined Types
#include <iostream>
using namespace std;
class Date
{
friend ostream& operator<< (ostream& cout, const Date& d);
public:
Date(int year = 2023, int month = 12, int day = 31)
{
_year = year;
_month = month;
_day = day;
}
private:
int _year;
int _month;
int _day;
};
int main()
{
Date* p1 = (Date*)malloc(sizeof(Date)); // Error if no default constructor? No, but the object is not initialized
Date* p2 = new Date; // Requires a default constructor
free(p1);
delete p2;
return 0;
}
ostream& operator<< (ostream& cout, const Date& d)
{
cout << d._year << " " << d._month << " " << d._day << endl;
return cout;
}
When new allocates space for a user-defined type, it first calls operator new (which internally wraps malloc), and then calls the constructor to initialize the allocated memory.
When delete releases the memory of a user-defined type, it first calls the destructor, and then calls operator delete (which internally wraps free) to destroy the space.
operator new and operator delete are global functions.
A* p1 = (A*)malloc(sizeof(A));—p1is of a built-in type and will not automatically envoke the constructor or destructor.
To explicitly call the constructor and destructor on memory allocated with malloc:
// Placement new: call constructor
new(p1) A;
// Explicit destructor call
p1->~A();