4

Given the code below

char buf[] = "asfsf";

char *a=buf;
++*a++;
cout<<*a;

I expect the result is the next character of 's' that is 't', but the result is still 's'. Why?

Why ++*a++ is not the same as

*a++;
++*a;
cout<<*a;

Is that really a duplicate question with ++i++? I know ++i++ is a undefined behavior and will cause compile error, but ++*i++ actually can run. Is my case also a undefined behavior?

tripleee
  • 175,061
  • 34
  • 275
  • 318
SimaGuanxing
  • 673
  • 2
  • 10
  • 29
  • You should use `const char *a="asfsf";` – Neil Kirk Apr 13 '15 at 22:21
  • @NeilKirk i don't think it solves the problem. – SimaGuanxing Apr 13 '15 at 22:27
  • I'm trying to conceive a way a compliant C++ compiler could indeed compile this at all. Perhaps include your toolchain in your question. The memory for the string is read-only. I'm surprised this doesn't fault. – WhozCraig Apr 13 '15 at 22:28
  • 1
    This is *not* a dupe (at least of the nominated duplicate). This one includes a dereference, which means the two increments are applied to *different objects* (i.e., one applies to `a`, the other applies to `*a`). That makes it subtly (but completely) different from applying two increments to the same object. – Jerry Coffin Apr 13 '15 at 22:31
  • 1
    Your code should just be avoided, even if it's well-defined behaviour (which is not). It faults on my system (OS X) with `Bus error: 10` (and also a warning of deprecated conversion from string constant to `char*`) – vsoftco Apr 13 '15 at 22:33
  • Thanks @vsoftco The reason why I want to do this is because I want to simplify the two lines code to one line and I think there maybe some ways to realize it. – SimaGuanxing Apr 13 '15 at 22:36
  • 2
    @vsoftco it faults because he's writing to read-only memory (the string literal). A [little modification](http://ideone.com/QFj4ky) will likely give what he's seeing without the ro-overreach.. – WhozCraig Apr 13 '15 at 22:36
  • 2
    @WhozCraig agree, still the maximum I'd use is something like `*a++`. More than one 2 `++/*` operators just create confusion for people who read your code. – vsoftco Apr 13 '15 at 22:49

2 Answers2

3

According to the language grammar, the operators associate as:

++(*a++)

Note: associativity does not imply an order of operations.

*a++ evaluates to an lvalue designating the location where a was originally pointing, with side-effect of modifying a. All fine so far.

Applying prefix-++ to that lvalue increments the value stored there (changing 'a' to 'b').

Although the two increments are unsequenced, this does not cause UB because different objects are being incremented, and the lvalue designating the latter location does not depend on the increment. (It uses the old value of a).

M.M
  • 138,810
  • 21
  • 208
  • 365
  • @bogdan thanks for pointing that out. The options are `++ cast-expression` and `postfix-expression ++` . But the former does not yield a `postfix-expression` whereas the latter does yield a `cast-expression`. – M.M Apr 14 '15 at 00:03
2

As it stands right now, your code has undefined behavior, because it attempts to modify the contents of a string literal.

One way (probably the preferred way) to prevent the compiler from accepting such code is to define your a like:

char const *a="asfsf";

This way, the ++*a part simply won't compile.

For the sake of exposition, let's change the code a little bit, to become:

#include <iostream>

int main(){ 

    char x[]="asfsf";
    char *a = x;
    ++*a++;
    std::cout<<x;
}

Now a points at memory we can actually write to, and get meaningful results. This prints out bsfsf. If we print out a, we'll get sfsf.

What's happening is that a++ increments a, but still yields the original value of a. That is dereferenced, giving a reference to the first element of x. Then the pre-increment is applied to that, changing it from a to b.

If you want to increment the pointer, dereference the result, then increment that, you'd use: ++*++a;. Well, no, you wouldn't use that--or at least I hope you wouldn't. It does increment a to point at the second element of the array, then increment that second element to change it from s to t--but anybody who read the code would be completely forgiven if they hated you for writing it that way.

Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • Can you please elaborate on why does "`a++` increments `a` but still yields the original value of `a`"?? – Martund Feb 12 '20 at 16:17
  • @Martund: That's simply what post-increment is defined to do. For example, if I do something like : int i=0; printf("%d ", i++); printf("%d", i);`, it should print out `0 1`. So the `i++` has yielded the existing value of `i` (which is 0) but incremented `i`, so the next time we look at it, its value is 1. – Jerry Coffin Feb 12 '20 at 17:54