The Average That Came Out Wrong
At a school in Mysuru, a student is asked to write a C program that averages four integer test scores stored in an int array: 17, 23, 9 and 30. The student declares int sum, i; and float avg; adds the scores, then writes avg = sum / 4; and prints the result with printf("%f", avg). The output is 19.000000, but the expected average is 19.75. The teacher also notices two lines the student added while "optimising": int x = 7, y = 2; printf("%d", x / y * y); which prints 6, and i = i++ + ++i; which gives different results under different compilers. The student cannot see why any of these three results is wrong, because each line looks mathematically acceptable. The teacher wants the errors explained using the concepts of integer division, operator precedence and associativity, and sequence points.
1. Explain exactly why avg prints 19.000000 instead of 19.75, and rewrite the assignment so it is correct.
Read the worked answer
sum and 4 are both int, so sum / 4 performs integer division: 79 / 4 is 19, and the fractional part 0.75 is discarded before any conversion to float happens. The resulting int 19 is then converted to float for assignment, giving 19.000000.
Casting the whole quotient, (float)(sum / 4), does not help because the division has already been done in integer arithmetic. Correct forms are:
avg = (float)sum / 4; /* cast one operand */
avg = sum / 4.0f; /* make the constant floating */
In both, one operand is floating, so the other is promoted and the division is real division. The same reasoning explains why x / y * y with 7 and 2 gives 6, not 7.
2. Evaluate x / y * y for x = 7 and y = 2, and explain the role of associativity. Then state what printf("%d", 7 + 2 * 3 % 4) prints and why.
Read the worked answer
*, / and % share the same precedence level and associate left to right. In x / y * y, the division is done first: 7 / 2 = 3 in integer arithmetic, then 3 * 2 = 6. Multiplying back does not recover 7 because the remainder was already thrown away.
In 7 + 2 * 3 % 4, the multiplicative operators are evaluated left to right before +: 2 * 3 gives 6, then 6 % 4 gives 2, and finally 7 + 2 gives 9. So the output is 9.
Precedence decides which operators bind first; associativity decides the order among operators of equal precedence. Neither rule fixes the integer-division loss, which is a type issue, not a precedence issue.
3. Why is i = i++ + ++i unreliable? State the rule the student has broken and give a safe rewrite.
Read the worked answer
Between two sequence points, i is modified more than once (i++ and ++i) and is also read for the addition. The C standard says that if an object is modified more than once between sequence points, or is modified and also read other than to compute the stored value, the behaviour is undefined. That is stronger than "unspecified": the program may print any value, crash, or appear to work, and different compilers or optimisation levels can give different results.
There is no "correct" value to compute from that expression. A safe rewrite separates the modifications:
i = i + 1; /* or simply i++; */
If the intent was to add two successive values, store them first, for example int a = i; i = i + 1; int b = i; and then add a + b. The habit to learn is: do not both modify and read the same variable in one expression between sequence points.