Pointer to Pointer:
A pointer to pointer (declared using **) stores the address of another pointer. It is used in more complex programming situations such as dynamic 2D arrays, function arguments that modify pointer values, or linked data structures like trees and graphs.
Example:
int a = 10;
int *p = &a;
int **pp = &p;
Here, pp stores the address of p, which in turn stores the address of a. Dereferencing twice (**pp) gives the value of a.
Void Pointers:
A void pointer (declared as void*) is a generic pointer that can point to data of any type (int, float, char, etc.). This is useful when writing functions that handle different data types or when building libraries.
However, since a void pointer doesn’t know the type of data it points to, it cannot be directly dereferenced. You must explicitly cast it to the correct type before using it.
Example:
void *ptr;
int x = 5;
ptr = &x; // Valid
*(int*)ptr; // Valid after casting