Pointer Expressions: *Ptr++, *++Ptr and ++*Ptr

Pointer expressions: *ptr++, *++ptr and ++*ptr

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):

  1. The precedence of the two operators, postfix ++ and indirection *
  2. The value of a postfix increment expression
  3. 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.

Pointer expressions: **ptr++, *++*ptr and ++**ptr use

Remember array name can easily decays into pointer to first element in most expressions (read some exceptions where array name not decaying into a pointer to first element? ably answered by @H2CO3).

For better understanding, consider my diagrams:

First, suppose a stored in memory as follows.

  a 
+----+----+----+----+---+
| 0 | 1 | 2 | 3 | 4 |
+----+----+----+----+---+
▲ ▲ ▲ ▲ ▲
| | | | |
a a+1 a+2 a+3 a+3

Declaration static int *p[] = {a, a+1, a+2, a+3, a+4}; creates a new array of pointers to integer, with following values:

p[0] == a
p[1] == a + 1
p[2] == a + 2
p[3] == a + 3
p[4] == a + 4

Now, p can also be assume to be stored in memory something like below:

  p
+----+----+----+----+-----+
| a |a +1| a+2| a+3| a+4 |
+----+----+----+----+-----+
▲ ▲ ▲ ▲ ▲
| | | | |
p p+1 p+2 p+3 p+4

After assignment ptr = p; things will be something like this:

  p                              a 
+----+----+----+----+-----+ +----+----+----+----+---+
| a |a +1| a+2| a+3| a+4 | | 0 | 1 | 2 | 3 | 4 |
+----+----+----+----+-----+ +----+----+----+----+---+
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
| | | | | | | | | |
p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+3
ptr


Notice: ptr points to first location in pointer array p[]

Expression: **ptr++;

Now we consider expression **ptr++; before first printf statement.

  1. ptr is equals to p that is address of first element in array of pointers.
    Hence, ptr point to first element p[0] in array (or we can say ptr == &p[0]).

  2. *ptr means p[0]
    and because p[0] is a, so *ptr is a ( so *ptr == a).

  3. And because *ptr is a, then **ptr is *a == *(a + 0) == a[0] that is 0.

  4. Note in expression **ptr++;, we do not assign its value to any lhs variable.

    So effect of **ptr++; is simply same as ptr++; == ptr = ptr + 1 = p + 1

    In this way after this expression ptr pointing to p[1] (or we can say ptr == &p[1]).

Print-1:

Before first printf things become:

  p                              a 
+----+----+----+----+-----+ +----+----+----+----+---+
| a | a+1| a+2| a+3| a+4 | | 0 | 1 | 2 | 3 | 4 |
+----+----+----+----+-----+ +----+----+----+----+---+
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
| | | | | | | | | |
p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+3
ptr


Notice: ptr is equals to p + 1 that means it points to p[1]

Now we can understand First printf:

  1. ptr - p output 1 because:

    ptr = p + 1, so ptr - p == p + 1 - p == 1

  2. *ptr - a output 1 because:

    ptr = p + 1, so *ptr == *(p + 1) == p[1] == a + 1

    This means: *ptr - a = a + 1 - a == 1

  3. **ptr output 1 because:

    *ptr == a + 1 from point-2

    So **ptr == *(a + 1) == a[1] == 1

Expression: *++*ptr;

After first printf we have an expression *++*ptr;.

As we know from above point-2 that *ptr == p[1].
So, ++*ptr (that is ++p[1]) will increments p[1] to a + 2

Again understand, in expression *++*ptr; we don't assign its value to any lhs variable so effect of *++*ptr; is just ++*ptr;.

Now, before second printf things become:

  p                              a 
+----+----+----+----+-----+ +----+----+----+----+---+
| a |a+2 | a+2| a+3| a+4 | | 0 | 1 | 2 | 3 | 4 |
+----+----+----+----+-----+ +----+----+----+----+---+
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
| | | | | | | | | |
p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+3
ptr


Notice: p[1] became a + 2

Print-2:

Now we can understand Second printf:

  1. ptr - p output 1 because:

    ptr = p + 1, so ptr - p == p + 1 - p == 1

  2. *ptr - a output 2 because:

    ptr = p + 1 so *ptr == *(p + 1) == p[1] == a + 2

    This means: *ptr - a == a + 2 - a == 2

  3. **ptr output 2 because:

    *ptr == a + 2 from point-2

    So **ptr == *(a + 2) == a[2] == 2

Expression: ++**ptr;

Now expression ++**ptr; before third printf.

As we know from above point-3 that **ptr == a[2].
So ++**ptr == ++a[2] will increments a[2] to 3

So before third printf things become:

  p                              a 
+----+----+----+----+-----+ +----+----+----+----+---+
| a | a+2| a+2| a+3| a+4 | | 0 | 1 | 3 | 3 | 4 |
+----+----+----+----+-----+ +----+----+----+----+---+
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
| | | | | | | | | |
p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+3
ptr


Notice: a[2] = 3

Print-3:

Now we can understand Third printf:

  1. ptr - p output 1 because:

    ptr = p + 1 so ptr - p == p + 1 - p == 1

  2. *ptr - a output 2 because:

    ptr = p + 1 so *ptr == *(p + 1) == p[1] == a + 2

    This means: *ptr - a = a + 2 - a == 2

  3. **ptr outputs 3 because:

    *ptr == a + 2 from point-2

    So **ptr == *(a + 2) == a[2] == 3

Edit Note: The difference of two pointers has type ptrdiff_t, and for that, the correct conversion specifier is %td, not %d.

An additional point:

