int r = 50;
int *p;
int **k;
int ***m;
printf( "r: %d ", r );
p = &r;
k = &p;
m = &k;
***m = 100; //line 9
printf( "r: %d\n", r );
When there is only one pointer, I can understand that we take 100 and we assign it to the variable at the address which is being held by the pointer. But what exactly is happening step by step when we do this with more than one pointer level? (line 9)
int *p=&r: p is a pointer-to-int, and it takes the address of r.
int **k=&p: k is a pointer-to-( pointer-to-int ), and it takes the address of p.
int ***m=&k: m is a pointer-to-( pointer-to-( pointer-to-int ) ), and it takes the address of k.
When you do ***m = 100, you are "unwrapping" the pointers, and finally you end up with just int.
The reason pointer-to-pointer works, is that a pointer is a variable, too. It just stores addresses. So a pointer-to-pointer is the address of a variable that contains an address.
In this diagram v is the variable, containing 100. Its address is 1000. ptr contains the address of v, which is 1000. pptr contains the addres of ptr, which is 720.
Pointer to Pointer or Multiline pointer
When address of r is passed to pointer p!
Then if you passing the address of p to another pointer k then for the dereferencing the actual value you want to dereference it two times to get actual value of r and so on.
Take a look at the image
Related
This question already has answers here:
Pointer to pointer clarification
(16 answers)
Closed 1 year ago.
#include <stdio.h>
int main(){
int integer = 300;
int* p = &integer;
int** pp = &p;
printf("*pp = %i", *pp);
}
My question is what is actually *pp? What does it mean to print the value in the address of *p ?
It is a reference to the integer converted to an integer value.
To print the reference you should use %p format specifier instead of the %i format specifier.
[pp] -> [p] -> [integer]
If you modify the program you can see the references and how they are chained:
int main()
{
int integer = 300;
int* p = &integer;
int** pp = &p;
printf("pp = %p *pp = %p\n",(void *)pp, (void *)*pp);
printf("&integer = %p &p = %p\n", (void *)&integer, (void *)&p);
}
pp = 0x7fffb6adc7d8 *pp = 0x7fffb6adc7e4
&integer = 0x7fffb6adc7e4 &p = 0x7fffb6adc7d8
#include <stdio.h>
int main(){
int integer = 300;
int* p = &integer;
int** pp = &p;
printf("**pp=%d\n", **pp);
printf("*p=%d\n", *p);
printf("*pp = %p\n", *pp);
printf("p=%p\n", p);
printf("&integer=%p\n", &integer);
printf("&(*p)=%p\n", &(*p));
printf("pp=%p\n", pp);
printf("&p=%p\n", &p);
}
Since &(*p) is simply p, yes *pp is the address of *p.
Since %i is integer but what you want to print is pointer. So I changed it to %p.
I'm not a pro in C programming, but I believe I have a decent knowledge of pointers.
So, to understand what is *pp, you need to understand what is * operator used for?
It is no doubt used for multiplication, but it is also used for pointer de-referencing.
So when I say *pp, it means the value of pp i.e. what is stored in pp. Each defined variable in C will have a memory space of its own. So *pp means what is stored in the memory space that was given to the variable pp.
In your case,
int integer = 300;
A variable of type integer named integer is declared and given the value 300
int* p = &integer;
A pointer that needs to point to an integer variable is declared and given the address of integer.
int** pp = &p;
A pointer that needs to point to an integer variable is declared and given the address of p
printf("*pp = %i", *pp);
*pp means printing the value which is stored in pp i.e. address of p
**pp means printing the value which is stored in the value which is stored in p i.e. 300
As I explained earlier, each variable has a memory space of its own, and each memory space will have an address assigned to it, so that it can be identified (the way we have an email address which is used to contact us via email or a postal address which is used to contact us via post).
Hope this answers your question. Do ask follow-up questions if any.
Cheers..!!
I don't understand why when dereferencing a pointer to an array, the result is the address of the first value of the array
int array[2][2] = {{0,1},{0,1}};
int (*p)[2];
p = array;
p = address of a[0][0], p+1 = address of a[1][0],
*p = address of a[0][0], (*p)+1 = the address of a[0][1];
I understand that p is a pointer to an array of 2 integers, not a pointer to an integer. But if we print out the value of p, it's still the address of an integer. I want to know what's going on under the hood? Is p a pointer to an array of pointers? So we have to dereference it twice to get the value of the integer its pointing?
A pointer to an int,
int* p;
is a variable, stored in a location, that contains the address of another variable (int).
When we dereference it, we get the value of that variable. How does this process work exactly with a pointer to an array?
The address of an array is the same as the address of its first element.
Given the definition int array[2][2] = {{0,1},{0,1}};, the compiler arranges some location in memory to contain the int values 0, 1, 0, and 1. Let’s say that location has address 1000, and the int value 0 is stored in bytes 1000-1003, 1 is stored in 1004 to 1007, 0 is stored in 1008 to 1011, and 1 is stored in 1012 to 1015.
Where does the element array[0][0] start in memory? At location 1000.
Where does the array array start in memory? At location 1000.
Where does the array array[0] start in memory? At location 1000.
The array starts in memory at the same location its first element starts in memory. Also, array[0], which is itself an array, starts at the location 1000.
So, after p = array;, p points the location 1000. And the element array[0][0] also starts at location 1000. So, when you print p, as with printf("%p\n", (void *) p);, it is unsurprising you get the same result as when you print the address of array[0][0], as with printf("%p\n", (void *) &array[0][0]);.
An array is automatically converted to the address of its first element.
Next, let’s consider *p. The type of p is int (*)[2], a pointer to an array of 2 int. Therefore, *p is an array of 2 int.
In particular, *p is an array. Suppose we attempt to print it by passing it as an argument to printf. What happens?
In C, when an array is used in an expression, it is automatically converted to the address of its first element (except when the array is the operand of sizeof or unary & or is a string literal used to initialize an array). So, if you use *p as an argument to printf, it initially means array[0], but that array is converted to the address of its first argument. So passing *p as an argument actually passes &array[0][0] (or, equivalently &(*p)[0]).
Thus, printf("%p\n", (void *) *p); will print the same address as printf("%p\n", (void *) &a[0][0]);.
Value at an array can be accessed using
array[i] = *(array+i) (expansion of [i]).
Similarily, (*p)[i] = *(*(p+i)). So, we need to dereference twice to access the value.
If you want to access, array[0][0], you have to use *(*(p+0)+0) = **p;,
Similarily, array[0][1] can be accessed using *(*(p+0)+1) = *((*p)+1);
Note, *p points to first row (stores address of array[0][0]), and *(p+1) points to second row (stores address of array[1][0]).
Please check the below code :
#include <stdio.h>
int main()
{
int array[2][2] = {{1, 2}, {3, 4}};
int(*p)[2];
p = array;
printf("The address of array[0][0] is %p \n",&array[0][0]);
printf("The address of *p is %p \n",*p);
printf("The address of array[1][0] is %p \n",&array[1][0]);
printf("The address of *(p+1) is %p \n",*(p+1));
printf("The value of array[0][0] is %d \n",array[0][0]);
printf("The value of **p is %d \n",**p);
printf("The value of array[0][1] is %d \n",array[0][1]);
printf("The value of *((*p)+1) is %d \n",*((*p)+1));
return 0;
}
The output is:
The address of array[0][0] is 0x7fff6e8781a0
The address of *p is 0x7fff6e8781a0
The address of array[1][0] is 0x7fff6e8781a8
The address of *(p+1) is 0x7fff6e8781a8
The value of array[0][0] is 1
The value of **p is 1
The value of array[0][1] is 2
The value of *((*p)+1) is 2
Refer the following C program and while incrementing the pointer (i.e. p), it is correctly incrementing by 4 bytes. While if I try to increment the pointer to pointer (i.e. pp), then same is incrementing by 8 bytes. And I am not understanding why is it happening in this way and may be i have misunderstanding in the concept.
#include <stdio.h>
int main()
{
float a = 5, *p, **pp;
p = &a;
pp = &p;
printf("a=%f, p=%p, pp=%p\n", a, p, pp);
a = a + 1;
p = p + 1;
pp = pp + 1;
printf("a=%f, p=%p, pp=%p\n", a, p, pp);
return 0;
}
output:
a=5.000000, p=0x7ffc93c93374, pp=0x7ffc93c93368
a=6.000000, p=0x7ffc93c93378, pp=0x7ffc93c93370
Pointer arithmetic is done in units of the size of the type that the pointer points to. On your system, sizeof(float) is 4, so incrementing p adds 4 bytes to it. But sizeof(float*) is 8 because it's a 64-bit system, so incrementing pp adds 8 bytes to it.
To append the answer of #Barmar I would like to point out that if you have an array
T a[N];
where T is some type and N is some value then after such a declaration of a pointer like
T *p = a;
The pointer p will point to the first element of the array a. This declaration is equivalent to
T *p = &a[0];
If to increment the pointer p it is naturally to assume that it will point to the second element of the array a that is its value will be the value of the expression &a[1]. S0 you need to add to the original value of the pointer p the value that is equal to the value of the size of an element of the array a that is the value equal to sizeof( T ).
Such a calculation is named the pointer arithmetic.
Thus the expression
p + 1
or
++p
means to add the value sizeof( T ) to the value stored in the pointer p. As a result the pointer expression will point to the next element of the array.
As per multiple sources, a pointer p points to a value when it is dereferenced. Thus, we may say that a pointer contains an address as it's value, and when the dereference operator (*) is used, the value at the address is returned.
A pointer may be assigned a value as follows:
int a = 90;
int *p = &a;
if we assign a pointer it's value as follows:
int *p;
*p = 60;
60 is alloted to p and causes undefined behavior upon dereferencing since 60 is not a valid address. (As per the answer to this question).
However, for the following code:
int a = 90;
int *p = &a;
printf ("p is %d \n",*p);
printf ("a is %d \n", a);
printf ("address is %p \n",p);
*p = 100;
printf ("p is %d \n",*p);
printf ("a is %d \n", a);
printf ("address is %p \n",p);
The following output is recieved :
p is 90
a is 90
address is 0028FED8
p is 100
a is 100
address is 0028FED8
ie, the expression *p = 100 changes the value at a, and not the value contained by p.
HOW ??????
*p = &a doesn't even compile. p is a pointer to int. It currently has an undefined value, therefore assigning anything to *p is undefined behaviour and would most likely crash. However, even if p did point to an int, you could only assign an int to *p, &a is a pointer to int, not an int, so this doesn't compile.
In your second example, *p = 60, the value of p is undefined, so you are trying to store 60 to an undefined location in memory. Instant crash. p isn't modified by this, so your explanation is wrong. p is not set to 60. You can't set p to an int. You can only set it to a pointer to int.
Correct:
p = &a;
*p = 60;
the code you wrote at the begining:
int *p;
int a = 90;
*p = &a;
is not valid, The asterisk (*) in line 1 indicate that it is a pointer, it is not the dereference operator as in line 3.
the following code:
int a = 90;
int *p = &a;
is equivalent to:
int a = 90;
int *p;
p = &a;
(p) is a pointer , and now is pointing at address of (a)
*p = 100;
so, you just assign a value to a, a = 100 .
and you are printing the same value from the same address.
You had asked:
ie, the expression *p = 100 changes the value at a, and not the value contained by p.
You can read the comment section for explanation of each line of C code and I'm not using exact address locations but using arbitrary ones for demonstration purposes:
int *p; // Stack variable pointer to integer type w/ p's address being 4 bytes # 0x00000000
int a = 90; // Stack integer variable `a` and initializing it to the value of 90 located # 0x00000040
*p = &a; // Dereferencing the pointer `p` to be equal to the address of `a` ... One would think
// that the address value of `a` 0x00000040 in hex would be stored into `a` which
// has the value of 64 in decimal, however this is not always the case and this should be
// undefined behavior, but can still compile and run depending on the compiler and architecture.
// It may run or crash or not even compile or build at all. Most compilers should throw an error.
*p = 100; // 'p' is located at 0x00000000 and contains the value 0x00000040 and by dereferencing it
// it will assign the value of 100 to the stack address location of 0x00000040. Thus this
// changes the value of `a` to 100
// These two statements are in a sense equivalent
*p = 100; a = 100;
// If one was to assign the address of `a` to `p` as such:
p = &a;
EDIT
// Therefor the statement `*p=100` will only work if the statement
// `p=&a` is defined and evaluated beforehand.
EDIT
Now as for the question based on the Title: "what does *p contain?" with the op's original code provided *p actually contains garbage or what ever was assigned to it upon declaration.
As per multiple sources, a pointer p points to a value when it is dereferenced.
Not quite. A pointer points to an object. Dereferecing a pointer produces that object. Using an object in a context where a value is needed produces the stored value.
int *p = &a;
The object that p now points to is a.
*p = 100;
Dereferencing p produces the pointed-to object, namely a. Since this is not a context where the stored value is needed, a's value isn't read, it remains the object a which is assigned the value 100.
Or, simply put, *p means a, therefore *p = 100 means a = 100.
If I run the following on OS X:
int main (void)
{
int* n; // initialise(declare) pointer
*n = 20; // the value in address pointed to by n is 20
printf("n: %i, n&: %i\n", n, &n);
return 0;
}
I get:
n: 1592302512, n&: 1592302480
Why the differing values?
Why do pointer and &pointer have different values?
The expression &n yields the address of n itself, while n evaluates to the value of the pointer, i.e. the address of the thing it points to.
But note that you have undefined behaviour First of all, because you are de-referencing an uninitialized pointer. You need to make n point somewhere you can write to.
For example,
int* n;
int i = 42;
n = &i;
// now you can de-reference n
*n = 20;
Second, you have the wrong printf specifier for &n. You need %p:
printf("n: %i, &n: %p\n", n, &n);
int* n declares a variable called n which is a pointer to an integer.
&n returns the address of the variable n, which would be a pointer to a pointer-to-integer.
Let's say we have the following code:
int a = 20; // declare an integer a whose value 20
int* n = &a; // declare a pointer n whose value is the address of a
int** p = &n; // declare a pointer p whose value is the address of n
In this case we would have the following:
variable name | value | address in memory
a | 20 | 1592302512
n | 1592302512 | 1592302480
p | 1592302480 | who knows?
In your code
int* n; //initialization is not done
*n = 20;
invokes undefined behavior. You're trying to de-reference (write into) uninitialized memory. You have to allocate memory to n before de-referencing.
Apart form that part,
n is of type int *
&n will be of type int **
So, they are different and supposed to have different values.
That said, you should use %p format specifier with printf() to print the pointers.
Just as an alternative, let me spell this out a different way.
char *ptr;
char c='A';
ptr = &c;
In this code, here's what's happening and what values are found when we qualify ptr in different ways.
ptr itself contains the address in memory where the char c variable is located.
*ptr dereferences the pointer, returning the actual value of the variable c. In this case, a capital A.
&ptr will give you the address of the memory location that ptr represents. In other words, if you needed to know where the pointer itself was located rather than what the address is of the thing that it points to, this is how you get it.