In C++, we often need to handle data storage issues. Sometimes, we may not know how much memory is required, or need to dynamically adjust the memory size based on runtime conditions. In such cases, static memory allocation (such as directly defining variables) is insufficient, and dynamic memory allocation becomes necessary.
Why Dynamic Memory Allocation?¶
In our daily coding, static memory allocation (e.g., int a; or char s[20];) determines the memory size at compile time and is automatically managed by the compiler. However, static memory lacks flexibility for scenarios like storing an uncertain number of data points (e.g., multiple numbers input by the user) or temporarily requiring a large block of memory.
Dynamic memory allocation allows us to request memory from the “heap” at runtime based on actual needs and manually release it after use. The heap is a flexible, independent memory area, but it requires careful management to avoid memory leaks.
Simple Differences Between Dynamic Memory, Heap, and Stack¶
- Stack: Automatically allocated and freed by the compiler, used for local variables, function parameters, etc. It has limited size and is fast.
- Heap: A dynamically requested memory area during program execution, with flexible size but manual management by the programmer (requires explicit release).
new and delete are the core tools for operating on heap memory.
new Operator: Allocating Memory on the Heap¶
To allocate memory on the heap, we use the new operator. Its syntax is straightforward:
1. Allocating a Single Object¶
Type* pointer = new Type; // Allocates memory for one object of type Type
Example: Allocate a dynamic int variable:
int* p = new int; // p points to a heap-allocated int
We can access or modify the memory via the pointer:
*p = 100; // Store 100 in the memory pointed to by p
cout << "Value of dynamic variable: " << *p << endl; // Output: 100
To initialize the memory during allocation, add initial values in parentheses after new:
int* num = new int(20); // Directly initialize to 20
cout << "Initialized variable: " << *num << endl; // Output: 20
2. Allocating an Array¶
For a collection of data (e.g., an array), use new[]:
Type* arrayPointer = new Type[arraySize]; // Allocates memory for an array of Type
Example: Allocate a dynamic array of 5 ints:
int* arr = new int[5]; // arr points to an array of 5 ints
Array elements are uninitialized by default (values may be random). To initialize them (e.g., to 0):
int* arr = new int[5](); // All elements initialized to 0
Access elements via subscripts:
for (int i = 0; i < 5; ++i) {
arr[i] = i * 2; // Assign values: 0, 2, 4, 6, 8
}
for (int i = 0; i < 5; ++i) {
cout << "arr[" << i << "] = " << arr[i] << endl;
}
delete Operator: Freeing Heap Memory¶
Memory allocated with new is not automatically freed. It must be manually released using delete or delete[] to avoid memory leaks (memory that is never released, causing the program to crash eventually).
1. Freeing a Single Object¶
Use delete to release memory for a single object:
int* p = new int(100);
// Use p...
delete p; // Frees the memory pointed to by p; *p is now invalid
2. Freeing an Array¶
Use delete[] to release memory for an array (critical: delete alone will only free the first element):
int* arr = new int[5];
// Use arr...
delete[] arr; // Must use delete[] to free the entire array
Common Errors and Precautions¶
- Forgetting to Free Memory: Failing to
deleteafternewcauses memory leaks:
int* p = new int(5);
// Use p...
// Missing: delete p; // Memory remains occupied
- Using
deletefor Arrays: Usingdeleteinstead ofdelete[]for arrays only frees the first element:
int* arr = new int[10];
delete arr; // Error! Should use delete[] arr;
- Double Freeing Memory: A pointer cannot be
deleted twice (undefined behavior):
int* p = new int;
delete p;
delete p; // Error! Double free causes program crash
Summary¶
Dynamic memory allocation enables flexible memory management at runtime, with new and delete as core tools:
- new allocates single objects (new Type) or arrays (new Type[size]).
- delete frees single objects, and delete[] frees arrays.
- Always match allocation and deallocation: use delete for single objects and delete[] for arrays to avoid leaks or crashes.
Proper use of dynamic memory improves efficiency, but strict attention to allocation and release is critical. Adopting good habits ensures robust memory management.