0

I'm new to C and I'm writting some simple stuff to get familiar. I just tried pre-increment on an array index and what I got was really not what I was expecting.

The code in question:

#include <stdio.h>

int main()
{
int array[5] = {1,2,3,4,5};
    int i = 0;
    printf("%d %d",array[i], array[++i]);
    return 0;
}

which should display elements of array[0] and array[1], right? But it doesn't, as the output is 2 2 What am I missing?

Stefanos
  • 25
  • 4
  • 4
    It is because the comma `,` is not an operator here, and both instances of `i` are sequenced together — meaning that your code has indeterminate behavior. Use `i` and `i+1` and increment the variable _after_ it is used. – Dúthomhas Oct 31 '22 at 15:04
  • You have undefined behaviour. You can't use `i` twice like that with one of the references with an increment. – Jonathan Leffler Oct 31 '22 at 15:04
  • 1
    The commas in a function call argument list are not comma operators. The order in which the arguments are evaluated is not defined. There are no intermediate sequence points while evaluating the arguments. It is undefined when the increment is completed, other than it must be before the sequence point before the function is called. – Jonathan Leffler Oct 31 '22 at 15:12

2 Answers2

3

Here's the thing: You can't guarantee what order function arguments are evaluated in.

What this means is, in your printf call, there's no way to tell whether array[i] or array[++i] will be evaluated first. In your case it appears that array[++i] won, so what happens is that you end up printing array[1] twice.

user18533375
  • 175
  • 1
  • You're absolutely correct. Look here for more details: [Sequence Points](https://en.wikipedia.org/wiki/Sequence_point) and [Why are these constructs using pre and post-increment undefined behavior?](https://stackoverflow.com/a/949443/421195) – paulsm4 Oct 31 '22 at 15:43
2

That's not a good use of pre-increment.

If you want to look at array[i] and array[i+1], just do that:

printf("%d %d\n", array[i], array[i+1]);

Remember, i++ does not just take i's old value and add 1 to it. It takes i's old value, and adds 1 to it, and stores the new value back into i. When you were printing array[i] and array[i+1], did you really want to change the value of i?

If you did want to change the value of i — or, in any case, since that mention of array[i++] did change the value of i — you introduced undefined behavior. Once you've got an expression that's modifying the value of i, how do you know what array[i] will print? How do you know that array[i] won't end up using the new value of i? You probably assumed that things are evaluated from left to right, but it turns out that's not necessarily true. So weird, weird things can happen.

Here's an example that helps show how ++ works, and that's well-defined:

#include <stdio.h>

int main()
{
int array[5] = {1,2,3,4,5};
    int i = 1;
    array[i++] = 22;
    array[++i] = 44;
    for(i = 0; i < 5; i++)
        printf("%d: %d\n", i, array[i]);
    return 0;
}

Or, as you suggested in a comment, if you did want to modify i's value, perhaps to advance the variable i along the array, you sometimes have to take care to move the i++ into a separate statement. The simple rule is, if you're applying ++ or -- to a variable, you can only use that variable once in the same statement. So you can't have i++ + i++, since that has two i's in it and they're both modified. But you also can't have i + i++, or f(a[i], a[i++]), since those have a spot where you modify i, and a spot where you use i, and there's no way to know whether you use the old or the new value of i. (And, again, in C there's not a general left-to-right rule that helps you here.)

Steve Summit
  • 45,437
  • 7
  • 70
  • 103
  • That was actually my intention. In the next line there was an i++; I just tried to make it more compact. – Stefanos Oct 31 '22 at 15:28