C Pointers from a previous article

I have one more question with C pointers.

Consider running the following program:

int x[5] = {0,3,5,7,9}; int* y = &x[2]; *(y+2) = *(y--); 

What values ​​does the x array hold after that?

What the hell is going on with y-- ? I know how *(y+2) works, and I understand the rest, but not how y-- communicates with the rest.

In addition, the answer will be {0, 3, 5, 5, 9} .

+5
source share
4 answers

You should not trust the answers given by your professor in this case.

Expand on Wintermute answer a little ...

The problem is approval

 *(y+2) = *(y--); 

The expression y-- evaluates the current value of y , and the variable decreases as a side effect. For instance:

 int a = 10; int b; b = a--; 

After the output expression is evaluated, b will have the value 10 and a will have the value 9.

However, the C language does not require that a side effect be applied immediately after evaluating the expression, only that it is applied until the next point in the sequence (which in this case is at the end of the instruction). It is also not required that expressions be evaluated from left to right (with some exceptions). Thus, it does not guarantee that the y value in y+2 represents the y value before or after the decrease operation.

The C language standard explicitly invokes operations such as undefined behavior, which means that the compiler is free to handle the situation in whatever way he wants. The result will depend on the compiler, compiler settings, and even the surrounding code, and any answer will be equally correct regarding the definition of the language.

To make this well-defined and give the same result, you will need to reduce y to an assignment operator:

 y--; *(y+2) = *y; 

This is constantly one of the most misunderstood and misunderstood aspects of C. If your professor expects this particular result to be clearly defined, then he does not know the language as well as he thinks. Again, it is not unique in this regard.

By repeating and expanding on a snippet from the draft C 2011 standard that Wintermute published:

6.5 Expressions
...
2 If the side effect of a scalar object is independent of another side effect on the same scalar object or calculating a value using the value of the same scalar object, the behavior is undefined . If there are several valid orders of expression subexpression, the behavior is undefined, if such an inconsistent side of the effect occurs in any of the orders. 84)

3 The grouping of operators and operands is indicated by the syntax. 85) Except as noted, later side effects and calculation of sub-expression values ​​are irrelevant . 86)
84) This paragraph displays undefined expression expressions such as
  i = ++i + 1; a[i++] = i; 
letting
  i = i + 1; a[i] = i; 

85) The syntax determines the priority of operators in evaluating an expression that is the same as the order of the main subparagraphs of this subparagraph, the highest priority in the first place. So, for example, expressions allowed as operands of the binary operator + (6.5.6) are expressions defined in 6.5.1 - 6.5.6. Exceptions are expressed expressions (6.5.4) as operands of unary operators (6.5.3) and an operand contained between any of the following pairs of operators: grouping parentheses () (6.5.1), parentheses for signing [] (6.5.2.1 ), parentheses of functions () (6.5.2.2) and conditional operator ? : ? : (6.5.15). Within each main subsection, operators have the same priority. The left or right associativity specified in each subclause is the syntax of the expressions discussed in it.

86). In an expression that is evaluated more than once during the execution of a program, indefinitely ordered estimates of its subexpressions should not be consistently performed in different evaluations.

Accent added. Note that this was true after the C89 standard, although this wording has changed a bit since then.

"Inconsistent" simply means that it does not guarantee that one operation will be completed before another. The assignment operator does not enter a sequence point, so it does not guarantee that the LHS expression is evaluated before the RHS.

Now for the hard bit - your professor clearly expects a certain behavior for these expressions. If he gives a test or quiz that asks what will be the result of something like a[i] = i--; , he probably won’t accept the answer “undefined behavior”, at least not by itself. You might want to discuss the Wintermute answers I gave with him, as well as the sections of the standard above.

+10
source

There is no sequence point between y-- and y + 2 in *(y+2) = *(y--); therefore, does not y + 2 refer to &x[4] or &x[3] . Depending on how your compiler does something, you may get 0 3 5 5 9 or 0 3 5 7 5 .

Which means the absence of a sequence point between the two expressions, in a nutshell, which does not indicate whether the side effects of one operation ( --y in this case) were applied at the time when the other ( y - 2 ). You can learn more about sequence points here .

ISO / IEC 9899: 201x

6.5 Expressions

p2: If the side effect of a scalar object is independent of another side effect on the same scalar object or calculating a value using the value of the same scalar object, the behavior is undefined. If there are several valid orders of expression subexpression, the behavior is undefined, if such an inconsistent side of the effect occurs in any of the orderings.

+14
source

The problem is this statement.

 *(y+2) = *(y--); 

Since in C, reading a variable twice in an expression (in which it was changed) has undefined behavior.

Another example:

 i = 5; v[i] = i++; 

In this case, it is most likely (AFAIK) that the compiler will evaluate RHS or LHS first, if LHS is first evaluated, then we will have v[5] = 5; and after assignment i is equal to 6, if instead RHS is evaluated first, then we will have that the estimate of the right side will be 5, but when we start to evaluate the left side i , it will be 6, so we end with v[6] = 5; however, given the quote “undefined behavior allows the compiler to do whatever it chooses, even to make demons fly out of your nose”, you should not expect one of these options, instead you should expect nothing because it depends on the compiler. what's happening.

0
source

First of all, int x[5] = {0, 3, 5, 7, 9} means

 x[0] = 0, x[1] = 3, x[2] = 5, x[3] = 7, x[4] = 9 

Next int *y = &x[2] Here you are trying to use the y pointer to specify the address x[2]

Now your confusion has come *(y + 2) means that you specify the address x[4] and *(y--) , here y-- is a decrement operator, so first of all you need to use the value *y , which is equal to x[2] = 5 , so now the assigned value x[4] = 5 .

The end result will be 0 3 5 7 5

0
source

Source: https://habr.com/ru/post/1209455/


All Articles