0% found this document useful (0 votes)
7 views3 pages

C++ Memory Management Basics

The document discusses C++ memory management using pointers and dynamic memory allocation. It explains that void pointers can point to memory of any type, and are useful when the pointer type is unknown. The new and delete keywords are used to dynamically allocate and free memory as needed. New returns a pointer to the allocated memory, which must later be freed using delete. Examples demonstrate allocating memory for arrays at runtime based on user input, avoiding wasted memory for fixed-size arrays.
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)
7 views3 pages

C++ Memory Management Basics

The document discusses C++ memory management using pointers and dynamic memory allocation. It explains that void pointers can point to memory of any type, and are useful when the pointer type is unknown. The new and delete keywords are used to dynamically allocate and free memory as needed. New returns a pointer to the allocated memory, which must later be freed using delete. Examples demonstrate allocating memory for arrays at runtime based on user input, avoiding wasted memory for fixed-size arrays.
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

C++ - Memory

VOID THE VERY EXCEPTIONAL TYPE


Despite the fact that the void type doesn't represent any useful value it is possible to declare
pointers to this type as in the following example
void *ptr;
You may ask how to use a pointer that points exactly at nothing and ask what such a pointer may
be useful for. That kind of pointer, which is precisely of the type void *, is named an amorphous
pointer to emphasize the fact that it is able to point to any value of any type. It means that the pointer
of type void * cannot be subject to the dereference operator, so you must not write anything similar
to this:
*ptr = 1;
It can be justified by the argument that if ptr was of type void * , *ptr would be of type void and the
assignment of a value of type int is prohibited by the compiler.
However, pointers of type void * are very useful when you need to have a pointer, but do not know
what purpose it may be used for in the future. As soon as it is clear, the pointer can easily be
converted into another pointer of the desired type (of course, a pointer one) which is always feasible
and does not cause any loss of accuracy.
MEMORY ON DEMAND
In the examples presented so far, memory management has taken place outside of our
consciousness. The parts of memory which we used to store values were hidden behind the names of
scalars and arrays. They appeared as soon as they had been declared and gone when our program
had ended operation. All work associated with memory allocation was organized by the compiler and
we didn't care how it works. This is how it should be - high level languages and their compilers are
designed to exonerate the developers' minds of such responsibilities.
It frequently happens that the developer wants to have full control over how much memory is used
and when exactly it is used. This is especially important when you do not know in advance, what the
size of the data to be processed is. To manage the allocating and freeing of the memory the C++
language provides two specialized keywords. Here, we present both of them for you
new
delete
The new keyword is used to request creation of a new memory block. When the allocated memory
is no longer needed and/or utilized, it would be a good habit to return it to the operating system. This
is done by the delete keyword.
The new keyword that performs the first-mentioned task can be used in the following way
float *array = new float [20];
int *count = new int;
it needs precise specification regarding the entity being created; it must be expressed as a
type description and if the created entity is an array, the size of the array must be given too
(like in the first example)
the new returns a pointer of type conforming the newly created entity
the newly allocated memory area is not filled (initiated) in any way so you should expect
that it contains just garbage
When the memory is no longer necessary we can release (free) it using the delete keyword in the
following way
delete [ ] array;
delete count;
we use delete [] form if we want to free the memory allocated for an array and delete
otherwise
you can only release the entire allocated block, not a part of it
after performing the free function all the pointers that point to the data inside the freed area
become illegal; attempting to use them may result in an abnormal program termination.

SS Puram, Tumkur | M.G. Road, Tumkur | Ph: +91-9620160796

