'Print all numbers from 1000 to 9999 array, while loop unexpected behaviour

I have the following code:

int main() {
    int PIN[4] = {1, 0, 0, 0}; // Start from 1000
    while ((PIN[0] != 9) && (PIN[1] != 9) && (PIN[2] != 9) && (PIN[3] != 9)) { // Stop at 9999

        PIN[3]++;
        if (PIN[3] > 9) {
            PIN[3] = 0;
            PIN[2]++;
            if (PIN[2] > 9) {
                PIN[2] = 0;
                PIN[1]++;
                if (PIN[1] > 9) {
                    PIN[1] = 0;
                    PIN[0]++;
                }
            }

        }
        //  Print all numbers from 1000 to 9999
        printf("%d %d %d %d \n", PIN[0], PIN[1], PIN[2], PIN[3]);
    }
    return 0;
}

Output is:

1 0 0 1 
1 0 0 2 
1 0 0 3 
1 0 0 4 
1 0 0 5 
1 0 0 6 
1 0 0 7 
1 0 0 8 
1 0 0 9 

Process finished with exit code 0

If I use the OR operator instead of the AND operator inside the while it stops at 9999 which is the desired behaviour. Why this happens?

I want to do while(every digit is different from 9)

like this:

...
9 9 9 3 
9 9 9 4 
9 9 9 5 
9 9 9 6 
9 9 9 7 
9 9 9 8 
9 9 9 9 

Process finished with exit code 0
c


Solution 1:[1]

Consider (PIN[0] != 9) || (PIN[1] != 9) || (PIN[2] != 9) || (PIN[3] != 9) when the PIN values are 1, 0, 0, and 9. Then:

  • 1 != 9 is true.
  • 0 != 9 is true.
  • 0 != 9 is true.
  • 9 != 9 is false.
  • true || true || true || false is true.

In more detail: || is true if either operand is true, and true || true || true || false is structured as ((true || true) || true) || false. In that, true || true evaluates as true, so we have (true || true) || true, which becomes true || true, which becomes true.

Consider the expression when the values are 9, 9, 9, 9. Then:

  • 9 != 9 is false.
  • 9 != 9 is false.
  • 9 != 9 is false.
  • 9 != 9 is false.
  • false || false || false || false is false.

In more detail: || is false if both of its operands are false. false || false || false || false is structured as ((false || false) || false) || false. In that, false || false evaluates as false, so we have (false || false) || false), which becomes false || false, which becomes false.

Solution 2:[2]

while ((PIN[0] != 9) && (PIN[1] != 9) && (PIN[2] != 9) && (PIN[3] != 9)) { is saying "while [0] is not nine and [1] is not 9 and [2] is not nine and [3] is not nine". So as soon as any one digit IS nine the loop ends.

You want to end when they are all 9. So you want to end when PIN[0] == 9 && PIN[1] == 9 && PIN[2] == 9 &&PIN[3] == 9 so you want to keep going while that is false. while(!(PIN[0] == 9 && PIN[1] == 9 && PIN[2] == 9 && PIN[3] == 9))

Solution 3:[3]

You are effectively trying to achieve the following:

for (int pin0=1; pin0<10; ++pin0) {
for (int pin1=0; pin1<10; ++pin1) {
for (int pin2=0; pin2<10; ++pin2) {
for (int pin3=0; pin3<10; ++pin3) {
   ...
}}}}

The difference is that your approach allows you to have a variable number of digits. If that's not something you need, then this approach would be simpler.


As for the problem with your code, it's that you have the wrong operation. You loop while no digit is nine, but you want to loop while any digit isn't nine.

PIN[0] != 9 || PIN[1] != 9 || PIN[2] != 9 || PIN[3] != 9

You could also think of it as looping until all the digits are nine.

!( PIN[0] == 9 && PIN[1] == 9 && PIN[2] == 9 && PIN[3] == 9 )

Alternative solution:

for (int pin=1000; pin<10000; ++pin) {
   int pin0 = ( pin / 1000 ) % 10;
   int pin1 = ( pin /  100 ) % 10;
   int pin2 = ( pin /   10 ) % 10;
   int pin3 = ( pin /    1 ) % 10;
   ...
}

This approach can also be used with a variable number of digits.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Eric Postpischil
Solution 2 John3136
Solution 3