top

Search

C Tutorial

.

UpGrad

C Tutorial

Pointer to Pointer in C

Overview

Pointer to pointer or double pointer in C is a crucial concept that enables working with pointers indirectly and dynamically allocating memories. It is useful in various scenarios involving pointers, including function parameter passing. On that note, let's take a closer look at the various nuances of a double pointer in C, its advantages as well as its functionalities. 

Advantages of Pointer to Pointer

Pointer to pointer in C, also sometimes referred to as double pointers, provides several advantages. Such include,

  • Dynamic Memory Allocation

By using a double pointer in C, you can quite easily allocate memory for a two-dimensional array or a dynamically growing structure like a linked list or a tree. 

  • Function Arguments And Return Value

Pointer to pointer is also useful when you wish to modify a pointer value passed as an argument to a function. By passing a pointer to pointer, the function can modify the original pointer and have the changes reflected outside the function's scope.

  • Dynamic Memory Deallocation

Similar to dynamic memory allocation, pointer to pointer is often used in dynamic memory deallocation. They allow traversing and deallocating memory in data structures, including linked lists and trees, thus ensuring proper deallocation of all nodes.

  • Efficient Array Modification

Last but not least, the pointer-to-pointer can be used to manipulate arrays of pointers in an efficient manner. This is especially beneficial when you are dealing with arrays of structures wherein each element has to be modified on an individual level. 

Apart from these, double pointers in C also facilitate the performance of other crucial tasks, including the implementation of data structures and enabling dynamic dispatch or polymorphism. Overall, it helps to enhance both flexibility and efficiency in C programming.

Syntax of Pointer to Pointer

The syntax of pointer to pointer in C is,

<type>** <pointer_name>;

As quite visible, it consists of three main components. They are,

'<type. - It denotes the particular data type of the variable that the pointer to pointer will be pointing to. It can be any data type in C, such as int, struct, and char, among others. 

'**'- It means that the variable will store the address of a pointer variable.

'<pointer_name>' - It contains the name that you assign to the pointer to pointer variable. 

Declaring pointer to pointer in C

Declaring pointer to pointer in C simply means defining the variable that can hold the address of a pointer. To achieve the same, you must be able to assign the appropriate pointer variables to the pointer-to-pointer variable. The syntax for the same goes as follows, 

<type>** <pointer_name>;

Let's explore a small pointer to pointer example of how you can declare it in C programming language.

int main() {
    int value = 42;
    int* pointer1 = &value; // Pointer to int
    int** pointer2 = &pointer1; // Pointer to pointer to int
    return 0;
}

As quite visible, here we have declared 'pointer2' as a pointer to pointer. It stores the address of the pointer variable, 'pointer1', which in turn points to an integer variable.

Size of pointer to pointer in C

In the C programming language, there is not much difference between a double pointer to a normal pointer. It all boils down to the underlying architecture of the CPU and the specific data type that it points to. For example, on a 32-bit system, a pointer is typically 4 bytes (32 bits). Similarly, on a 64-bit system, the size of a pointer will be 8 bytes (64 bits). 

To accurately determine the size of pointer to pointer in C, we use the 'sizeof' operator.

#include <stdio.h>
int main() {
    int** ptrptr;
    printf("Size of pointer to pointer: %zu bytes\n", sizeof(ptrptr));
    return 0;
}

Here, the 'sizeof(ptrptr) returns the size in bytes of the pointer to pointer variable, 'ptrptr'. 

Pointer to Pointer and Arrays

Pointer to pointer can be used alongside arrays in C to achieve various functionalities. Such include,

  • Creating Two-Dimensional Arrays - By allocating memory dynamically, you can create a pointer to pointer array wherein each pointer will point towards another dynamically allocated array. This enables the creation of flexible and reusable two-dimensional arrays.

  • Dynamic Array of Strings - With the help of double pointers in C, you can also create and manipulate a dynamic array of strings. Each element of the array is a pointer to a dynamically allocated string. 

  • Creating Pointer to Array of Pointers - Lastly, double pointers in C also enable the creation and manipulation of an array of pointers dynamically. 

Examples of double pointers

Here is one small example of how you can use a double pointer in C to swap the values of two variables.

#include <stdio.h>
void swap(int** a, int** b) {
    int* temp = *a;
    *a = *b;
    *b = temp;
}
int main() {
    int x = 5;
    int y = 10;
    int* ptr1 = &x;
    int* ptr2 = &y;
    printf("Before swap: x = %d, y = %d\n", *ptr1, *ptr2);
    swap(&ptr1, &ptr2);
    printf("After swap: x = %d, y = %d\n", *ptr1, *ptr2);
    return 0;
}

Dynamic Memory Allocation using Pointer to Pointer

Pointer to Pointer in C can be used to allocate memory dynamically and create flexible data structures. It also enables access to the elements of the allocated memory and helps to manage memory, especially at runtime, in an efficient manner. 

Heap Memory Allocation using Pointer to Pointer

Heap memory allocation using pointer to pointer is useful, especially when you have to create resizable data structures. By using a double pointer, you can quite easily modify the pointer itself, thus allowing you to allocate more memory on the heap and use the same for various purposes. Example,

