if (Int32.Parse(strTotals) == 0 && nTotalCount != 0)
{
nTotalCount = 0;
for (int j = 0; j < 66; j++)
{
if (GameHistoryPicBox1[j].InvokeRequired)
{
GameHistoryPicBox1[j].BeginInvoke(new MethodInvoker(() =>
{
if ((j + j / 6) % 2 == 0)
GameHistoryPicBox1[j].Image = Properties.Resources.al1; // Line2
else
GameHistoryPicBox1[j].Image = Properties.Resources.al2; // Line4
}));
}
else
{
if ((j + j / 6) % 2 == 0)
GameHistoryPicBox1[j].Image = Properties.Resources.al1;
else
GameHistoryPicBox1[j].Image = Properties.Resources.al2;
}
}
}
I have been checking nTotalCount value by using thread.
If nTotalCount is zero, then I must clean all game picture box image.
So I was implement above code.
Unfortunately, I got the error:
An unhandled exception of type 'System.IndexOutOfRangeException'
on Line 2 and 4.
And the j value was 66.
Is it possible that j value could be 66?
This is because of how closures work. Your lambda expression that you're creating and passing to the MethodInvoker references the j variable by reference. Thus when this piece of code is being executed (which can be almost any time, as it's asynchronous) the j variable can have any value from 0 to 66. And it can be 66 after the loop has finished.
A quick fix is to make a copy of j:
int index = j;
GameHistoryPicBox1[index].BeginInvoke(new MethodInvoker(() =>
{
if ((index + index / 6) % 2 == 0)
GameHistoryPicBox1[index].Image = Properties.Resources.al1; // Line2
else
GameHistoryPicBox1[index].Image = Properties.Resources.al2; // Line4
}));
You can read more about this here.
The variable j is being passed into the closure, and because the call is asynchronous, it is actually executed at some point after the loop completes. You cannot be sure what the value of j will be when the delegate is executed.
Try passing the value of j in as a parameter to the delegate, like this:
GameHistoryPicBox1[j].BeginInvoke(new Action<int>((x) =>
{
if ((x + x / 6) % 2 == 0)
GameHistoryPicBox1[x].Image = Properties.Resources.al1;
else
GameHistoryPicBox1[x].Image = Properties.Resources.al2;
}), j);
You've been bitten by the loop-variable-in-a-closure-bug.
Instead of
for (int j = 0; j < 66; j++)
{
//blahblahblah
}
write
for (int jj = 0; jj < 66; jj++)
{
int j = jj;
//blahblahblah
}
Related
I am working on a if statement that compare cell values to an integer. The method I used is convert.ToInt16. As result showing below, the if statement becomes very long. I am wondering if there an another approach to shorten the code?
int i, emplyNum;
for (int j = 1; j< 3; j++)
{
if ((( Convert.ToInt16(Employee.Rows[j][1]) - 1) < i && i < ( Convert.ToInt16(Employee.Rows[j][2]) + 1)) || ((Convert.ToInt16(Employee.Rows[j][3]) - 1) < i && i < (Convert.ToInt16(Employee.Rows[j][4]) + 1)) || ((Convert.ToInt16(Employee.Rows[j][5]) - 1) < i && i < (Convert.ToInt16(Employee.Rows[j][6]) + 1)))
{
emplyNum = j;
}
}
I've just started getting into Lambda-Expressions, and found a behaviour that - to me - seems unintuitive. I suspect I haven't understood aspects of the underlying concept.
so we have These two for-loops:
List< Func< int, int>> list = new List< Func < int, int>>();
for (int i = 0; i < 5; i++)
{
list.Add(j => j + i);
}
for (int i = 0; i < 5; i++)
{
Console.WriteLine(list[i](i));
}
I had expected an Output something like this:
0 ( since j+0 with j=0 equals 0)
2 ( since j+1 with j=1 equals 2)
4 (…)
6
8
Instead the Output showed:
5 ( I suspect since j+5 with j=0 equals 5)
6 ( I suspect since j+5 with j=1 equals 6)
7 (…)
8
9
What happens is that adding Funcs to the List the i-value is updated for every previously-added Func.
Why is that so?
That is because the local variable i is only capturing the last value. You should create a separate variable with a local scope (one that goes out of scope for the next iteration):
for (int i = 0; i < 5; i++)
{
int l = i;
list.Add(j => j + l);
}
This is a very written about Capture/Closure issue
for (int i = 0; i < 5; i++)
{
var newI = i;
list.Add(j => j + newI);
}
for (int i = 0; i < 5; i++)
{
Console.WriteLine(list[i](i));
}
Output
0
2
4
6
8
When a local variable is captured, it is captured by reference, so any update to the variable will be reflected when you use the captured variable in the function.
The compiler lifts the local variable as the field of a generated class, basically what happens is something similar to this:
class Closure
{
public int i;
public int Fn(int j) => i + j;
}
static void Main(string[] args)
{
List<Func<int, int>> list = new List<Func<int, int>>();
var c = new Closure();
for (c.i = 0; c.i < 5; c.i++)
{
list.Add(c.Fn);
}
for (int i = 0; i < 5; i++)
{
Console.WriteLine(list[i](i));
}
}
You can get around this behavior by declaring a local variable in the loops o the compiler will capture that local variable, and since the semantics of that are that the variable must be different on each loop iteration, the compiler will generate a separate capture instance for each iteration.
for (int i = 0; i < 5; i++)
{
int l = i;
list.Add(j => j + l);
}
// Equivalent to :
for (var i = 0; i < 5; i++)
{
var c = new Closure();
c.i = i;
list.Add(c.Fn);
}
It's a known effect of capture; in your current code
for (int i = 0; i < 5; i++)
{
// each lambda uses shared "i" variable
list.Add(j => j + i);
}
// Now (after the for loop) i == 5,
// that's why all lambdas j => j + i are in fact j => j + 5
If you want to avoid i variable capture, you can change your code into
for (int i = 0; i < 5; i++)
{
// local variable: each iteration has its own temp to be captured
int temp = i;
list.Add(j => j + temp);
}
// 1st lambda j => j + temp equals to j => j + 0
// 2nd lambda j => j + temp equals to j => j + 1
// ...
// n-th lambda j => j + temp equals to j => j + n - 1
I am attempting an insertion sort algorithm in c# and struggling to fix this error message:
"System.IndexOutOfRangeException' occurred in algorithmsAssignment.exe"
As soon as it reaches the while loop, the code breaks and gives me the message. Any help would be appreciated
(I have had to do string.compare as I'm using a 2D array string.
static void insertionSort(int columnSort, bool accendingOrder)
{
int column = columnSort - 1;
int i, j;
for (i = 1; i < dataArray.GetLength(1); i++)
{
string key = dataArray[column, i];
j = i - 1;
/* Move elements of arr[0..i-1], that are
greater than key, to one position ahead
of their current position */
while (j >= 0 && string.Compare(dataArray[column, j - 1],
dataArray[j, column]) > 0)
{
dataArray[column, j + 1] = dataArray[column, j];
j = j - 1;
}
dataArray[column, j + 1] = key;
}
}
In your first for iteration: ( i = 1 )
string key = dataArray[column, i];
j = i - 1;
// J value is 0
while (j >= 0 && string.Compare(dataArray[column, j - 1], //Here, j - 1 = -1, since j = 0
....
....
I bet there is your index out of range, since index -1 can't exist.
Cheers
You will get error for i=1 because you have this conditions:
j = i - 1; //j=0 for i=1
and wrong condition in while loop
while (j >= 0 && string.Compare(dataArray[column, j - 1],
dataArray[j, column]) > 0)
this condition in while loop dataArray[column, j - 1] will throw IndexOutOfRange exception because
j-1=-1 for j=0
Its been bugging me for hours because it is always returning 0 at numbers[i] and I cant figure out the problem. code worked for a different program but I had to change it so it could have a custom array size and that's when everything went wrong.
any help would be great.
Thanks in advance.
int[] numbers = new int[Convert.ToInt16(TxtArray.Text)];
int j = 0;
for (j = numbers.Length; j >= 0; j--)
{
int i = 0;
for (i = 0; i <= j - 1; i++)
{
string NumbersInput = Microsoft.VisualBasic.Interaction.InputBox("Enter Numbers to be sorted",
"Numbers Input", "", -1, -1);
numbers[i] = Convert.ToInt16(NumbersInput);
//returns 0 in if statement
if (numbers[i] < numbers[i + 1])
{
int intTemp = 0;
intTemp = numbers[i];
numbers[i] = numbers[i + 1];
numbers[i + 1] = intTemp;
}
}
}
for (int i = 0; i < numbers.Length; i++)
{
LstNumbers.Items.Add(numbers[i]);
}
private void button1_Click(object sender, EventArgs e)
{
int sizeOfArrayInt = Convert.ToInt32(arraySize.Text);
int[] array = new int[sizeOfArrayInt];
string numbers = arrayValues.Text;
string[] numbersSplit = numbers.Split(',');
int count = 0;
foreach (string character in numbersSplit)
{
int value;
bool parse = Int32.TryParse(character, out value);
if (value != null)
{
array[count] = value;
}
count++;
}
array = this.SortArray(array);
foreach (int item in array)
{
this.listBox.Items.Add(item);
}
}
private int[] SortArray(int[] arrayToSort)
{
//int[] sortedArray = new int[arrayToSort.Length];
int count = arrayToSort.Length;
for (int j = count; j >= 0; j--)
{
int i = 0;
for (i = 0; i <= j - 2; i++)
{
if (arrayToSort[i] < arrayToSort[i + 1])
{
int intTemp = 0;
intTemp = arrayToSort[i];
arrayToSort[i] = arrayToSort[i + 1];
arrayToSort[i + 1] = intTemp;
}
}
}
return arrayToSort;
}
strong text
This I got to work as a Windows Form and the output displays in the list box as each array item or individual i iteration over the array. Of course there is no error checking. Hope that helps.
Setting aside the strangeness of how you are working with text boxes, your problem with throwing an exception would happen even without them because it lies here, in your inner loop:
for (i = 0; i <= j - 1; i++)
Suppose that numbers.Length == 2. This means that j == 2. So on the first time through the outer loop, you hit the inner loop with these conditions. The first time through, i == 0. You get to the if statement:
if (numbers[i] < numbers[i + 1])
numbers[0] exists, and numbers[1] exists, so this iteration goes through fine and i is incremented.
Now i == 1. Now the loop checks its boundary condition. i <= j - 1 == true, so the loop continues. Now when you hit that if statement, it tries to access numbers[i + 1], i.e., numbers[2], which does not exist, throwing an IndexOutOfRangeException.
Edit: Came back and realized that I left out the solution (to the exception, anyway). For the bubble sort to work, your inner loop's boundary condition should be i <= j - 2, because j's initial value is == numbers.Length, which is not zero-based, while array indexes are.
Second Edit: Note that just using a List won't actually solve this problem. You have to use the right boundary condition. Trying to access list[list.Count()] will throw an ArgumentOutOfRangeException. Just because a List will dynamically resize doesn't mean that it will somehow let you access items that don't exist. You should always take time to check your boundary conditions, no matter what data structure you use.
I'm taking a class that uses C# and our first assignment is to implement Conway's game of Life. We must do this by reading in a text file formatted something like this:
*
*
***
***
We then have to display the next 10 generations on the screen.
I have the file read into a string array, then I copy it to another array. I then go through it character by character and change the copied array to match what the next generation should be. My problem is that the code I have to count the live neighbors isn't working and I can't figure out why. I displayed the number of live neighbors for each cell on the screen and about half of them are wrong. I know the error is occurring with cells on the edge of the "board," but I can't figure out how to fix it.
Now, I don't want the whole thing written for me, that'd be a bit pointless. I just can't figure out where my logic is off. Any help would be appreciated. Also, I'm aware that my code is pretty poor, overall. This was just the only way I could figure it out. Sorry.
class Program
{
static void Main(string[] args)
{
//gets file name from command arguments
//checks to make sure file exists, exits if file does not exist
if (!File.Exists(Environment.GetCommandLineArgs()[1])) { System.Environment.Exit(1); }
//gets file name from command arguments then reads file into array of strings
string[] gen0 = File.ReadAllLines(Environment.GetCommandLineArgs()[1]);
string[] gen1 = gen0;
char alive = '*';
char dead = ' ';
//displays first generation
foreach (string s in gen0)
{
Console.WriteLine(s);
}
Console.WriteLine("=====================================");
//counts live neighbors of a cell
int count = 0;
for (int i = 0; i < gen0.Length; i++)
{
count = 0;
for (int j = 0; j < gen0[i].Length; j++)
{
//check top left neighbor
if (i > 0 && j > 0 && j < gen0[i-1].Length )
{
if (gen0[i - 1][j - 1] == alive) { count++; }
}
//check above neighbor
if (i > 0 && j < gen0[i-1].Length)
{
if (gen0[i - 1][j] == alive) { count++; }
}
//check top right neighbor
if (i > 0 && j + 1 < gen0[i - 1].Length)
{
if (gen0[i - 1][j + 1] == alive) { count++; }
}
//check left neighbor
if (j > 0)
{
if (gen0[i][j - 1] == alive) { count++; }
}
//check right neighbor
if (j + 1 < gen0[i].Length)
{
if (gen0[i][j + 1] == alive) { count++; }
}
//check bottom left neighbor
if (i + 1 < gen0.Length && j > 0 && j < gen0[i+1].Length)
{
if (gen0[i + 1][j - 1] == alive) { count++; }
}
//check below neighbor
if (i + 1 < gen0.Length && j < gen0[i+1].Length)
{
if (gen0[i + 1][j] == alive) { count++; }
}
//check bottom right neighbor
if (i + 1 < gen0.Length && j + 1 < gen0[i].Length && j + 1 < gen0[i+1].Length)
{
if (gen0[i + 1][j + 1] == alive) { count++; }
}
//Console.WriteLine(count);
//kills cells
if (count < 2 || count > 3)
{
gen1[i] = gen1[i].Remove(j, 1);
gen1[i] = gen1[i].Insert(j, dead.ToString());
}
//births cells
if (count == 3)
{
gen1[i] = gen1[i].Remove(j, 1);
gen1[i] = gen1[i].Insert(j, alive.ToString());
}
}
}
foreach (string s in gen1)
{
Console.WriteLine(s);
}
}
}
Your problem is very simple - you're resetting count in the wrong place. Put it inside the loop and it will (probably) work.
Regarding the rest of the code, if you want to make it significantly easier to follow just give your game area a one-element border.
You'll need to pad the file you read in (blank line above and below, blank characters to the left and right), and alter your loops to:
for (int i = 1; i < gen0.Length - 1; i++)
and
for (int j = 1; j < gen0[i].Length - 1; j++)
but your central count calculation can then be reduced down to a single calculation:
count = (gen0[i - 1][j - 1] == alive) ? 1 : 0 +
(gen0[i - 1][j] == alive) ? 1 : 0 +
... etc ...
which should make for cleaner code and ensure that any other errors you may make are significantly easier to spot.
So the first bug I see is that you don't actually copy the board for the next iteration.
gen1 = gen0;
The code above only assigns the gen1 reference to the same object as gen0. So when you modify gen1, you actually modify gen0 as well... causing inconsistencies in latter iterations. Try this:
gen1 = (string[])gen0.Clone();
Second bug is that int count = 0 should be in the second loop instead of first:
for (int i = 0; i< gen0.Length; i++)
{
// not here
// int count = 0
for (int j = 0; j < gen0[i].Length; j++)
{
// here
int count = 0
...
}
...
}
This way you reset the count for every cell instead of every row.