2

If I run the following code, graph[0][0] gets 1 while graph[0][1] gets 4.

In other words, the line graph[0][++graph[0][0]] = 4; puts 1 into graph[0][0] and 4 into graph[0][1].

I would really appreciate if anyone can offer reasonable explanation.

I observed this from Visual C++ 2015 as well as an Android C compiler (CppDriod).

static int graph[10][10];
void main(void)
{
    graph[0][++graph[0][0]] = 4;
}
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261

5 Answers5

5

Let's break it down:

++graph[0][0]

This pre-increments the value at graph[0][0], which means that now graph[0][0] = 1, and then the value of the expression is 1 (because that is the final value of graph[0][0]).

Then,

graph[0][/*previous expression = 1*/] = 4;

So basically, graph[0][1] = 4;

That's it! Now graph[0][0] = 1 and graph[0][1] = 4.

Jashaszun
  • 9,207
  • 3
  • 29
  • 57
  • @AnT Could you explain that? What do you mean by `imposing an ordering where no ordering exists`? This isn't undefined behavior. – Jashaszun Jul 27 '15 at 18:29
  • @Jashaszun: No, this isn't undefined behavior. But your claim that "now `graph[0][0] = 1`" is misleading. Evaluation of `++graph[0][0]` in the context of the original expression is not required to *modify* `graph[0][0]` immediately. All this `++` does is produce the value `1` and send it up the evaluation chain, but you cannot claim that "now `graph[0][0] = 1`". It is quite possible that `graph[0][0]` remains `0` for a while. It will become `1` much later (before the end of the full statement). C language gives you no guarantees as to when exactly it will happen. – AnT stands with Russia Jul 27 '15 at 18:59
  • Side-effects in this expression are not sequenced. No one knows when exactly they happen. All one can claim is that `1` will get into `graph[0][0]` and `4` will get into `graph[0][1]` sometime before the end of the full statement. Misguided belief that `++` modifies its operand *immediately* is exactly the reason that spawns confused questions of this nature here on SO and everywhere. – AnT stands with Russia Jul 27 '15 at 19:01
2

First let's see what is the unary (prefix) increment operator does.

The value of the operand of the prefix ++ operator is incremented. The result is the new value of the operand after incrementation.

So, in case of

graph[0][++graph[0][0]] = 4;

first, the value of graph[0][0] is incremented by 1, and then the value is used in indexing.

Now, graph being a static global variable, due to implicit initialization, all the members in the array are initialized to 0 by default. So, ++graph[0][0] increments the value of graph[0][0] to 1 and returns the value of 1.

Then, the simpllified version of the instrucion looks like

graph[0][1] = 4;

Thus, you get

  • graph[0][0] as 1
  • graph[0][1] as 4.

Also, FWIW, the recommended signature of main() is int main(void).

Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
  • That's wrong. Where did that "first" in "... first, the value of `graph[0][0]` is incremented by 1..." come from? There' no sequencing in this expression, for which reason nobody can say when the value of `graph[0][0]` gets incremented. – AnT stands with Russia Jul 27 '15 at 18:36
  • @AnT sir, is not it like the array subscript operation will take higher priority? I mean, the expression in the array subscript will be evaluated first. Please correct me if i'm wrong. – Sourav Ghosh Jul 27 '15 at 18:40
  • Yes, you are right: the expression in the array subscript will be evaluated first. And it will produce `1` as it result. But that has nothing to do with actually writing that `1` back into `graph[0][0]`. The modification of `graph[0][0]` is not a part of "evaluation of expression in the array subscript". It is a side-effect. That side-effect is allowed to materialize much later. – AnT stands with Russia Jul 27 '15 at 18:46
  • Operator *priority* has nothing to do with order of evaluation and has nothing to do with materialization of side-effects. – AnT stands with Russia Jul 27 '15 at 19:05
1

You are adding one to graph[0][0], by doing ++graph[0][0]. And then setting graph[0][1] to 4. Maybe you want to do graph[0][graph[0][0]+1] = 4

David Ranieri
  • 39,972
  • 7
  • 52
  • 94
mart
  • 41
  • 3
1

At first your variable graph[10][10] is static so it will be initialized with value 0.

Then line graph[0][++graph[0][0]] = 4 ; here graph[0][0] = 0 in expression you just incrementing the value of graph[0][0] so basically you assigning graph[0][1] = 4; yourself

Note that you have used pre-increment operator (++x) so it first get incremented and value is changed but if you would have use post-increment operator(x++) then graph[0][0] = 4; itself

Bhavesh Kumar
  • 116
  • 1
  • 9
0

Let's line up the facts about this expression

graph[0][++graph[0][0]] = 4;
  • Per 6.5.1, the computation of the array index ++graph[0][0] is sequenced before the computation of array element graph[0][++graph[0][0]], which in turn is sequenced before the computation of the entire assignment operator.

  • The value of ++graph[0][0] is required to be 1. Note that this does not mean that the whole pre-increment together with its side-effects has to "happen first". It simply means that the result of that pre-increment (which is 1) has to be computed first. The actual modification of graph[0][0] (i.e. changing of graph[0][0] from 0 to 1) might happen much much later. Nobody knows when it will happen exactly (sometime before the end of the statement).

  • This means that the element being modified by the assignment operator is graph[0][1]. This is where that 4 should go to. Assignment of 4 to graph[0][1] is also a side-effect of = operator, which will happen sometime before the end of the statement.

Note, that in this case we could conclusively establish that ++ modifies graph[0][0], while = modifies graph[0][1]. We have two unsequenced side-effects (which is dangerous), but they act on two different objects (which makes them safe). This is exactly what saves us from undefined behavior in this case.

However, this is dependent on the initial value of graph array. If you try this

graph[0][0] = -1;
graph[0][++graph[0][0]] = 4;

the behavior will immediately become undefined, even though the expression itself looks the same. In this case the side-effect of ++ and the side-effect of = are applied to the same array element graph[0][0]. The side-effects are not sequenced with relation to each other, which means that the behavior is undefined.

AnT stands with Russia
  • 312,472
  • 42
  • 525
  • 765