I'm new to C# and practising by writing a solution to the classic 100 doors problem. The below (and probably bad) code solves the problem:
internal class Program
{
private static void Main(string[] args)
{
var doors = new bool[100];
var ints = new int[100];
ints = Enumerable.Range(1, 100).ToArray();
for (int i = 1; i <= 100; i )
{
ints.Where(j => j % i == 0)
.Select(j => j)
.ToList()
.ForEach(j => doors[j - 1] = !doors[j - 1]); //This is the relevant line.
}
Array.ForEach(doors, i => Console.WriteLine(i));
}
}
The line that I've put the comment on has surprised me. It works perfectly fine, but replacing it with either of the below throws System.IndexOutOfRangeException
.ForEach(j => doors[--j] = !doors[--j]);
.ForEach(j => doors[j--] = !doors[j--]);
Why are both of these invalid despite j - 1
being perfectly fine? It's my understanding that, in all circumstances, exactly one of --j
and j--
will be equivalent to j - 1
.
CodePudding user response:
It's my understanding that, in all circumstances, exactly one of --j and j-- will be equivalent to j - 1.
No, definitely not.
The two fail for different reasons though - one when j
is initially 1, and the other when j
is initially 100.
First consider this:
.ForEach(j => doors[--j] = !doors[--j]);
That decrements j
twice, and in each case uses the value of j
after the decrement has happened.
The left hand operand is evaluated first, so when j
is 1, this ends up evaluating array indexes as:
doors[0] = !doors[-1];
Obviously, doors[-1]
is invalid.
Now let's consider the second option:
.ForEach(j => doors[j--] = !doors[j--]);
This again decrements j
twice, but in each array indexing operation uses the value of j
before the decrement. So when j
is 100, this ends up evaluating array indexes as:
doors[100] = !doors[99];
This time it's doors[100]
which is invalid.
In your working code, you're using j - 1
for both indexes, without modifying j
at all, so as j
goes from 1 to 100, the array indexes you're using go from 0 to 99, which are valid.
I would strongly advise against using pre/post-increments/decrements in any expression or statement where you use the modified variable in more than one place - and definitely avoid pre/post-increments/decrements of the same variable multiple times in the same expression or statement.