C++ - Memory
We are going to present a complete, although not very useful, program that demonstrates the use of
both keywords.
We declare a variable called ptr which will point to the data of type int (the pointer's type is int
*); no value is assigned to this variable initially
We use the new keyword to allocate a block of memory sufficient to store a float array
consisting of 5 elements;
We make use of the newly allocated array (to be precise, a vector) and next we release it
using the delete keyword
We want you to pay attention to the fact that the pointer returned by new is treated as if it is an array.
Surprising?
The handling of the dynamic arrays (created during the run of the program) is no different than using
regular arrays declared in the usual way.
We owe it to the [] operator. Regardless of the nature of the array we can access its elements in the
same way.
#include <iostream>
using namespace std;
int main(void) {
float *arr;
arr = new float[5];
for(int i = 0; i < 5; i++)
arr[i] = i * i;
for(int i = 0; i < 5; i++)
cout << arr[i] << endl;
delete [] arr;
return 0;
}
The possibility of allocating the amount of memory which is really needed lets us write programs that
can adapt themselves to the size of the currently processed data. Let's go back to the bubble sort
algorithm that we presented previously. That program assumed that there were exactly 5 numbers to
sort. This is obviously a serious inconvenience. It may happen one day that we want to sort 10,000
numbers and sometimes hundreds of them. You can of course, declare an array of the maximum
predictable size but it would be unreasonable. A much better way is to ask the user how many
numbers will be sorted and then allocate the array of the appropriate size.
Let's try to start with a simpler example. In the following program we allocate an array containing 5
elements of type int, set their values, sum them up and, finally, release the previously allocated
memory.
int *tabptr, sum = 0;
tabptr = new int[5];
for(int i = 0; i < 5; i++)
tabptr[i] = i;
sum = 0;
for(int i = 0; i < 5; i++)
sum += tabptr[i];
delete [] tabptr;
The improved bubble sort program goes here We encourage you to compile and run the program
yourself.
#include <iostream>
using namespace std;

SS Puram, Tumkur | M.G. Road, Tumkur | Ph: +91-9620160796

C++ - Memory
int main(void) {
int *numbers, how_many_numbers;
int aux;
bool swapped;
cout << "How many numbers are you going to sort? ";
cin >> how_many_numbers;
if( how_many_numbers <= 0 || how_many_numbers > 1000000) {
cout << "Are you kidding?" << endl;
return 1;
}
numbers = new int[how_many_numbers];
for(int i = 0; i < how_many_numbers; i++) {
cout << "\nEnter the number #" << i + 1 << ": ";
cin >> numbers[i];
}
do {
swapped = false;
for(int i = 0; i < how_many_numbers - 1; i++)
if(numbers[i] > numbers[i + 1]) {
swapped = true;
aux = numbers[i];
numbers[i] = numbers[i + 1];
numbers[i + 1] = aux;
}
} while(swapped);
cout << endl << "The sorted array:" << endl;
for(int i = 0; i < how_many_numbers; i++)
cout << numbers[i] << " ";
cout << endl;
delete [] numbers;
return 0;
}

SS Puram, Tumkur | M.G. Road, Tumkur | Ph: +91-9620160796

Common questions

Powered by AI

A void pointer in C++ is a special type of pointer that can point to any data type, which makes it versatile for scenarios where the specific data type is not known at compile time . This characteristic is beneficial because it allows developers to write generic code that can handle data of various types without requiring specific type definitions. Additionally, void pointers can be particularly useful in systems programming and in developing libraries where flexibility is needed to handle various data structures . However, it's important to note that void pointers cannot be dereferenced directly without casting to another pointer type .

Initializing dynamically allocated memory in C++ is critical as uninitialized memory contains garbage values, leading to unpredictable behavior if accessed directly in computations or logic . Uninitialized memory can result in bugs that are difficult to identify, often manifesting as incorrect program outputs or crashes. While the 'new' keyword allocates memory, it does not automatically initialize it, leaving the contents in an indeterminate state. To prevent such issues, developers can explicitly initialize allocated memory immediately after allocation, either through constructors or manual setting of default values .

