In this tutorial, you will learn about the dangling pointer, void pointer, NULL, and wild pointer in C. I have already written a brief article on these topics. The main aim of this blog post to give you a quick introduction to these important concepts. Also, I will describe different states of the pointer with common tips to protect the code from the bad effect of pointers.
Despite the fact that pointers are an important tool, sometimes code get crashes due to improper use of pointers. If you do not use the pointers in a proper way, the pointer can become a curse and it can create a very crucial issue (segmentation fault or bus error). So let’s see the different states of pointers in C programming.
What is a dangling pointer in C?
Generally, daggling pointer arises when the referencing object is deleted or deallocated and your pointer still pointing to a memory location. It creates a problem because the pointer is pointing to the memory that is not available. When the user tries to dereference such type of pointer then it shows the undefined behavior and can be the cause of the segmentation fault.
In simple words, you can say that “a dangling pointer is a pointer that points to invalid memory or to memory that is not valid anymore and can be the cause of the undefined behavior”. Let’s see the below image for a better understanding.
In the image Pointer1, Pointer2 is pointing to a valid memory object but Pointer3 is pointing to a memory object that has been already deallocated. So Pointer3 becomes a dangling pointer when you will try to access the Pointer3 then you will get the undefined result or segmentation fault.
Important causes of the dangling pointer in C language
There a lot of cause to arise the dangling pointers in C language but here I am describing some common cause that creates the dangling pointer in C.
Access a local variable outside of its lifetime
Basically, lifetime means “Storage Duration”. If an identifier is referred to outside of its lifetime, the behavior is undefined.
A local variable has a local lifetime and it belongs to their block where it is declared. Whenever control comes out to the block then memory reserved for it will be free automatically.
If a local variable is referred to by pointers outside of its lifetime, then the behavior will be undefined and the value of the pointer becomes indeterminate. Let see the below code for a better understanding.
In the below code, we try to read the value of “Data” (integer variable) outside of their block (scope) through the “piData” (integer pointer), so the behavior of the integer pointer (piData) will be undefined.
#include <stdio.h> int main(void) { int * piData; { //block int Data = 27; piData = &Data; } //piData is dangling pointer printf("piData = %d\n", *piData); return 0; }
After destroying the stack frame
The stack frame that is allocated to a function is destroyed after returning the control from the function. The common mistake performed by the developer is that to return the address of the stack-allocated variable from the function. If you tried to access the returning address from the pointer, you will get an unpredictable result or might get the same value but it is very dangerous and need to avoid. Let’s see an example program,
In the below code, the “Data” variable has the scope and life only in the function “Fun”. If you try to read the value of Data after calling the Fun() using the pointer may you will get the correct value (5), but any functions called thereafter will overwrite the stack storage allocated for Data with other values and the pointer would no longer work correctly.
So in the below code piData is a dangling pointer that is pointing to a memory that is not available.
#include<stdio.h> int *Fun() { int Data = 5; //Local variable return &Data; //Address of local variable } int main() { int *piData = Fun(); //Returning address of the local variable printf("%d", *piData); return 0; }
If you already know how to program and just want to learn C++, you can start with the C++ Fundamentals course. The good thing is that TRIAL IS FREE
Duration: Approx. 43 hours
Rating: 4.6
Deleting the memory explicitly
The compiler handles static and auto-allocated memory but if the user allocates the memory from the heap, then it is the responsibility of the user to free the allocated heap memory. In “C language” malloc, calloc, and realloc library function are used to allocate the memory at runtime and the “free” function is used to deallocate the allocated memory. The jumbled combination of malloc (calloc, realloc) and free is born the dangling pointers.
The problem invokes, whenever the programmer has freed the allocated memory and tries to access the freed memory. You will be lucky if you not get the segmentation fault after using the freed memory. It is a very common mistake that is generally done by the developers.
Let’s see the below code, After deallocating the memory, “piData” becomes the dangling pointer and if you try to access the “piData”, your program could be crash.
#include<stdio.h> #include<stdlib.h> int main() { int *piData = NULL; piData = malloc(sizeof(int)* 10); //creating integer of size 10. free(piData); //free the allocated memory *piData = 10; //piData is dangling pointer return 0; }
Uninitialized pointer
An uninitialized pointer is called a dangling pointer (also called a wild pointer) because we don’t know where it points. The behavior of an uninitialized pointer is unpredictable. Example,
//p is uninitialized pointer int* p;
You can see another related article,
How to avoid the dangling pointer errors
As we know the behavior of the dangling pointers is undefined, so it is very important to avoid the born of dangling pointers. The common mistake that is done by many programmers is that not assigning the NULL explicitly after freeing the dynamically allocated memory. So It is a very good habit to assign the NULL after deallocation of the dynamically allocated memory.
#include<stdio.h> #include<stdlib.h> int main() { char *pcData = NULL; pcData = malloc(sizeof(char)* 10); //creating integer of size 10. free(pcData); /* piData can be becomes a dangling pointer */ pcData = NULL; //piData is no longer dangling pointer return 0; }
Apart from that, another mistake is to return the address of the local variable (stack variable) from the function, it is also a cause to create a dangling pointer. Using the static variable we can resolve the problem because the lifetime of the static variable is the entire run of the program.
#include<stdio.h> int *foo() { static int Data = 6; return &Data; } int main() { int *piData = NULL; piData = foo(); // Now piData is Not a dangling pointer as it points // to static variable. printf("%d",*piData); return 0; }
Output: 6
Another important point which you should remember is that before accessing the array you should validate the array boundary. Because If you try to access the array outside of the boundary, it also considers a dangling pointer and shows the undefined behavior.
What is the wild pointer?
A pointer that is not initialized properly prior to its first use is known as the wild pointer. Uninitialized pointer’s behavior is totally undefined because it may point to some arbitrary location that can be the cause of the program crash, that’s is the reason it is called a wild pointer.
In other words, we can say every pointer in programming languages that are not initialized either by the compiler or programmer begins as a wild pointer.
Note: Generally, compilers warn about the wild pointer.
int *piData; //piData is wild pointer
What is a NULL pointer?
According to the C standard, an integer constant expression with the value 0, or such an expression cast to type void *, is called a null pointer constant. If a null pointer constant is converted to a pointer type, the resulting pointer, called a null pointer.
int *piData = NULL; // piData is a null pointer
Few important points of the NULL pointer
- According to the C standard, 0 is also a null pointer constant. It is a valid statement “int *ptr = 0 ;” and “ptr” is a null pointer.
- If we compare the null pointer from the pointer that’s is pointing to any object or function, the comparison shall be unequal. The uninitialized pointer does not give any such type of guarantee.
- If we convert the null pointer to another pointer of type “T”, the resulting pointer will be a null pointer of that type “T”.
- In C, two null pointers of any type are guaranteed to compare equal.
- In C, if you try to dereference the NULL pointers, the result will be segmentation faults.
- If T is a null pointer, &*T is equivalent to T.
Use of null pointer in C
- A pointer that is not pointing to the address of a valid object or valid memory should be initialized to NULL. It prevents the pointer to become a dangling pointer and ensures the programmer that the pointer is not pointing anywhere.
char *pcData = NULL; //Prevent to become dangling pointer
- A very good habit to check the validity of the pointers before using them. It prevents the crashing of the code and unwanted result. The null pointer helps you in error handling.
#include<stdio.h> #include<stdlib.h> int main() { int *piData = NULL; piData = malloc(sizeof(int)*10); if(NULL == piData) { //exit } else { //code free(piData); //free after the use } return 0; }
- There is a lot of library function in C where pointer arguments are optional. So passing the null pointer to a function argument is useful when you don’t want to pass any valid memory or object address. For example,
//Some arguments could be NULL int pthread_create(pthread_t *restrict thread, const pthread_attr_t *restrict attr, void *(*start_routine)(void *), void *restrict arg);
What is void or Generic pointers in C?
A void pointer is a generic pointer, it has no associated data type. It can store the address of any type of object and it can be type-casted to any type. According to the C standard, the pointer to void shall have the same representation and alignment requirements as a pointer to a character type. A void pointer declaration is similar to the normal pointer, but the difference is that instead of data types we use the void keyword.
Syntax of a void pointer:
//Syntax of void pointer in C void * Pointer_Name;
Let’s see an example code to understand the working of the void pointer. I have already written some blog post on the void pointer, you can check,
#include <stdio.h> int main() { //pvData is void pointer void *pvData; int iData = 6; pvData = &iData; printf("pvData = %d",*(int*)pvData); return 0; }
Output: 6
Recommended Articles for you:
- A brief description of the pointer in C.
- Application of void pointer in C
- Function pointer in c, a detailed guide
- How to use the structure of function pointer in c language?
- Online programming tools.
- Function pointer in structure.
- Pointer Arithmetic in C.
- 10 questions about dynamic memory allocation.
- Memory Layout in C.
- 100 C interview Questions
- File handling in C.
- C format specifiers.