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
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
Function Pointer to Member Function in C++
In C++, function pointers enable users to treat functions as objects. They provide a way to pass functions as arguments to other functions. A function pointer to a member function is a pointer that points to a non-static member function of a class. In this article, we will learn how to use a functio
3 min read
Useful Inbuilt Functions in C++
In-built functions in C++ are those functions that are part of C++ standard libraries. The purpose of inbuilt functions is to provide common and essential functionality that is frequently required in the programming. In this article, we will look at some of the commonly used inbuilt functions in C++
7 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
exchange() Function in C++ 14
The exchange() function is a built-in function in C++ 14 defined in the <utility> header. The exchange() function copies new value to old value and it will return the old value. Syntax: exchange(old, new) Parameters: The function needs two parameters. The parameter needs to be set.The paramete
2 min read
How to Join a Thread in C++?
In C++, a thread is a basic element of multithreading that represents the smallest sequence of instructions that can be executed independently by the CPU. In this article, we will discuss how to join a thread in C++. How to Join a Thread in C++?Joining a thread is a means to wait for the thread to c
2 min read