Related
Recently I have come across this problem which I am unable to understand by myself.
What do these three Expressions REALLY mean?
*ptr++
*++ptr
++*ptr
I have tried Ritchie. But unfortunately was unable to follow what he told about these 3 operations.
I know they are all performed to increment the pointer/the value pointed to. I can also guess there may be a lot of things about precedence and order of evaluation. Like one increments the pointer first then fetches the content of that pointer, one simply fetches the content and then increments the pointer etc etc. As you can see, I don't have a clear understanding about their actual operations, which i would like to clear as soon as possible. But I am truly lost when I get a chance to apply them in programs. For example:
int main()
{
char *p = "Hello";
while(*p++)
printf("%c",*p);
return 0;
}
gives me this output:
ello
But my expectation was that it would print Hello .
One final request -- Please give me examples for how each expression works in a given code snippet. As most of the time only a mere paragraph of theory gets flown over my head.
Here's a detailed explanation which I hope will be helpful. Let's begin with your program, as it's the simplest to explain.
int main()
{
char *p = "Hello";
while(*p++)
printf("%c",*p);
return 0;
}
The first statement:
char* p = "Hello";
declares p as a pointer to char. When we say "pointer to a char", what does that mean? It means that the value of p is the address of a char; p tells us where in memory there is some space set aside to hold a char.
The statement also initializes p to point to the first character in the string literal "Hello". For the sake of this exercise, it's important to understand p as pointing not to the entire string, but only to the first character, 'H'. After all, p is a pointer to one char, not to the entire string. The value of p is the address of the 'H' in "Hello".
Then you set up a loop:
while (*p++)
What does the loop condition *p++ mean? Three things are at work here that make this puzzling (at least until familiarity sets in):
The precedence of the two operators, postfix ++ and indirection *
The value of a postfix increment expression
The side effect of a postfix increment expression
1. Precedence. A quick glance at the precedence table for operators will tell you that postfix increment has a higher precedence (16) than dereference / indirection (15). This means that the complex expression *p++ is going to be grouped as: *(p++). That is to say, the * part will be applied to the value of the p++ part. So let's take the p++ part first.
2. Postfix expression value. The value of p++ is the value of p before the increment. If you have:
int i = 7;
printf ("%d\n", i++);
printf ("%d\n", i);
the output will be:
7
8
because i++ evaluates to i before the increment. Similarly p++ is going to evaluate to the current value of p. As we know, the current value of p is the address of 'H'.
So now the p++ part of *p++ has been evaluated; it's the current value of p. Then the * part happens. *(current value of p) means: access the value at the address held by p. We know that the value at that address is 'H'. So the expression *p++ evaluates to 'H'.
Now hold on a minute, you're saying. If *p++ evaluates to 'H', why doesn't that 'H' print in the above code? That's where side effects come in.
3. Postfix expression side effects. The postfix ++ has the value of the current operand, but it has the side effect of incrementing that operand. Huh? Take a look at that int code again:
int i = 7;
printf ("%d\n", i++);
printf ("%d\n", i);
As noted earlier, the output will be:
7
8
When i++ is evaluated in the first printf(), it evaluates to 7. But the C standard guarantees that at some point before the second printf() begins executing, the side effect of the ++ operator will have taken place. That is to say, before the second printf() happens, i will have been incremented as a result of the ++ operator in the first printf(). This, by the way, is one of the few guarantees the standard gives about the timing of side effects.
In your code, then, when the expression *p++is evaluated, it evaluates to 'H'. But by the time you get to this:
printf ("%c", *p)
that pesky side-effect has occurred. p has been incremented. Whoa! It no longer points to 'H', but to one character past 'H': to the 'e', in other words. That explains your cockneyfied output:
ello
Hence the chorus of helpful (and accurate) suggestions in the other answers: to print the Received Pronunciation "Hello" and not its cockney counterpart, you need something like
while (*p)
printf ("%c", *p++);
So much for that. What about the rest? You ask about the meanings of these:
*ptr++
*++ptr
++*ptr
We just talked about the first, so let's look at the second: *++ptr.
We saw in our earlier explanation that postfix increment p++ has a certain precedence, a value, and a side effect. The prefix increment ++p has the same side effect as its postfix counterpart: it increments its operand by 1. However, it has a different precedence and a different value.
The prefix increment has lower precedence than the postfix; it has precedence 15. In other words, it has the same precedence as the dereference / indirection operator *. In an expression like
*++ptr
what matters is not precedence: the two operators are identical in precedence. So associativity kicks in. The prefix increment and the indirection operator have right-left associativity. Because of that associativity, the operand ptr is going to be grouped with the rightmost operator ++ before the operator more to the left, *. In other words, the expression is going to be grouped *(++ptr). So, as with *ptr++ but for a different reason, here too the * part is going to be applied to the value of the ++ptr part.
So what is that value? The value of the prefix increment expression is the value of the operand after the increment. This makes it a very different beast from the postfix increment operator. Let's say you have:
int i = 7;
printf ("%d\n", ++i);
printf ("%d\n", i);
The output will be:
8
8
... different from what we saw with the postfix operator. Similarly, if you have:
char* p = "Hello";
printf ("%c ", *p); // note space in format string
printf ("%c ", *++p); // value of ++p is p after the increment
printf ("%c ", *p++); // value of p++ is p before the increment
printf ("%c ", *p); // value of p has been incremented as a side effect of p++
the output will be:
H e e l // good dog
Do you see why?
Now we get to the third expression you asked about, ++*ptr. That's the trickiest of the lot, actually. Both operators have the same precedence, and right-left associativity. This means the expression will be grouped ++(*ptr). The ++ part will be applied to the value of the *ptr part.
So if we have:
char q[] = "Hello";
char* p = q;
printf ("%c", ++*p);
the surprisingly egotistical output is going to be:
I
What?! Okay, so the *p part is going to evaluate to 'H'. Then the ++ comes into play, at which point, it's going to be applied to the 'H', not to the pointer at all! What happens when you add 1 to 'H'? You get 1 plus the ASCII value of 'H', 72; you get 73. Represent that as a char, and you get the char with the ASCII value of 73: 'I'.
That takes care of the three expressions you asked about in your question. Here is another, mentioned in the first comment to your question:
(*ptr)++
That one is interesting too. If you have:
char q[] = "Hello";
char* p = q;
printf ("%c", (*p)++);
printf ("%c\n", *p);
it will give you this enthusiastic output:
HI
What's going on? Again, it's a matter of precedence, expression value, and side effects. Because of the parentheses, the *p part is treated as a primary expression. Primary expressions trump everything else; they get evaluated first. And *p, as you know, evaluates to 'H'. The rest of the expression, the ++ part, is applied to that value. So, in this case, (*p)++ becomes 'H'++.
What is the value of 'H'++? If you said 'I', you've forgotten (already!) our discussion of value vs. side effect with postfix increment. Remember, 'H'++ evaluates to the current value of 'H'. So that first printf() is going to print 'H'. Then, as a side effect, that 'H' is going to be incremented to 'I'. The second printf() prints that 'I'. And you have your cheery greeting.
All right, but in those last two cases, why do I need
char q[] = "Hello";
char* p = q;
Why can't I just have something like
char* p = "Hello";
printf ("%c", ++*p); // attempting to change string literal!
Because "Hello" is a string literal. If you try ++*p, you're trying to change the 'H' in the string to 'I', making the whole string "Iello". In C, string literals are read-only; attempting to modify them invokes undefined behavior. "Iello" is undefined in English as well, but that's just coincidence.
Conversely, you can't have
char p[] = "Hello";
printf ("%c", *++p); // attempting to modify value of array identifier!
Why not? Because in this instance, p is an array. An array is not a modifiable l-value; you can't change where p points by pre- or post- increment or decrement, because the name of the array works as though it's a constant pointer. (That's not what it actually is; that's just a convenient way to look at it.)
To sum up, here are the three things you asked about:
*ptr++ // effectively dereferences the pointer, then increments the pointer
*++ptr // effectively increments the pointer, then dereferences the pointer
++*ptr // effectively dereferences the pointer, then increments dereferenced value
And here's a fourth, every bit as much fun as the other three:
(*ptr)++ // effectively forces a dereference, then increments dereferenced value
The first and second will crash if ptr is actually an array identifier. The third and fourth will crash if ptr points to a string literal.
There you have it. I hope it's all crystal now. You've been a great audience, and I'll be here all week.
Suppose ptr points to the i-th element of array arr.
*ptr++ evaluates to arr[i] and sets ptr to point to the (i+1)-th element of arr. It is equivalent to *(ptr++).
*++ptr sets ptr to point to the (i+1)-th element of arr and evaluates to arr[i+1]. It is equivalent to *(++ptr).
++*ptr increases arr[i] by one and evaluates to its increased value; the pointer ptr is left untouched. It is equivalent to ++(*ptr).
There's also one more, but you'd need parentheses to write it:
(*ptr)++ increases arr[i] by one and evaluates to its value before being increased; the pointer ptr is again left untouched.
The rest you can figure out yourself; it was also answered by #Jaguar.
*ptr++ : post increment a pointer ptr
*++ptr : Pre Increment a pointer ptr
++*ptr : preincrement the value at ptr location
Read here about pre increment and post increment operators
This will give Hello as output
int main()
{
const char *p = "Hello";
while(*p)
printf("%c",*p++);//Increment the pointer here
return 0;
}
The condition in your loop is bad:
while(*p++)
printf("%c",*p);
Is the same as
while(*p)
{
++p;
printf("%c",*p);
}
And that's wrong, this should be:
while(*p)
{
printf("%c",*p);
++p;
}
*ptr++ is the same as *(ptr++), which is:
const char *ptr = "example";
char value;
value = *ptr;
++p;
printf("%c", value); // will print 'e'
*++ptr is the same as *(++ptr), which is:
const char *ptr = "example";
char value;
++p;
value = *ptr;
printf("%c", value); // will print 'x'
++*ptr is the same as ++(*ptr), which is:
const char *ptr = "example";
char value;
value = *ptr;
++value;
printf("%c", value); // will print 'f' ('e' + 1)
You right about precedence, note that the * has precedence over prefix increment, but not over postfix increment. Here's how these breakdown:
*ptr++ - going from left-to-right, dereference the pointer, and then increment the pointer value (not what it points to, due to the precedence of postfix over dereference)
*++ptr - increment the pointer and then dereference it, this is because prefix and dereference have the same precedence and so they are evaluated in order right-to-left
++*ptr - similar to the above in terms of precedence, again going from right-to-left in order dereference the pointer and then increment what the pointer points to. Please note that in your case this one will lead to undefined behaviour because you're trying to modify a read-only variable (char* p = "Hello";).
I'm going to add my take because while the other answers are correct I think they're missing something.
v = *ptr++
means
temp = ptr;
ptr = ptr + 1
v = *temp;
Where as
v = *++ptr
means
ptr = ptr + 1
v = *ptr
It's important to understand that post increment (and post decrement) mean
temp = ptr // Temp created here!!!
ptr = ptr + 1 // or - 1 if decrement)
v = *temp // Temp destroyed here!!!
Why does it matter? Well in C that's not so important. In C++ though ptr might be a complex type like an iterator. For example
for (std::set<int>::iterator it = someSet.begin(); it != someSet.end(); it++)
In this case, because it is a complex type it++ maybe have side effects because of the temp creation. Of course if you're lucky the compiler will try to throw away code that's not needed but if iterator's constructor or destructor do anything then it++ is going to show those effects when it creates temp.
The short of what I'm trying to say is Write What You Mean. If you mean increment ptr then write ++ptr not ptr++. If you mean temp = ptr, ptr += 1, temp then write ptr++
*ptr++ // 1
This is the same as:
tmp = *ptr;
ptr++;
So the value of the object pointed to by ptr is retrieved, then ptr is incremented.
*++ptr // 2
This is the same as:
++ptr;
tmp = *ptr;
So the pointer ptr is incremented, then the object pointed to by ptr is read.
++*ptr // 3
This is the same as:
++(*ptr);
So the object pointed to by ptr is incremented; ptr itself is unchanged.
Pointer Expressions : *ptr++, *++ptr and ++*ptr :
Note : pointers must initialized and must have valid address. Because in RAM apart from our program(a.out) there are lot more program running simultaneously i.e if you are try to access some memory which was not reserved for you OS will through Segmentation fault.
Before explaining this lets consider simple example ?
#include<stdio.h>
int main()
{
int num = 300;
int *ptr;//uninitialized pointer.. must be initialized
ptr = #
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
*ptr = *ptr + 1;//*ptr means value/data on the address.. so here value gets incremented
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
/** observe here that "num" got changed but manually we didn't change, it got modified by pointer **/
ptr = ptr + 1;//ptr means address.. so here address got incremented
/** char pointer gets incremented by 1 bytes
Integer pointer gets incremented by 4 bytes
**/
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}
analyze the output of above code, I hope you got the output of above code. One thing is clear from above code is that pointer name (ptr) means we are talking about address and *ptr means we are talking abbout value/data.
CASE 1 : *ptr++ , *++ptr, *(ptr++) and *(++ptr) :
above mentioned all 4 syntax are similar, in all address gets incremented but how address gets incremented that's different.
Note : for solving any expression find out how many operators are there in expression, then find out priorities of operator. I multiple operators having same priority then check order of evolution or associativity that may right(R) to left(L) ot left to right.
*ptr++ : Here 2 operators are there namely de-reference( *) and ++(increment). Both are having same priority then check the associativity which is R to L. So starts solving from Right to Left, whatever operators is coming first.
*ptr++ : first ++ came while solving from R to L, so address gets incremented but its post increment.
*++ptr : Same as first one here also address gets incremented but its pre increment.
*(ptr++) : Here there are 3 operators, among them grouping () having highest priority, So first ptr++ solved i.e address gets incremented but post.
*(++ptr) : Same as above case here also address gets incremented but pre increment.
CASE 2 : ++*ptr, ++(*ptr), (*ptr)++ :
above mentioned all 4 syntax are similar, in all value/data gets incremented but how value gets changed that's different.
++*ptr : first * came while solving from R to L, so value gets changed but its pre increment.
++(*ptr) : Same as above case, value gets modified.
(*ptr)++ : Here there are 3 operators, among them grouping () having highest priority, Inside () *ptr is there , So first *ptr is solved i.e value gets incremented but post.
Note : ++*ptr and *ptr = *ptr + 1 both are same, in both case value gets changed.
++*ptr : only 1 instruction (INC) is used, directly value gets changed in single shot.
*ptr = *ptr + 1 : here first value gets incremented(INC) and then assigned(MOV).
To understand all above different syntax of increment on pointer lets consider simple code :
#include<stdio.h>
int main()
{
int num = 300;
int *ptr;
ptr = #
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
*ptr++;//address changed(post increment), value remains un-changed
// *++ptr;//address changed(post increment), value remains un-changed
// *(ptr)++;//address changed(post increment), value remains un-changed
// *(++ptr);//address changed(post increment), value remains un-changed
// ++*ptr;//value changed(pre increment), address remains un-changed
// (*ptr)++;//value changed(pre increment), address remains un-changed
// ++(*ptr);//value changed(post increment), address remains un-changed
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}
In above code, try to comment/un-comment comments and analyze outputs.
Pointers as Constant : there are no of ways by which you can make pointers as constant, few I am mentioning here.
1)const int *p OR int const *p : Here value is constant, address is not constant i.e where p is pointing ? Some address ? On that address what is the value ? Some value right ? That value is constant, you can't modify that value but where pointer is pointing ? Some address right ? It can point to other address also.
To understand this lets consider below code :
#include<stdio.h>
int main()
{
int num = 300;
const int *ptr;//constant value, address is modifible
ptr = #
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
*ptr++;//
// *++ptr;//possible bcz you are trying to change address which is possible
// *(ptr)++;//possible
// *(++ptr);//possible
// ++*ptr;//not possible bcz you trying to change value which is not allowed
// (*ptr)++;//not possible
// ++(*ptr);//not possible
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}
Try to analyze the output of above code
2)int const *p : it's called '**constant pointe**r' i.e address is constant but value is not constant. Here you are not allowed to change the address but you can modify the value.
Note : constant pointer(above case) must initialize while declariung itself.
To understand this lets check simple code.
#include<stdio.h>
int main()
{
int x = 300;
int* const p;
p = &x;
printf("x = %d p =%p and *p = %d\n",num,p,*p);
}
In above code, if you observe that there is no ++*p or *p++ So you may thought this is simple case because we are not changing address or value but it will produce error. Why ? Reason I mention in comments.
#include<stdio.h>
int main()
{
int x = 300;
/** constant pointer must initialize while decaring itself **/
int* const p;//constant pointer i.e its pointing to some address(here its pointing to garbage), it should point to same address(i.e garbage ad
dress only
p = &x;// but here what we are doing ? we are changing address. we are making p to point to address of x instead of garbage address.
printf("x = %d p =%p and *p = %d\n",num,p,*p);
}
So whats the Solution of this problem ?
int* const p = &x;
for more about this case lets consider below example.
#include<stdio.h>
int main()
{
int num = 300;
int *const ptr = #//constant value, address is modifible
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
*ptr++;//not possible
// *++ptr;//not possible bcz you are trying to change address which is not possible
// *(ptr)++;//not possible
// *(++ptr);//not possible
// ++*ptr;// possible bcz you trying to change value which is allowed
// (*ptr)++;// possible
// ++(*ptr);// possible
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}
3)const int* const p : Here both address and value are constant.
To understand this lets check below code
#include<stdio.h>
int main()
{
int num = 300;
const int* const ptr = #//constant value,constant address
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
*ptr++;//not possible
++*ptr;//not possible
printf(" num = %d ptr = %p and data on ptr : %d \n",num,ptr,*ptr);
}
Postfix ++ has higher precedence than unary *.
Prefix ++ and unary * have the same precedence, expressions with both have right-to-left operator associativity, meaning the right one(s) binds to the operand before the left one(s).
Therefore:
*ptr++ Increment the pointer by 1 item then de-reference the memory location it had before incrementing.
*++ptr Increment the pointer by 1 item then de-reference the memory location where it now points.
++*ptr De-reference the memory location then increment the contents (value) there by 1.
postfix and prefix has higher precedence than dereference so
*ptr++ here post increment ptr and then pointing to new value of ptr
*++ptr here Pre Increment fist then pointing to new value of ptr
++*ptr here first get the value of ptr pointing to and increment that vlaue
const char *p = "Hello";
*p means "Hello"
^
|
p
*p++ means "Hello"
^
|
p
*++p means "Hello"
^
| (WHILE THE STATEMENT IS EXECUTED)
p
*++p means "Hello"
^
| (AFTER THE STATEMENT IS EXECUTED)
p
++*p means that you are trying to increment the ASCII value of *p which
is "Hello"
^
|
p
you cannot increment the value 'cause it's a constant so you would get an error
as for your while loop the loop runs until *p++ reaches the end of the string where there is a '\0'(NULL) character.
Now since *p++ skips the first character you would only get your output starting from the second character.
The following code will not output anything because while loop has '\0'
const char *p = "Hello";
while('\0')
printf("%c",*p);
The following code will give you the same output as the next code i.e ello .
const char *p = "Hello";
while(*++p)
printf("%c",*p);
...................................
const char *p = "Hello";
while(*p++)
printf("%c",*p);
As per the information in this link, post increment and decrement operators have first place. And this link says " Take this example:
foo = *p++;
Here p is incremented as a side effect of the expression, but foo takes the value of *(p++) rather than (*p)++, since the unary operators bind right to left ".
But after doing it practically nothing happened as information mentioned in those links.
#include<stdio.h>
#include<stdlib.h>
int main()
{
int i = 1;
int *iptr;
iptr = &i;
int num = *iptr++;//1) In this expression the value of 'i' is assigned to num. And an attempt of post incrementing the address stored in *iptr is done as side effect.
printf("Num value: %d\n",num);
printf("Pointer: %d\n",*iptr);//2) The address of *iptr is not incremented. If it was then the value of 'i' would not be printed instead it would print the incremented address itself.
printf("Post increment: %d\n",*iptr++);//3) The address of *iptr will be post incremented (which didn't happen in case of num). But for now the value of 'i' will be printed.
printf("After increment: %d\n",*iptr);//4) Now the incremented address stored in *iptr will be displayed as there is no value assigned to that address.
return 0;
}
In the above experiment the effect of post increment can be seen only after a statement terminator. But no effect can be seen even after a statement terminator if a post increment is done on the right operand of the assignment operator. E.G int num = *iptr++; (as mentioned in the above experiment). So exactly what place does post increment and decrement operators have in the rules of operator precedence.
The problem with your code is that it has undefined behavior: when you point a pointer to a singular local variable, dereferencing incremented pointer yields undefined behavior.
Derefefencing incremented pointers is well-defined for pointers into an array.
int array[] = {1, 2, 3};
int *iptr = &array[0];
int num = *iptr++;
In addition, printing iptr using %d and dereference operator is incorrect: you need to print it using %p, after casting iptr to void*, without dereferencing:
printf("Pointer: %p\n", (void*)iptr);
// No asterisk here -----------^
Now everything works as expected (demo).
I just read some question about pointer. Here is the code:
int a[5]={1, 2, 3, 4, 5};
int *p = (int*)(&a + 1);//second line
cout<<(*p)<<endl;
My compiler output is 0. What is *p? Is it the pointer to array a? and what is &a+1 means?
This is what your declaration statement means:
p
|
v
a[0] a[1] a[2] a[3] a[4] | a[5]
---------(Length)------->
But you're trying to get this (I assume):
p
|
v
a[0] a[1] a[2] a[3] a[4] |
---------(Length)------->
You need to remove the second set of parenthesis from your declaration statement to get a[1]:
int * p = (int *)(&a + 1);
// change to this:
int * p = (int *) &a + 1;
The reason you're getting the wrong value has to do with the sizeof operator, operator precedence, and pointer arithmetic. Let me explain those before I explain the error.
Sizeof Operator
The sizeof operator evaluates the size (in bytes) of a datatype. Immediate example:
sizeof (char) // always returns 1
sizeof (int) // usually returns 4 or 8
sizeof (int *) // usually returns 4 or 8
And note this interesting example:
int a[5];
sizeof (a) // returns sizeof (int) * 5
Operator Precedence
Operator precedence is the order in which a series of operators are evaluated. Anything in parenthesis will be evaluated first. After parenthesis are evaluated, it's up to the operator precedence to determine what order the expression will be solved.
Here's the relevant operators and they're order in the precedence table:
Operator Description Associativity
() Parenthesis Left-to-right
(cast) Cast Right-to-left
& Address of Right-to-left
+, - Plus, Minus Right-to-left
Pointer Arithmetic
Pointer arithmetic is mostly about adding, subtracting and multiplying pointers with integers (or other pointers). What you need to know (for the scope of this question) is this:
int * p;
p = p + 1;
Even though it says + 1, it is actually adding sizeof (int) to the pointer.
This was a design choice by the writers of the C standard because it is much more common
that programmers want to add sizeof (int) to the pointer (which brings them to the next integer in an array) than to add 1 (which brings the pointer in between the first and second element in the array).
More generally put:
datatype p;
p = p + 1;
// actually means
p = p + sizeof (datatype);
Here's a relevant example:
int a[5];
a = a + 1;
// actually means
a = a + sizeof (a);
// remember that sizeof (a) is going to be sizeof (int) * 5?
Declaration Statement
Back to your declaration statement:
int * p = (int *)(&a + 1);
You may already see what's wrong with it: a + 1 really means a + sizeof (a), which brings you out of scope of the array. This may be 0 (often it is) or it may be some other random value.
What you might not have noticed is that this:
int * p = (int *) &a + 1;
Actually gives you the second element in the array. This has to do with operator precedence. If you look at the operator precedence table that I put in a link, casts have a higher precedence than & and + operators. So if a is cast as a (int *) instead of a[5] before the rest of the expression is evaluated, then it becomes equivalent to this:
int * a;
a = a + 1; /* and this would
give you the second element
in the array */
So simply put, if you want to access the second element in your array, change:
int * p = (int *)(&a + 1);
// to this:
int * p = (int *) &a + 1;
&a is the address of the array.
&a + 1 is also an address, but what is this 1? It's a pointer that points sizeof a bytes from a. So it's like writing int *p = &a[5];, then you're casting it to int *.
Now why 0? Because a[5] happens to be 0 - Note that it's out of bounds and could be anything else (Undefined behavior).
Note that arrays are zero-based, meaning that the indexes are from 0. So actually a[4] is the last element, a[5] is out of bounds.
The operator & is used to take the address of a variable. Thus, &a is of type pointer to array of 5 ints: int (*)[5].
Pointer arithmetic means that when you have a pointer p, then p+1 will point to the next element, which is sizeof(*p) bytes away. This means that &a+1 points to 5*sizeof(int) blocks away, namely, the block after the last element in the array.
Casting &a+1 to int * means that now you want this new pointer to be interpreted as a pointer to int instead of pointer to array of 5 ints. You're saying that, from now on, this pointer references something that is sizeof(int) bytes long, so if you increment it, it will move forward sizeof(int) units.
Therefore, *p is accessing a[5], which is an out of bounds position (one beyond the last), so the program has undefined behavior. It printed 0, but it could have crashed or printed something else. Anything can happen when undefined behavior occurs.
int *p = (int*)(&a+1);
what is *p? :
In your code, *p is a pointer to an unknown element of type int.
Lets reason it out:
&a is a valid pointer expression. An integer can be added to a pointer expression.
Result of &a : points to the whole array a[5]. Its type is int (*)[5]
Result of sizeof *(&a) is 5, which is the size of the array.
Result of &a +1 is pointer expression which holds the address of the 1st int beyond the one &a currently points to.
Hence, 1 object past the &a is what *p points to. Hence it is unknown element of type int. So, accessing unknown element is undefined behaviour. This also answers why your output is zero.
Side Note:
If you really wanted to access the second element in the array, you should add 1 to pointer which points to the first element of array. a points to the first element in the array and size is sizeof(int*).
Result of a+1 is the address of the second element in the array.
Result of *(a+1) is the value of the second element in the array. 2
Please help me understand the reason the following code works the way it does:
#include <stdio.h>
int main(){
int a = 10;
void *b = &a;
int *p = b;
printf("%u",*p++);
return 0;
}
I know the output of printf will be 10, but I'm not quite following why *p++ is 10
Here are my steps:
1) void *b = &a; stores the address of a in pointer b
2) int *p = b; pointer p now points to the same data item as pointer b
3) printf("%u",*p++); is where I get confused... the dereference of pointer p is a, which is 10... isn't *p++ basically the same as 10+1 which will be 11?
*p++ is essentially *(p++). It evaluates to the value of p before it is incremented which is the address to a. Then you dereference it which evaluates to the value 10.
The post-increment operator in the expression *p++ applies to the pointer, not the value stored at that location, so the result is never 11, before or after it is evaluated. The expression *p++ means: dereference p (get it's value) then increment p one location. Since p points to an int, incrementing it will move it forward sizeof(int) bytes . The addition does not ever apply to the value that p points to, which is 10.
However, the expression (*p)++ is different. It dereferences p (gets its value) and then increments the value in that memory location. The expression evaluates to the original value. So after executing the statement
int c = (*p)++;
the variable c would equal 10, while a would equal 11.
*p++ is parsed as *(p++). p++ evaluates to p, and then increments p, so the change won't be seen until the next reference to p. So *p is 10, *p++ is 10 (but p now points to &a+1), *++p is undefined behavior (because *(&a+1) is not a valid value), (*p)++ is 10 but changes a to 11, and ++*p (or ++(*p)) is 11 (as is a).
Variable p is a pointer to an int (pointing to a)
The expression *p dereferences the pointer, hence it's like accessing the int a directly.
Operator postfix ++ on pointer p takes precedence over the dereferencing. Therefore *p++ increments the pointer p (to whatever junk is in memory after int a) AFTER the expression is evaluated, so the dereferencing still resolves to a and that's why 10 is printed. But after the statement is run the value of p is changed. So, likely after that statement if you do printf("%u ",*p) you will get an awkward value.
If you do ++*p however, the expression is evaluated as ++ operation on the dereferenced int variable pointed by p. If you want to avoid trouble like this, when not sure, use parenthesis:
(*p)++
++(*p)
And you're making sure you are dereferencing the value and acting on it. Incrementing a pointer value is a very dangerous operation allowed by languages like C and C++, so avoid whenever possible!
Why *p++ is 10 ?
[C11: §6.5.2.4/2]: The result of the postfix ++ operator is the value of the operand. As a side effect, the value of the operand object is incremented (that is, the value 1 of the appropriate type is added to it).
The below statement
printf("%u",*p++);
is equivalent to
printf("%u",*p); /* p points to 'a' and value of `a` is 10. Hence, 10 is printed */
p = p + 1;
p is of type pointer-to-int. Hence, 1 is scaled to sizeof (int).
As a result, p now points to an int at address : p + sizeof (int)
I just want to add my five cents.
For incrementing value indirected via pointer you can use ++*ip or (*ip)++. There is a nice explanation about parentheses in K&R book:
The parentheses are necessary in this last example
(*ip)++; without them, them expression
would increment ip instead of what it points to, because
unary operators like * and ++ associate right to left.
And in your piece of code you got 10 because printf will print original value of variable and only after it wiil be incremented by one due of using of postfix ++ operator.
Trying to understand the behaviour of pointers in C, I was a little surprised by the following (example code below):
#include <stdio.h>
void add_one_v1(int *our_var_ptr)
{
*our_var_ptr = *our_var_ptr +1;
}
void add_one_v2(int *our_var_ptr)
{
*our_var_ptr++;
}
int main()
{
int testvar;
testvar = 63;
add_one_v1(&(testvar)); /* Try first version of the function */
printf("%d\n", testvar); /* Prints out 64 */
printf("# %p\n\n", &(testvar));
testvar = 63;
add_one_v2(&(testvar)); /* Try first version of the function */
printf("%d\n", testvar); /* Prints 63 ? */
printf("# %p\n", &(testvar)); /* Address remains identical */
}
Output:
64
# 0xbf84c6b0
63
# 0xbf84c6b0
What exactly does the *our_var_ptr++ statement in the second function (add_one_v2) do since it's clearly not the same as *our_var_ptr = *our_var_ptr +1?
This is one of those little gotcha's that make C and C++ so much fun. If you want to bend your brain, figure out this one:
while (*dst++ = *src++) ;
It's a string copy. The pointers keep getting incremented until a character with a value of zero is copied. Once you know why this trick works, you'll never forget how ++ works on pointers again.
P.S. You can always override the operator order with parentheses. The following will increment the value pointed at, rather than the pointer itself:
(*our_var_ptr)++;
OK,
*our_var_ptr++;
it works like this:
The dereference happens first, giving you the memory location indicated by our_var_ptr (which contains 63).
Then the expression is evaluated, the result of 63 is still 63.
The result is thrown away (you aren't doing anything with it).
our_var_ptr is then incremented AFTER the evaluation. It's changing where the pointer is pointing to, not what it's pointing at.
It is effectively the same as doing this:
*our_var_ptr;
our_var_ptr = our_var_ptr + 1;
Make sense? Mark Ransom's answer has a good example of this, except he actually uses the result.
Due to operator precedence rules and the fact that ++ is a postfix operator, add_one_v2() does dereference the pointer, but the ++ is actually being applied to the pointer itself. However, remember that C always uses pass-by-value: add_one_v2() is incrementing its local copy of the pointer, which will have no effect whatsoever on the value stored at that address.
As a test, replace add_one_v2() with these bits of code and see how the output is affected:
void add_one_v2(int *our_var_ptr)
{
(*our_var_ptr)++; // Now stores 64
}
void add_one_v2(int *our_var_ptr)
{
*(our_var_ptr++); // Increments the pointer, but this is a local
// copy of the pointer, so it doesn't do anything.
}
Much confusion here, so here is a modified test program to make what happens clear (or at least clearer):
#include <stdio.h>
void add_one_v1(int *p){
printf("v1: pre: p = %p\n",p);
printf("v1: pre: *p = %d\n",*p);
*p = *p + 1;
printf("v1: post: p = %p\n",p);
printf("v1: post: *p = %d\n",*p);
}
void add_one_v2(int *p)
{
printf("v2: pre: p = %p\n",p);
printf("v2: pre: *p = %d\n",*p);
int q = *p++;
printf("v2: post: p = %p\n",p);
printf("v2: post: *p = %d\n",*p);
printf("v2: post: q = %d\n",q);
}
int main()
{
int ary[2] = {63, -63};
int *ptr = ary;
add_one_v1(ptr);
printf("# %p\n", ptr);
printf("%d\n", *(ptr));
printf("%d\n\n", *(ptr+1));
add_one_v2(ptr);
printf("# %p\n", ptr);
printf("%d\n", *ptr);
printf("%d\n", *(ptr+1));
}
with the resulting output:
v1: pre: p = 0xbfffecb4
v1: pre: *p = 63
v1: post: p = 0xbfffecb4
v1: post: *p = 64
# 0xbfffecb4
64
-63
v2: pre: p = 0xbfffecb4
v2: pre: *p = 64
v2: post: p = 0xbfffecb8
v2: post: *p = -63
v2: post: q = 64
# 0xbfffecb4
64
-63
Four things to note:
changes to the local copy of the pointer are not reflected in the calling pointer.
changes to the target of the local pointer do affect the target of the calling pointer (at least until the target pointer is updated)
the value pointed to in add_one_v2 is not incremented and neither is the following value, but the pointer is
the increment of the pointer in add_one_v2 happens after the dereference
Why?
Because ++ binds more tightly than * (as dereference or multiplication) so the increment in add_one_v2 applies to the pointer, and not what it points at.
post increments happen after the evaluation of the term, so the dereference gets the first value in the array (element 0).
As the others have pointed out, operator precedence cause the expression in the v2 function to be seen as *(our_var_ptr++).
However, since this is a post-increment operator, it's not quite true to say that it increments the pointer and then dereferences it. If this were true I don't think you'd be getting 63 as your output, since it would be returning the value in the next memory location. Actually, I believe the logical sequence of operations is:
Save off the current value of the pointer
Increment the pointer
Dereference the pointer value saved in step 1
As htw explained, you aren't seeing the change to the value of the pointer because it is being passed by value to the function.
If you are not using parenthesis to specify the order of operations, both prefix and postfix increments have precedence over reference and dereference. However, prefix increment and postfix increment are different operations. In ++x, the operator takes a reference to your variable, add one to it and return it by value. In x++, the operator increment your variable, but returns its old value. They behave sort of like this (imagine they are declared as methods inside your class):
//prefix increment (++x)
auto operator++()
{
(*this) = (*this) + 1;
return (*this);
}
//postfix increment (x++)
auto operator++(int) //unfortunately, the "int" is how they differentiate
{
auto temp = (*this);
(*this) = (*this) + 1; //same as ++(*this);
return temp;
}
(Note that there is a copy involved in the postfix increment, making it is less efficient. That's the reason why you should prefer ++i instead of i++ in loops, even though most compilers do it automatically for you these days.)
As you can see, postfix increment is processed first, but, because of the way it behaves, you will be dereferencing the prior value of the pointer.
Here is an example:
char * x = {'a', 'c'};
char y = *x++; //same as *(x++);
char z = *x;
In the second line, the pointer x will be incremented before the dereference, but the dereference will happen over the old value of x (which is an address returned by the postfix increment). So y will be initialized with 'a', and z with 'c'. But if you do it like this:
char * x = {'a', 'c'};
char y = (*x)++;
char z = *x;
Here, x will be dereferenced and the value pointed by it ('a') will be incremented (to 'b'). Since the postfix increment returns the old value, y will still be initialized with 'a'. And since the pointer didn't change, z will be initialized with the new value 'b'.
Now let's check the prefix cases:
char * x = {'a', 'c'};
char y = *++x; //same as *(++x)
char z = *x;
Here, the dereference will happen on the incremented value of x (which is immediately returned by the prefix increment operator), so both y and z will be initialized with 'c'. To get a different behavior, you can change the order of the operators:
char * x = {'a', 'c'};
char y = ++*x; //same as ++(*x)
char z = *x;
Here you ensure that you are incrementing the content of x first and the value of the pointer never change, so y and z will be assigned with 'b'. In the strcpy function (mentioned in other answer), the increment is also done first:
char * strcpy(char * dst, char * src)
{
char * aux = dst;
while(*dst++ = *src++);
return aux;
}
At each iteration, src++ is processed first and, being a postfix increment, it returns the old value of src. Then, the old value of src (which is a pointer) is dereferenced to be assigned to whatever is in the left side of the assignment operator. The dst is then incremented and its old value is dereferenced to become an lvalue and receive the old src value. This is why dst[0] = src[0], dst[1] = src[1] etc, up until *dst is assigned with 0, breaking the loop.
Addendum:
All the code in this answer was tested with C language. In C++ you probably won't be able to list-initialize the pointer. So, if you want to test the examples in C++, you should initialize an array first and then degrade it to a pointer:
char w[] = {'a', 'c'};
char * x = w;
char y = *x++; //or the other cases
char z = *x;
our_var_ptr is a pointer to some memory. ie it is the memory cell where the data is stored. (n this case 4 bytes in the binary format of an int).
*our_var_ptr is the dereferenced pointer - it goes to the location the pointer 'points' at.
++ increments a value.
so. *our_var_ptr = *our_var_ptr+1 dereferences the pointer and adds one to the value at that location.
Now add in operator precedence - read it as (*our_var_ptr) = (*our_var_ptr)+1 and you see that the dereference happens first, so you take the value and incremement it.
In your other example, the ++ operator has lower precedence than the *, so it takes the pointer you passed in, added one to it (so it points at garbage now), and then returns. (remember values are always passed by value in C, so when the function returns the original testvar pointer remains the same, you only changed the pointer inside the function).
My advice, when using dereferencing (or anything else) use brackets to make your decision explicit. Don't try to remember the precedence rules as you'll only end up using another language one day that has them slightly different and you'll get confused. Or old and end up forgetting which has higher precedence (like I do with * and ->).
I will try to answer this from a bit of a different angle...
Step 1
Let's look at the operators and the operands:
In this case it is the operand, and you have two operators, in this case * for dereferencing and ++ for increment.
Step 2
which has the higher precedence
++ has higher precedence over *
Step 3
Where is ++, it is to the right which means POST Increment
In this case, the compiler take a 'mental note' to perform the increment AFTER it is done with all the other operators...
note if it was *++p then it will do it BEFORE
so in this case, it is as equivalent to taking two of the processor's register, one will hold the value of the dereferenced *p and the other will hold the value of the incremented p++, the reason in this case there are two, is the POST activity...
This is where in this case it is tricky, and it looks like a contradiction.
One would expect the ++ to take precedence over the *, which it does, only that the POST means that it will be applied only after ALL other operands, BEFORE the next ';' token...
From K&R, page 105: "The value of *t++ is the character that t pointed to before t was incremented".
uint32_t* test;
test = &__STACK_TOP;
for (i = 0; i < 10; i++) {
*test++ = 0x5A5A5A5A;
}
//same as above
for (i = 0; i < 10; i++) {
*test = 0x5A5A5A5A;
test++;
}
Because test is a pointer, test++ (this is without dereferencing it) will increment the pointer (it increments the value of test which happens to be the (destination) address of what's being pointed at). Because the destination is of type uint32_t, test++ will increment by 4 bytes, and if the destination was for example an array of this type, then test would now be pointing at the next element.
When doing these kinds of manipulations, sometimes you have to cast the pointer first to get the desired memory offset.
((unsigned char*) test)++;
This will increment the address by 1 byte only ;)
The '++' operator has higher precedence over the '*' operator, which means that the pointer address will be incremented before being dereferenced.
The '+' operator, however, has lower precedence than '*'.
Pictures are worth approximately a thousand words (give or take a million or so)...and symbols can be pictures (and vice versa.)
So⸺for those of us who seek tl;dr's (optimized data consumption) yet still want “(mostly) lossless” encoding, vector images/pictures/illustrations/demos are paramount.
In other words, just ignore my last 2 statements and see below.
Valid Forms
*a++ ≣ *(a++)
≣ (a++)[0] ≣ a++[0]
≣ 0[a++] // Don't you dare use this (“educational purposes only”)
// These produce equivalent (side) effects;
≡ val=*a,++a,val
≡ ptr=a,++a,*ptr
≡ *(ptr=a,++a,ptr)
*++a ≣ *(++a)
≣ *(a+=1) ≣ *(a=a+1)
≣ (++a)[0] ≣ (a+=1)[0] ≣ (a=a+1)[0] // ()'s are necessary
≣ 0[++a] // 0[a+=1], etc... “educational purposes only”
// These produce equivalent (side) effects:
≡ ++a,*a
≡ a+=1,*a
≡ a=a+1,*a
++*a ≣ ++(*a)
≣ *a+=1
≣ *a=*a+1
≣ ++a[0] ≣ ++(a[0])
≣ ++0[a] // STAY AWAY
(*a)++ // Note that this does NOT return a pointer;
// Location `a` points to does not change
// (i.e. the address `a` is unchanged)
≡ val=*a,++*a,val
Notes/* Indirection/deference operator must pr̲e̲cede the target identifier: */
❌ a++*; ❌❌ a*++; ❌❌ ++a*; ❌
Because the pointer is being passed in by value only the local copy gets incremented. If you really want to increment the pointer you have to pass it in by reference like this:
void inc_value_and_ptr(int **ptr)
{
(**ptr)++;
(*ptr)++;
}