In C++, pointers can be used for various purposes such as storing the address of a variable, allocated objects on the heap, passing functions to other functions, iterating over elements in arrays, and so on. But many problems arise when pointers are not handled properly. In this article, we will learn about dangling pointers, how they occur and how to deal with them.
Dangling Pointer in C++
What is a Dangling Pointer in C++?
In C language, a pointer that points to a memory location that has been deallocated earlier in the program is called Dangling Pointer.
A dangling pointer is a very common occurrence that generally occurs when we use the 'delete' to deallocate memory that was previously allocated and the pointer that was pointing to that memory still points to the same address. There are also other cases which leads to the pointer being the dangling pointer:
Cases that Leads to Dangling Pointer in C++
- Deallocation of Memory using delete or free().
- Referencing the Local Variable of the function after it is executed.
- Variable goes out of scope.
For Example
int* ptr = new int(5);
delete ptr; // ptr now becomes a dangling pointer
Examples of Dangling Pointer in C++
Example 1: Dangling Pointer by Memory Deallocation using delete.
The below program demonstrates how a pointer becomes a dangling pointer when the dynamic memory is deallocated using delete or in C++.
C++
// C++ program demonstrating how a dangling pointer is
// created
#include <iostream>
using namespace std;
int main()
{
// Allocating memory
int* ptr = new int(5);
// Deallocating memory
delete ptr;
// Now, ptr becomes a dangling pointer
cout << "ptr is now a dangling pointer" << endl;
return 0;
}
Outputptr is now a dangling pointer
Example 2: Dangling Pointer Created by Accessing Local Variable of Function After its Execution
C++
// C++ program to demonstrate how the accessing of functions
// local variable after it is executed results in dangling
// pointer
#include <stdio.h>
int* getDanglingPointer()
{
int localVar = 42;
// Returning the address of a local variable
return &localVar;
}
int main()
{
int* danglingPtr = getDanglingPointer();
// Undefined behavior
printf("Value of dangling pointer: %d\n", *danglingPtr);
return 0;
}
Output
{Segmentation Fault}
Example 3: Dangling Pointer Created by Accessing Variable Out of Scope.
C++
// C++ program to demonstrate how the accessing a variable
// outisde its scope results in dangling pointer
#include <stdio.h>
int main()
{
int* danglingPtr;
// block scope
{
int var = 210;
danglingPtr = &var;
}
// Undefined behavior
printf("Value of dangling pointer: %d\n", *danglingPtr);
return 0;
}
The above program will lead to undefined behaviour or segmentation fault or you can also get the value of the variable. It is unpredictable.
Why is it important to handle Dangling Pointers?
Handling dangling pointers is important for maintaining the integrity and stability of a program. If a program attempts to access or modify the memory through a dangling pointer, it can lead to unpredictable behaviour, including crashes and data corruption as shown by the above examples.
By handling dangling pointers properly, we can improve the reliability and security of the program and prevent any unpredictable access to any memory location.
How to Handle Dangling Pointers in C++?
The methods of handling dangling pointers vary depending on the cases it is being created. Following is the list of all the methods using which we can prevent the dangling pointers:
1. Assign NULL or nullptr to the Pointers that are Not in Use
Make a habit that, whenever we are done with the pointer, always assign it to NULL or nullptr and whenever you access any variable, we can check if the pointer is NULL or nullptr and then access it.
C++
// C++ program to illustrate how to handle null pointer.
#include <iostream>
using namespace std;
int main()
{
// allocating memory
int* value = new int(11);
// freeing it
delete value;
// assigning null
value = nullptr;
// checking null before accessing value
if (value == nullptr) {
cout << "Memory is deallocated." << endl;
}
else {
cout << "Value: " << value << endl;
}
return 0;
}
OutputMemory is deallocated.
2. Using Smart Pointers
Smart pointers are the new feature of C++ 11 that are the wrapper classes over the raw pointer. These pointer are specifically designed to avoid all these cases of dangling pointers along with other common pointer risks and errors.
C++
#include <iostream>
#include <memory>
using namespace std;
// Function returns a smart pointer
shared_ptr<int> getSmartPointer()
{
return make_shared<int>(42); // Return a smart pointer
}
int main()
{
// Call the function and store the returned smart
// pointer
shared_ptr<int> ptr = getSmartPointer();
cout << "Value: " << *ptr << endl;
// Smart pointer automatically handles memory
// deallocation
return 0;
}
To learn more about them, refer to the article - Smart Pointer in C++
3. Use Dynamic Memory Allocation for the Local Variables that are to be returned.
The memory allocated using new or malloc in C++ will not be deallocated till we do it manually using delete or free(). We can use this type of memory for local variables of a function that we want to return to the caller function.
Example:
C++
// C++ Program to illustrate how to return dynamically
// created funtion's local variable.
#include <iostream>
using namespace std;
int* getPointer()
{
// Allocate on the heap
int* localVar = new int(42);
return localVar;
}
int main()
{
// getting the pointer to the variable
int* ptr = getPointer();
cout << "Value: " << *ptr << endl;
// manually deallocating it
delete ptr;
// setting ptr to null
ptr = NULL;
return 0;
}
4. Using References instead of Pointers
References are builtin features in C++ and are the variables that reference the another variables. The references are safer as compared to pointers but we cannot use them to replace pointers in all cases. So, we should use it wherever it is possible to use instead of pointers.
Example
C++
#include <iostream>
using namespace std;
int& getReference()
{
// Use static to extend the lifetime
static int localVar = 42;
return localVar;
}
int main()
{
int& ref = getReference();
cout << "Value: " << ref << endl;
return 0;
}
Similar Reads
Creating array of pointers in C++
An array of pointers is an array of pointer variables. It is also known as pointer arrays. We will discuss how to create a 1D and 2D array of pointers dynamically. The word dynamic signifies that the memory is allocated during the runtime, and it allocates memory in Heap Section. In a Stack, memory
5 min read
Object Delegation in C++
Introduction: Every programming language that is based on an object-oriented concept tries to connect everything to the real world.Similarly, C++ languages use classes, Inheritance, Polymorphism to connect the concept with the real-world concept.In this article, the topic of discussion will be what
2 min read
How to Create a Pointer to a Function in C++?
In C++, a function pointer is a variable that stores the address of a function that can later be called through that function pointer. It is useful for passing functions as parameters to other functions(callback functions) or storing them in data structures. In this article, we will learn how to use
2 min read
Overloading function templates in C++
Template: A template is a tool that reduces the efforts in writing the same code as templates can be used at those places.A template function can be overloaded either by a non-template function or using an ordinary function template. Function Overloading: In function overloading, the function may ha
3 min read
Cascading of Input/Output Operators in C++
Prerequisite: Operator Overloading in C++, Types of Operator Overloading When an object calls an operator function by passing an argument and the returned value of the operator function calls the next operator function in the same expression, it is called as cascading of operators. Below are the exa
5 min read
Array of Pointers to Strings in C++
In C++, an array is a homogeneous collection of data that is stored in a contiguous memory location. We can store almost all types of data as array elements. In this article, we will learn how to store the array of pointers to strings in C++. Array of Pointers to Strings in C++A pointer to a string
6 min read
erase_if() Function in C++
The std::erase_if() is a utility introduced in C++20 that is used to remove elements from containers based on a specified condition. This function erases all elements that satisfy a given predicate from standard containers like std::vector, std::deque, std::list, std::forward_list, std::string, and
3 min read
Managing Console I/O operations in C++
Every program takes some data as input and generates processed data as an output following the familiar input process output cycle. It is essential to know how to provide the input data and present the results in the desired form. The use of the cin and cout is already known with the operator >
4 min read
Type Qualifiers in C++
In C++, type qualifiers are keywords that modify the properties of data types, influencing how variables, pointers, or references can be used. These qualifiers enhance variable declarations by providing additional information on their access and usage constraints, ensuring more controlled and secure
5 min read
How to Return a Pointer from a Function in C++?
In C++, we can return a pointer from a function which is useful when we want to return large data structures that cannot be returned by value. However, it must be done carefully to avoid memory leaks, dangling pointers, and other issues related to dynamic memory management. In this article, we will
2 min read