I wish to add as I believe it will be helpful for new learners

Suppose we have following two lines with one more 4th printf in you code before return 0;

**++ptr;    // additional 
printf("%d %d %d\n", ptr-p, *ptr-a, **ptr); // fourth printf

One can check this working code @Codepade , this line outputs 2 2 3.

Expression: **++ptr;

Because ptr is equals to p + 1 , after increment ++ operation ptr becomes p + 2 (or we can say ptr == &p[2]).

After that double deference operation ** ==> **(p + 2) == *p[2] == *(a + 2) == a[2] == 3.

Now, again because we don't have any assignment operation in this statement so effect of expression **++ptr; is just ++ptr;.

So thing after expression **++ptr; becomes as below in figure:

  p                              a 
+----+----+----+----+-----+ +----+----+----+----+---+
| a | a+2| a+2| a+3| a+4 | | 0 | 1 | 3 | 3 | 4 |
+----+----+----+----+-----+ +----+----+----+----+---+
▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲ ▲
| | | | | | | | | |
p p+1 p+2 p+3 p+4 a a+1 a+2 a+3 a+3
ptr

Notice: ptr is equals to p + 2 that means it points to p[2]

Print-4:

Considering Forth printf I added in question:

  1. ptr - p output 2 because:

    ptr = p + 2 so ptr - p == p + 2 - p == 2

  2. *ptr - a output 2 because:

    ptr = p + 2 so *ptr == *(p + 2) == p[2] == a + 2

    This means: *ptr - a = a + 2 - a == 2

  3. **ptr outputs 3 because:

    *ptr == a + 2 from above point-2

    So **ptr == *(a + 2) == a[2] == 3

Incrementing pointer (ptr++) and (*ptr++)

The first snippet is obvious: it prints what ptr points to, i.e. 10.

The second one, moves the pointer forward of one element, which then points to the next element, i.e. 20.

The third snippet is exactly the same as the previous one, because its first instruction increments the pointer and returns the unincremented value, which is dereferenced, but its result is discarded; what is dereferenced in the printf is the incremented pointer, which now points to 30.

The last snippet is different: ++*ptr is ++(*ptr); *ptr dereferences ptr (which already points to 30), yielding 30, and ++ increments such value, which becomes 31.

Pointer Arithmetic: ++*ptr or *ptr++?

These statements produce different results because of the way in which the operators bind. In particular, the prefix ++ operator has the same precedence as *, and they associate right-to-left. Thus

++*ptr

is parsed as

++(*ptr)

meaning "increment the value pointed at by ptr,". On the other hand, the postfix ++ operator has higher precedence than the dereferrence operator *. Thefore

*ptr++

means

*(ptr++)

which means "increment ptr to go to the element after the one it points at, then dereference its old value" (since postfix ++ hands back the value the pointer used to have).

In the context you described, you probably want to write ++*ptr, which would increment x indirectly through ptr. Writing *ptr++ would be dangerous because it would march ptr forward past x, and since x isn't part of an array the pointer would be dangling somewhere in memory (perhaps on top of itself!)

Hope this helps!

What's difference between ptr=&n and ptr = (int*)malloc(4)for my code?

With ptr=&n; you take the address of an existing variable.

You would be able to access the variable directly and you can access it via the pointer.

With ptr = (int*)malloc(4); you take the address of a newly allocated pice of memory. Assuming that sizeof(int)==4 in your environment here.
You can only access it via the pointer.

In both cases your loop, from the second interation (when >0) accesses memory you are not allowed to access.

If you observe a difference, e.g. that the code seems to work with the second version, but not with the first, then the explanation is that you got lucky, or unlucky, depending on your philosophy on how and when you want to notice errors.

C Pointers: *ptr vs &ptr vs ptr

Take the following variables in a function.

int i = 0;
int* ptr = &i;

In the function, the memory layout could look something like:

Memory corresponding to i:

+---+---+---+---+
| 0 |
+---+---+---+---+
^
|
Address of i

Memory corresponding to ptr:

+---+---+---+---+
| address of i |
+---+---+---+---+
^
|
Address of ptr

In the above scenario,

*ptr == i == 0
ptr == address of i == address of memory location where the vale of i is stored
&ptr == address of ptr == address of memory location where the value of ptr is stored.

Hope that makes sense.

PTR DWORD in nim lang

ProcessIdToSessionId needs a pointer to the variable to write to, but you're passing the value of the variable itself as a pointer, that's why it fails.

Correct code would be like this (untested):

import winim

let CurrentProcessID = GetCurrentProcessId()
var SessionID: DWORD
let result1 = ProcessIdToSessionId(CurrentProcessID, addr SessionID)
echo SessionID

How would ++*ptr++ be evaluated by compiler if ptr is ptr to first element of a static array?

The postfix increment a++ increments the pointer ptr, but returns the copy of ptr before the operation (see difference between prefix/postfix).
So it can be rewritten (as noted in Quimby's answer) as ++(*(ptr++)) and goes like:

  1. ptr++ : increments ptr so that it points to 99, but returns another pointer that still points to 9
  2. *ptr++ : dereferences, evaluates to 9
  3. ++*ptr++ : increments the value pointed to by the copied pointer, meaning increments 9 and returns 10

Here the logic behind pre/post increment/decrement is explained well:

Pre-increment and pre-decrement operators increments or decrements the value of the object and returns a reference to the result.
Post-increment and post-decrement creates a copy of the object, increments or decrements the value of the object and returns the copy from before the increment or decrement.

From: https://en.cppreference.com/w/cpp/language/operator_incdec



Related Topics



Leave a reply



Submit