#include <stdio.h>
#include <stdlib.h>
void allocateArray(int** arr, int size) {
    *arr = (int*)malloc(size * sizeof(int));
    if (*arr == NULL) {
        printf("Memory allocation failed\n");
        exit(1); // Exit the program if memory allocation fails
    }
}
void freeArray(int** arr) {
    free(*arr);
    *arr = NULL; // Set the pointer to NULL after freeing the memory
}
int main() {
    int* array = NULL;
    int size = 5;
    allocateArray(&array, size);
    // Access and modify the array
    for (int i = 0; i < size; i++) {
        array[i] = i + 1;
    }
    // Print the array
    for (int i = 0; i < size; i++) {
        printf("%d ", array[i]);
    }
    printf("\n");
    freeArray(&array);
    return 0;
}

Memory Leak using Pointer to Pointer

The occurrence of memory leaks, especially when the memory is allocated dynamically but not properly freed, is very common. Although pointer to pointer does not directly cause memory leaks, if handled incorrectly, it can lead to such scenarios. Therefore to prevent the same, you must make use of the 'free' function to ensure that every dynamically allocated memory is freed properly. Here's how you can achieve this.

#include <stdio.h>
#include <stdlib.h>
void allocateArray(int** arr, int size) {
    *arr = (int*)malloc(size * sizeof(int));
    if (*arr == NULL) {
        printf("Memory allocation failed\n");
        exit(1); // Exit the program if memory allocation fails
    }
}
void freeArray(int** arr) {
    free(*arr);
    *arr = NULL; // Set the pointer to NULL after freeing the memory
}
int main() {
    int* array = NULL;
    int size = 5;
    allocateArray(&array, size);
    // Access and use the array
    // Free the dynamically allocated memory
    freeArray(&array);
    return 0;
}

calloc() vs malloc() using Pointer to Pointer

The calloc() and malloc() are two functions used in the C programming language, alongside pointer to pointer, to dynamically allocate memory. Each of these functions has its own unique way by which they operate. For example, while calloc() is used to allocate a block of memory for a specified number of elements, the malloc() function is used to allocate a specified size block of memory in bytes. 

Secondly, the memory returned by the former function is initialised with zeros, whereas the memory returned by the latter is uninitialised. On that note, here is a small example highlighting how to use the calloc() and malloc() functions with a double pointer. 

#include <stdio.h>
#include <stdlib.h>
void allocateMemoryMalloc(int** ptr, int size) {
    *ptr = (int*)malloc(size * sizeof(int));
    if (*ptr == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }
}
void allocateMemoryCalloc(int** ptr, int size) {
    *ptr = (int*)calloc(size, sizeof(int));
    if (*ptr == NULL) {
        printf("Memory allocation failed\n");
        exit(1);
    }
}
int main() {
    int* arrayMalloc = NULL;
    int* arrayCalloc = NULL;
    int size = 5;
    allocateMemoryMalloc(&arrayMalloc, size);
    allocateMemoryCalloc(&arrayCalloc, size);
    // Access and use the allocated memory
    // Free the allocated memory
    free(arrayMalloc);
    free(arrayCalloc);
    return 0;
}

Common Mistakes and Pitfalls

While working with pointer to pointer in C, it is very common to encounter a few minute but critical mistakes. Wondering what those are? Let's find out. 

  • Null Pointer to Pointer

Null pointer to pointer typically occurs when a pointer variable stores the null value, indicating that it does not point to any valid memory location. One of the main drawbacks of this is the risk of encountering segmentation faults or undefined behaviour when you dereference a null pointer without first checking its nullness. It can lead to potential issues such as runtime errors, memory leaks, and debugging challenges. 

  • Dangling Pointer to Pointer

Dangling pointer mainly occurs when you assign a double pointer to a dynamically allocated memory block, followed by assigning a new address to the same double pointer without freeing the previous memory block. This can result in either a memory leak or accessing invalid memory. 

  • Uninitialized Pointer to Pointer

Lastly, forgetting to initialise a double pointer before actually using it can lead to undefined behaviour. To prevent the same, you must always initialise a double pointer to NULL in case you do not have a valid memory address to assign initially. 

Conclusion 

To sum up, pointer to pointer does indeed have a lot of applications and advantages in the C programming language. From dynamic memory allocation to efficient string manipulation, they provide optimum flexibility and are a crucial part of C. 

If you wish to learn more about the same, then do not forget to check out upGrad’s MS in Computer Science course offered under Liverpool John Moores University. It offers various advantages to all its students, including just-in-time interviews and high-performance coaching sessions, among others. 

FAQs

1. Can you state the various types of pointers used in C?

In the C programming language, there are mainly four different types of pointers used. They are, namely, null pointer, void pointer, dangling pointer, and wild pointer. 

2. What do we mean by pointer to pointer in C?

A pointer is typically used to store the variable's address in C. Pointer to pointer refers to a chain of pointers wherein the first pointer stores the variable's address, and the second pointer pinpoints the location that stores the actual value. 

3. What do we mean by a null pointer in C?

A null pointer in C is primarily used to indicate the absence of a valid memory address or to initiate a pointer variable before actually assigning it to a valid memory address. 

Leave a Reply

Your email address will not be published. Required fields are marked *