can someone explain to me how double pointers work? On this code for example, why it prints the values that it prints in the end?
int main(void) {
int anArray[] = {5,16,33,99};
int * p = anArray;
printf("*p = %d\n", *p);
p ;
printf("Now *p = %d\n", *p);
int * q = &anArray[3];
int ** x = &q;
**x = 12;
*x = p;
**x = 42;
q[1] = 9;
for (int i =0; i < 4; i ){
printf("anArray[%d] = %d\n",i, anArray[i]);
}
return EXIT_SUCCESS;
}
CodePudding user response:
Let's draw out:
int q = 15;
int * p = &q;
int * * z = &p;
q
----
p --> | 15 |
^ ----
|
z
In the above drawing, q is an integer variable with the value 15.
The pointer p points to the variable q.
The pointer z points to the pointer p.
The expression *z refers to the value in the pointer p.
The expression **z or rewritten as *(*z) refers to the variable q (following the links).
We know that (*z) is the pointer p, so let's replace:
*(*z) == *(p);
We can replace *(p) with q, from the above definitions: *(*z) == *(p) == q;.
CodePudding user response:
Let's fully draw it out:
int anArray[] = {5,16,33,99}; // 4 values in consecutive addresses
// ----
// anArray -> 5
// ----
// 16
// ----
// 33
// ----
// 99
// ----
int * p = anArray; // A new variable, whose contents points to the address of anArray
// ---------
// anArray -> 5 <-
// --------- |
// 16 |
// --------- |
// 33 |
// --------- |
// 99 |
// --------- |
// p -> anArray -
// ---------
printf("*p = %d\n", *p); // prints 5
p ; // increment pointer p to the next element.
// -----------
// anArray -> 5
// -----------
// 16 <-
// ----------- |
// 33 |
// ----------- |
// 99 |
// ----------- |
// p -> anArray 1 -
// ---------
printf("Now *p = %d\n", *p); // prints 16
int * q = &anArray[3]; // new pointer variable, points to 4th element of anArray (0-based)
// -----------
// anArray -> 5
// -----------
// 16 <-
// ----------- |
// 33 |
// ----------- |
// 99 | <-
// ----------- | |
// p -> anArray 1 - |
// ----------- |
// q -> anArray 3 -----
// -----------
int ** x = &q; // new pointer variable, points to address of q pointer variable
// -----------
// anArray -> 5
// -----------
// 16 <-
// ----------- |
// 33 |
// ----------- |
// 99 | <-
// ----------- | |
// p -> anArray 1 - |
// ----------- |
// q -> anArray 3 ----- <-
// ----------- |
// x -> q ---------
// -----------
**x = 12; // get address in x (q), then address in q (anArray 3) and write 12 to it
// -----------
// anArray -> 5
// -----------
// 16 <-
// ----------- |
// 33 |
// ----------- |
// 12 | <-
// ----------- | |
// p -> anArray 1 - |
// ----------- |
// q -> anArray 3 ----- <-
// ----------- |
// x -> q ---------
// -----------
*x = p; // get address in x (q) and write p value to it (anArray 1)
// -----------
// anArray -> 5
// -----------
// 16 <- <-
// ----------- | |
// 33 | |
// ----------- | |
// 12 | |
// ----------- | |
// p -> anArray 1 - |
// ----------- |
// q -> anArray 1 ----- <-
// ----------- |
// x -> q ---------
// -----------
**x = 42; // get address in x (q), then address in q (anArray 1) and write a 42 to it
// -----------
// anArray -> 5
// -----------
// 42 <- <-
// ----------- | |
// 33 | |
// ----------- | |
// 12 | |
// ----------- | |
// p -> anArray 1 - |
// ----------- |
// q -> anArray 1 ----- <-
// ----------- |
// x -> q ---------
// -----------
q[1] = 9; // get address in q (anArray 1) add one element (anArray 2), and assign 9
// -----------
// anArray -> 5
// -----------
// 42 <- <- (q[0])
// ----------- | |
// 9 | | (q[1])
// ----------- | |
// 12 | |
// ----------- | |
// p -> anArray 1 - |
// ----------- |
// q -> anArray 1 ----- <-
// ----------- |
// x -> q ---------
// -----------
CodePudding user response:
First of all, I will use a simple example to demonstrate double pointers:
int x = 5; // Simply 5
int* y = &x; // y holds the address of x
int** z = &y; // z holds the address of y
When y holds the address of x it means that no matter what is the value of x, y still points to it (points means 'holding the address of').
So, changing x also changes *y which is the syntax for accessing the value that y points to.
The same is applied to z, but here we need to use * operator twice in order to access x value, because z points to y which points to x (meaning **z == *y == x).
To understand your question we also need to understand what arrays are in C.
Array is a sequence of elements (e.g. integers, chars and etc...) in a contiguous memory location.
An array is actually a pointer meaning if we have int anArray[] = {5,16,33,99}; accessing anArray using anArray[0] is the same as *anArray, or anArray[1] is the same as *(anArray sizeof(int)) and etc...
CodePudding user response:
A pointer is a variable holding a memory address which contains the value you want. For example:
int value = 42;
int* value_ptr = &value;
int access_via_ptr = *value_ptr;
A double pointer, or a pointer to pointer, is a variable holding an address of another pointer, which holds an address to the value you want. For example:
int value = 42;
int* value_ptr = &value;
int** value_ptr = &value_ptr;
int access_via_ptr_ptr = **value_ptr;
Why would you want to use **? One really useful way is in functions. You want to pass a pointer to a pointer, so that the function can setup the pointer address for you. For example:
#include <iostream>
void GetPtr(int** val_ptr_ptr, int init_contents)
{
// val_ptr_ptr should point to a pointer
// lets allocate it
*val_ptr_ptr = new int;
// de-reference ptr->ptr->val to initialize
// the contents
**val_ptr_ptr = init_contents;
}
int main(void)
{
int* val_ptr = NULL;
GetPtr(&val_ptr, 42);
std::cout << *val_ptr;
delete val_ptr;
return 0;
}
In this example we want a function to allocate memory. We want that memory to be stored in a pointer outside the function, so we can access it. We pass in an address of outside pointer, or a pointer to a pointer. We then assign the address inside the function.
