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.
>Solution :
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.