Yuu
Yuu

Reputation: 39

How is pointer ++*ptr++ evaluated

So I'm quite confused as to how the post-increment is not evaluated first. (According to precedence post-increment comes first.) Can someone please explain this?

Consider the code given below:

int main()
{
    char arr[] = "iitbforgoodlife";
    char *ptr = arr;
    
    while(*ptr != '\0')
        ++*ptr++;
    
    printf("%s %s", arr, ptr);
    
    getchar();
    return 0;
}

The output is: jjucgpshppemjgf

Upvotes: 1

Views: 227

Answers (5)

Luis Colorado
Luis Colorado

Reputation: 12708

Monadic operators are always executed from right to left (first right operators, then left ones), and fron the inside to the outside. So first an increment of the pointer is scheduled to be done at the end, but the actual value is used to dereference the pointer, and then the value of the pointed out item is incremented. The final value is the result of the increment of the pointed value, and the pointer is itself incremented after the statement is executed.

The overal result is to increment each character in the string to the next character value, resulting in something like

"jjucgpshppemjgf"

but as ptr will end pointing to the final '\0' in the string, the result will be to print the string above (without the quotes) and a space, and nothing else (the pointer ptr is left pointing to the final null in the string). No line end is printed, so the prompt will appear to the right of the space.

Upvotes: 0

jxh
jxh

Reputation: 70492

    ++*ptr++;
//  | |   |
//  | |   ` post-increment
//  | ` dereference
//  ` pre-increment

The post-increment, being a primary expression operator, has highest precedence. The result of the operator is the original value (the increment may happen any time before the end of the sequence point).

Next is the unary operator * which dereferences the pointer to return the underlying object, which is a character from the array arr.

Finally, the pre-increment operator, also a unary operator, which has the same precedence as *. However, it is applied later because operators of the same precedence are associated in some precedence specific order. For unary operators, they are associated right-to-left. Therefore, the pre-increment is applied to the object resulting from the * operator.

So, if you wanted expanded pseudo code to explain it:

optr = ptr;
val = *optr;
nval = val + 1;
*optr = nval;
ptr = ptr + 1;

Where the last assignment could happen at any point after the first assignment.

Upvotes: 0

Vlad from Moscow
Vlad from Moscow

Reputation: 311088

Consider this expression:

++*ptr++

This expression uses one postfix operator (postfix increment) and two unary operators (unary indirection operator and unary increment operator).

Postfix operators have a higher precedence than unary operators.

Unary operators are evaluated from right to left.

So you have the following sequence of operations.

  1. From the C Standard (6.5.2.4 Postfix increment and decrement operators)

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). See the discussions of additive operators and compound assignment for information on constraints, types, and conversions and the effects of operations on pointers. The value computation of the result is sequenced before the side effect of updating the stored value of the operand. With respect to an indeterminately-sequenced function call, the operation of postfix++ is a single evaluation. Postfix ++ on an object with atomic type is a read-modify-write operation with memory_order_seq_cst memory order semantics.

So the value of the sub-expression ptr++ is the value of the pointer before its increment.

  1. (the C Standard, 6.5.3.3 Unary arithmetic operators)

4 The unary * operator denotes indirection. If the operand points to a function, the result is a function designator; if it points to an object, the result is an lvalue designating the object. If the operand has type "pointer to type", the result has type "type". If an invalid value has been assigned to the pointer, the behavior of the unary * operator is undefined.

  1. And at last the lvalue supplied by the indirection operator is incremented using the unary increment operator (the C Standard, 6.5.3.1 Prefix increment and decrement operators)

2 The value of the operand of the prefix++ operator is incremented. The result is the new value of the operand after incrementation. The expression++E is equivalent to (E+=1). See the discussions of additive operators and compound assignment for information on constraints, types, side effects, and conversions and the effects of operations on pointers.

So due to operation precedence this expression statement

++*ptr++;

may be equivalently rewritten using parentheses like

++( *( ptr++ ) ); 

For example when initially the pointer ptr points to the first character of the array arr

char arr[] = "iitbforgoodlife";
char *ptr = arr;

when in the first iteration of the while loop after this statement

++*ptr++;

the first character of the array will be increnented and becomes equal to 'j' and the pointer ptr itself will point to the second character of the array.

Pay attention to that the array arr initialized by the string literal

char arr[] = "iitbforgoodlife";

includes the terminating zero character '\0' of the string literal and when the terminating zero character is encountered in the array the while loop stops its iteration:

while(*ptr != '\0')
   

Upvotes: 0

giusti
giusti

Reputation: 3538

Operator precedence is only about what operators bind to their operands first, not about the order in which the operations are carried out or when the variables are actually modified.

When you write

++*ptr++;

it is indeed equivalent to

++*(ptr++);

However this does not mean that ptr has to be incremented before the rest of the expression is evaluated. In fact, *(ptr++) must derrefence the current value of the pointer. Because the semantic of the post-increment operator is that ptr++ yields the value of ptr and increments ptr (it doesn't specify when the increment happens).

In other words, the compiler may chose to increment *ptr and then the pointer or it may first increment the pointer and then use its previous value to increment the pointed object.

The best thing is not to rely on that knowledge. Always prefer to write simpler code:

while(*ptr != 0) {
    ++*ptr;
    ptr++;
}

My personal rule of thumb is that you should avoid using ++ with any other operator as much as possible. In particular, if you have two instances of ++ in an expression, it is very likely wrong or poorly written.

Upvotes: 4

4386427
4386427

Reputation: 44339

The horrible expression ++*ptr++; will increment whatever ptr points to and leave ptr incremented as well. Consequently each array element will be incremented by one.

It's evaluated like:

++(*(ptr++));

Consider it like:

char* temp = ptr;
*temp = *temp + 1;
ptr = temp + 1;

Upvotes: 0

Related Questions