-1

I am a CS student preparing for a test in Introduction to CS in C language. I am solving some tests from the past and in one of them there was this question:

Look at the code below and state if there any errors. If so, correct them. Also if the program have any input write it down.

The code that came with the question is this:

#include <stdio.h>
#ifdef SIZE
#define MAX_SIZE (2*(SIZE))
#endif
int main() {
  int i;
  int arr[MAX_SIZE + 1];
  for (i = 0; i < sizeof(arr)/sizeof(int);) {
    arr[i] = i++;
    printf("%d ", arr[i-1]);
  }
  return 0;
}  

So of course I noticed that it wouldn't compile because the preprocessor would just skip the define part and MAX_SIZE would be undeclared variable. Beside that there shouldn't be any other compiling errors, I did notice the arr[i] = i++ but that should work even if a bit unpredictably (in the test I will call it an error though), so to test my answer I copied it to my IDE and fixed it to my best of knowledge. (I picked 5 randomly)

#include <stdio.h>
#define SIZE 5

#ifdef SIZE
#define MAX_SIZE (2*(SIZE))
#endif

int main()
{
  int i;
  int arr[MAX_SIZE + 1];
  for (i = 0; i < sizeof(arr)/sizeof(int);)
  {
    arr[i] = i++;
    printf("%d ", arr[i-1]);
  }
  return 0;
}

to my surprise the function went into an endless loop printing 8 all the time.

After some digging I figured out that for some reason when i is equal to 10 it stops increasing. Some more digging made me realize that it's only happening when SIZE is an odd number and it won't happen if the ++ is prefix (as in ++i). If the changes mentioned above are applied, the output is as I expected, except that arr[0] doesn't get assigned.

All of that made me conclude that it is a compiler optimization error of some kind, bit I really would like it if someone could explain to me what is really happening here.

wovano
  • 4,543
  • 5
  • 22
  • 49
  • Note that this has nothing to do with either your defines or `sizeof`. You'll get the same behavior even if you change them to hard coded values. – klutt Feb 08 '20 at 13:42
  • 3
    Both your code and the 'original' have undefined behaviour in this line: `a[i] = i++;`. See [Undefined behavior and sequence points](https://stackoverflow.com/questions/4176328/undefined-behavior-and-sequence-points/4176333#4176333) for further discussion. – Adrian Mole Feb 08 '20 at 13:43
  • _"to my surprise the function went into an endless loop printing 8 all the time"_ Not in this case https://repl.it/repls/CarpalParallelSpyware – Alejandro Feb 08 '20 at 14:02

2 Answers2

4

Using the value of a variable while also applying a side effect to it in the same statement is undefined behavior.

Therefore this:

arr[i] = i++;

Is an error, and invokes undefined behavior, meaning that the compiler is allowed to do anything. In your case, this happens to cause an endless loop. Using ++i instead of i++ is also an error invoking undefined behavior. The fact that it "seems to work" is just a coincidence.

In general, in order to be able to use the same variable more than once in the same statement, no side effect can be performed in that statement that alters the value of the variable.

From the C11 standard paragraph 6.5 point 2 (page 76):

If a side effect on a scalar object is unsequenced relative to either a different side effect on the same scalar object or a value computation using the value of the same scalar object, the behavior is undefined. If there are multiple allowable orderings of the subexpressions of an expression, the behavior is undefined if such an unsequenced side effect occurs in any of the orderings.

[...]

This paragraph renders undefined statement expressions such as

i = ++i + 1;
a[i++] = i;

while allowing

i = i + 1;
a[i] = i;
Community
  • 1
  • 1
Marco Bonelli
  • 63,369
  • 21
  • 118
  • 128
3

The problem is at this line:

arr[i] = i++;

This invokes undefined behavior. Change it to

arr[i] = i;
i++;

and it will work the way you want.

Let's take this code:

i=0;
arr[i] = i++;

According to how ++ works, it's reasonable that some array element gets the value 0. However, is it a[0] or a[1] that gets the value 0? i++ will return 0, but after it's done i will have the value 1. This is one of the many cases where C has undefined behavior, which basically means that anything might happen. The standard allows the compiler to produce whatever it wants.

klutt
  • 30,332
  • 17
  • 55
  • 95