+2  A: 
*it++ = tolower(*it); 
*p++ = tolower(*p);

Both of these lines invoke undefined behaviour. You cannot modify the value of a variable more than once in a single statement (++ modifies once, operator = modifies twice).

So the fact that you get different values is unsurprising.

Dean Harding
`operator++` and `operator=` applied here to two different variables in each case. There's no UB.
Kirill V. Lyadvinsky
@Kirill V. Lyadvinsky: There is undefined behaviour for both the pointer and iterator case as there is a possible sequencing of the operations were there is no intervening sequence point between the read of the value of `it` (or `p`) for the `*` operator on the RHS of the assignment and the increment operation on the LHS of the assignment.
Charles Bailey
Whatever the case, the lines are certainly confusing and I wouldn't want to see it written like that anyway :-)
Dean Harding
@Charles Bailey, changing the same variable twice in between two sequence points is UB. Here is only one change. I think the problem is that the order of compute arguments of the function `operator=` is unspecified.
Kirill V. Lyadvinsky
@Kirill V. Lyadvinsky: Reading (except to determine the value to be written) and writing the same variable without an intervening sequence point also causes UB.
Charles Bailey
@Kirill V. Lyadvinsky: For clarity, I am, of course, talking about the write to `it` implied by the `++` not the write implied by the assignment which isn't directly to `it`.
Charles Bailey
For the `char*` case, we have undefined behavior due to `*` being applied twice in combination with `++`; for the `std::string::iterator` case, we might merely have *unspecified* evaluation order of those same operators. If the iterator type is a user-defined type and not merely an alias for `char*`, then the overloaded operators are functions and thus there are more sequence points. But even though it's defined, it still might not yield the desired results.
Rob Kennedy
@Rob Kennedy: Even in the iterator case where there are more sequence points, there are valid orderings of sub-exressions where `it++` and `*it` are not separated by a sequence point and 5 / para 8 says that this means that you have UB.
Charles Bailey
+2  A: 

The grammar works exactly the same for pointers and iterators. The operations implied by operators are turned into function calls for objects of class type (such as most iterators).

The issue with your code isn't with operator precedence though, in both of these lines there is no sequencing between the increment operation and the second read of the same variable that is incremented elsewhere in the statement. Because of this, you have undefined behaviour so he might see any behaviour from your program including the results that you are seeing.

*p++ = tolower(*p);

*it++ = tolower(*it);

You need to reformulate this statement in a way in which the sequencing is defined. I'm guessing that you want something like this.

char c = tolower(*p);
*p++ = c;
Charles Bailey
+1: your addon works, but i've vague undestanding why
oraz
Rationale for downvote, anyone?
Charles Bailey
+1 for good suggestion. May be it's wrong suggestion in the end, but it's helpful. Consider to add links to the Standard.
Kirill V. Lyadvinsky
@oraz: In C++ there fewer restrictions than some languages in how an implementation breaks down an evaluates the sub-expressions of any given expressions. If the result of the expression depends on the order in which the sub-expressions are performed then it is often the case that you have not guarantees on what will actually happen. The solution (for the programmer) is to break down complex expressions into smaller expression which exactly express your intent.
Charles Bailey
+8  A: 

The problem is that the order of evaluation of arguments of operator= is unspecified. This is according to C++ Standard 5.2.2/8. Consider the following:

*it++ = tolower(*it);

is equal to

operator=( *it++, tolower(*it) );

Now *it++ could be computed before tolower(*it) and vice versa.

Kirill V. Lyadvinsky
It's worse than unspecified behavior, there is undefined behavior in the original expression. There is a possible ordering of subexpressions where `it++` is evaluated (i.e. a write to `it`) before `it` is read in the parameter evaluation for `tolower` with no intervening sequence point. This can happen whether or not the assignment operator is a function call or not. Either way 5 [expr], para 8 confirms that this is undefined behaviour.
Charles Bailey