What does int** mean in C in this context?
Categories:
Understanding int**
in C: Pointers to Pointers Explained

Demystify the concept of int**
in C programming, exploring its meaning, common use cases, and how to correctly declare, initialize, and manipulate double pointers.
In C and C++, the declaration int**
can often be a source of confusion for developers, especially those new to pointers. This construct represents a 'pointer to a pointer to an integer.' While it might seem intimidating at first, understanding int**
is crucial for advanced memory management, dynamic array allocation, and working with functions that modify pointer arguments. This article will break down what int**
means, illustrate its common applications, and provide clear examples to help you master this powerful C concept.
The Basics: Pointers and int*
Before diving into int**
, let's quickly recap what a single pointer (int*
) is. A pointer is a variable that stores the memory address of another variable. When you declare int* ptr;
, ptr
is a variable designed to hold the address of an int
. The *
operator has two main uses: declaration (e.g., int* ptr;
) and dereferencing (e.g., *ptr = 10;
to access the value at the address ptr
holds).
int main() {
int value = 10;
int* ptr = &value; // ptr stores the address of 'value'
printf("Value: %d\n", value); // Output: 10
printf("Address of value: %p\n", &value); // Output: (some memory address)
printf("Value of ptr (address of value): %p\n", ptr); // Output: (same memory address)
printf("Value pointed to by ptr: %d\n", *ptr); // Output: 10
*ptr = 20; // Change the value through the pointer
printf("New value: %d\n", value); // Output: 20
return 0;
}
Basic usage of a single pointer (int*
)
Understanding int**
: Pointer to a Pointer
Now, let's introduce int**
. Just as int*
is a pointer to an int
, int**
is a pointer to an int*
. This means a variable declared as int**
will store the memory address of another variable that is itself an int*
. In essence, it's a level of indirection: int**
points to int*
, which in turn points to an int
.
graph TD A[int** pptr] --> B[Memory Address of ptr]; B --> C[int* ptr]; C --> D[Memory Address of value]; D --> E[int value];
Conceptual diagram of int**
pointing to int*
which points to int
To access the int
value using int**
, you need to dereference twice:
*pptr
: This dereferencespptr
once, giving you theint*
(the value ofptr
).**pptr
: This dereferencespptr
twice, giving you theint
(the value ofvalue
).
int main() {
int value = 100;
int* ptr = &value; // ptr holds the address of 'value'
int** pptr = &ptr; // pptr holds the address of 'ptr'
printf("Value: %d\n", value); // Output: 100
printf("Address of value: %p\n", &value); // Output: (address of value)
printf("Value of ptr (address of value): %p\n", ptr); // Output: (address of value)
printf("Address of ptr: %p\n", &ptr); // Output: (address of ptr)
printf("Value of pptr (address of ptr): %p\n", pptr); // Output: (address of ptr)
printf("Value pointed to by ptr: %d\n", *ptr); // Output: 100
printf("Value pointed to by pptr (first dereference): %p\n", *pptr); // Output: (address of value)
printf("Value pointed to by pptr (second dereference): %d\n", **pptr); // Output: 100
**pptr = 200; // Change the value through the double pointer
printf("New value: %d\n", value); // Output: 200
return 0;
}
Demonstration of int**
declaration and dereferencing
Common Use Cases for int**
int**
is not just an academic exercise; it has several practical applications in C programming.
1. Modifying a Pointer in a Function
One of the most common uses for int**
is when you need a function to modify a pointer that was passed to it. If you pass an int*
by value to a function, the function receives a copy of the pointer. Any changes to that copy will not affect the original pointer in the calling function. To modify the original pointer, you must pass its address, which means passing an int**
.
void allocate_int(int** ptr_ref) {
// Allocate memory for an int and make *ptr_ref point to it
*ptr_ref = (int*)malloc(sizeof(int));
if (*ptr_ref == NULL) {
// Handle allocation error
return;
}
**ptr_ref = 500; // Initialize the allocated int
}
int main() {
int* my_ptr = NULL;
printf("Before allocation, my_ptr: %p\n", (void*)my_ptr); // Output: (nil) or 0x0
allocate_int(&my_ptr); // Pass the address of my_ptr
if (my_ptr != NULL) {
printf("After allocation, my_ptr: %p\n", (void*)my_ptr); // Output: (some memory address)
printf("Value pointed to by my_ptr: %d\n", *my_ptr); // Output: 500
free(my_ptr); // Don't forget to free allocated memory
}
return 0;
}
Using int**
to modify a pointer within a function
2. Dynamic 2D Arrays (Arrays of Pointers)
When you need a 2D array whose dimensions are not known at compile time, or if you want rows of varying lengths, int**
is the typical solution. Here, int**
represents a pointer to an array of int*
pointers. Each int*
then points to the beginning of a row of integers.
#include <stdio.h>
#include <stdlib.h>
int main() {
int rows = 3;
int cols = 4;
// 1. Allocate memory for 'rows' number of int* pointers
int** dynamic_2d_array = (int**)malloc(rows * sizeof(int*));
if (dynamic_2d_array == NULL) { /* Handle error */ return 1; }
// 2. For each int*, allocate memory for 'cols' number of ints
for (int i = 0; i < rows; i++) {
dynamic_2d_array[i] = (int*)malloc(cols * sizeof(int));
if (dynamic_2d_array[i] == NULL) { /* Handle error, free previously allocated rows */ return 1; }
for (int j = 0; j < cols; j++) {
dynamic_2d_array[i][j] = i * cols + j + 1; // Initialize with some values
}
}
// Print the 2D array
printf("Dynamic 2D Array:\n");
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
printf("%2d ", dynamic_2d_array[i][j]);
}
printf("\n");
}
// 3. Free the allocated memory (in reverse order of allocation)
for (int i = 0; i < rows; i++) {
free(dynamic_2d_array[i]);
}
free(dynamic_2d_array);
return 0;
}
Creating a dynamic 2D array using int**
3. Command-Line Arguments (char** argv
)
A very common appearance of char**
(which is analogous to int**
but for characters) is in the main
function signature: int main(int argc, char** argv)
. Here, argv
is an array of character pointers, where each char*
points to a null-terminated string (a command-line argument). So, argv
is a pointer to the first char*
in that array.
int**
is powerful, it also increases the complexity of memory management. Always ensure you free
memory allocated with malloc
to prevent memory leaks, especially when dealing with multiple levels of pointers.