The provided C++ implementation of the bubble sort algorithm effectively handles varying numbers of inputs by prompting the user to specify the number of elements to sort at runtime. This value is then used to dynamically allocate an array of the appropriate size using the 'new' keyword . The program reads each number into the array, processes the bubble sort, and finally releases the allocated memory using the 'delete[]' operator after sorting is complete. This approach enables the program to adapt to different input sizes, optimizing memory usage and processing efficiency .

Dynamic arrays enhance program efficiency in fluctuating data size scenarios by enabling the program to allocate memory on-the-fly, matching the exact data requirements without reserving excessive memory upfront . This ability reduces memory waste that occurs when maximum sizes are anticipated but rarely used, as seen in fixed-size arrays. Additionally, it optimizes processing time and resource management, since the program does not handle unnecessary data structures, leading to a leaner program footprint and responsive performance .

The strategy of employing dynamic memory allocation for algorithms like sorting in C++ is advantageous for creating scalable and flexible solutions that can handle varied input sizes efficiently. This approach avoids the constraints of fixed-size arrays, reducing memory overhead by allocating just what is necessary, which is crucial for optimizing resource utilization in real-world applications. However, challenges include the need for careful memory management to prevent leaks and dangling pointers, requiring the implementation of rigorous allocation-checking and deallocation practices . Furthermore, the overhead of dynamic allocation, such as allocation and deallocation time, must be considered, as it could affect performance in time-sensitive applications . Overall, while powerful, dynamic allocation requires careful implementation to ensure robustness and efficiency.

In C++, ensuring pointers do not reference freed memory involves setting pointers to nullptr immediately after memory is deallocated . This action contributes to preventing dangling pointers, which occur when pointers retain addresses of freed memory, potentially leading to undefined behavior and program crashes if dereferenced. While this method effectively prevents the accidental use of invalidated pointers, it relies heavily on disciplined coding practices. There is no automatic safeguard for this situation in C++, which makes it crucial for developers to consistently apply this practice throughout the code .

Using the 'new' keyword for dynamic memory allocation in C++ can lead to several risks, including memory leaks and undefined behavior if not handled properly. When memory allocated with 'new' is no longer needed, it must be deallocated using 'delete' or 'delete[]' to avoid memory leaks . Failure to do so results in reserved memory that cannot be reused, leading to increased memory consumption and potentially exhausting system resources. Another risk is accessing memory after it has been deallocated, which leads to undefined behavior and can cause program crashes . To mitigate these risks, developers should ensure that every 'new' allocation has a corresponding 'delete' operation, and pointer variables are set to nullptr immediately after deletion to avoid dangling pointers .

In type-safe languages like C++, using void pointers has specific implications due to the absence of a defined data type. While void pointers offer flexibility by allowing function and logic implementations that handle multiple data types, they bypass type safety checks that are inherent in C++ . Consequently, when converting void pointers back to their respective data types, developers must ensure type correctness to prevent runtime errors and undefined behavior. This necessitates explicit type casting, often placing additional responsibility on the programmer to maintain accuracy and avoid common coding pitfalls associated with misuse or incorrect casting .

Dynamic memory allocation for arrays allows a program to allocate the exact amount of memory needed at runtime, which provides flexibility and efficiency . This approach is advantageous over fixed-size arrays, which are limited by their predetermined size, as it allows the program to handle varying sizes of data input, adapting dynamically according to the requirements. This is particularly useful in cases where the number of elements is not known beforehand, such as user input-driven applications. Dynamic allocation prevents the wastage of memory seen in allocating large fixed-size arrays for maximum anticipated data sizes .

In C++, when working with dynamically allocated arrays, the 'delete' operator should be used with the '[]' bracket notation, like 'delete[] array', to properly deallocate the memory block associated with the array . This is crucial because the 'new' keyword understands whether it is allocating a single object or an array of objects, and the same understanding applies to 'delete'. If you omit the '[]', only the first element of the array might be deallocated, leaving the rest of the memory block inaccessible and causing a memory leak. Therefore, using 'delete[]' ensures the entire array is freed correctly .

You might also like