Home > Enterprise >  How to uodate array inside a for loop and add it to a list
How to uodate array inside a for loop and add it to a list

Time:01-05

I am trying to update an array and add it to a list if a certain condition is true. As you can see in my code the array "rows" is updated every time inside the if condition, and the it is added to "checkList".

The problem is that when I iterate through the list to check the values, it seems that only the last value of rows has been added in every entry in the list.

Here is some code to explain

        int[] rows = new int[2];
        List<int[]> checkList = new List<int[]>();

        for (int i = 0; i < 4; i  )
        {
            for (int j = 0; j < 4; j  )
            {
                if (true) 
                {

                    rows[0] = i;
                    rows[1] = j;

                    checkList.Add(rows);
                }
            }

        }

        foreach (var row in checkList)
        {
            Console.WriteLine(row[0]   "   "   row[1]);
        }

Output:

enter image description here

I hope someone can explain this. Thanks

CodePudding user response:

Most object types in .NET (including arrays) are passed by reference, so checkList.Add(rows); adds a reference to the same array to the list, multiple times.

Instead, you'll want to create a new array instance every time:

List<int[]> checkList = new List<int[]>();

for (int i = 0; i < 4; i  )
{
    for (int j = 0; j < 4; j  )
    {
        if (true) 
        {
            checkList.Add(new int[]{ i, j });
        }
    }
}

CodePudding user response:

I believe the issue here is that when you are

checkList.Add(rows);

You are adding a reference to the rows array every time to the list, not a separate copy of it. This leads to your current behaviour.

A solution would be to instantiate the array inside the loop, so a new array is created every iteration.

        List<int[]> checkList = new List<int[]>();

        for (int i = 0; i < 4; i  )
        {
            for (int j = 0; j < 4; j  )
            {
                if (true) 
                {
                    int[] rows = new int[2];
                    rows[0] = i;
                    rows[1] = j;

                    checkList.Add(rows);
                }
            }

        }

CodePudding user response:

As a supplement to Matthias answer, one of the things that's perhaps not easy to appreciate about C# is that most variables you have and use are merely a reference to something else. When you assign some variable like this:

int[] rows = new int[2];

C# creates some space in memory to keep an array of 2 integers, it attaches a reference to it, and that thing becomes your variable that you use, named rows. If you then do:

int[] rows2 = rows;

It doesn't clone the memory space used and create a new array, it just creates another reference attached to the same data in memory. If the data were a dog, it now has 2 leads attached to its collar but there is still only one dog. You can pull on either lead to urge the dog to stop peeing on a car, but it's the same dog you're affecting.

Array/list slots are just like variables in this regard. To say you have:

List<int[]> checkList = new List<int[]>();

Means declare a list where each of its slots are a variable capable of referring to an int array. It's conceptually no different to saying:

int[] checkList0 = row;
int[] checkList1 = row;
int[] checkList2 = row;
int[] checkList3 = row;

It's just that those numbers are baked into the name, whereas a list permits you a way of varying the name programmatically (and having more than 4 slots):

checkList[0] = row;
checkList[1] = row;
checkList[2] = row;
checkList[3] = row;

checkList[0] is conceptually the entire variable name, just like checkList0 is a variable name, and remember that this is hence just another variable that is just a reference to that same array in memory.

By not making a new array each time, you attached every variable slot in the list to the same array in memory, and thus you ended up with something in memory that looks like:

enter image description here

The black is the list, the blue is the array. Every list slot is just a reference to the same array. You might have changed the numbers in the array 200 times, but at the end of the oepration, because there was only ever one array, you only see the final set of numbers you wrote into the array. You might have attached 20 leads to your dog and pulled each of them once, but it's still just the same dog that has 20 times been stopped from peeing on 20 cars.

Matthias answer works (and is how it should be done) because you concretely make a new array each time

enter image description here

Numbers in blue are fabricated and not intended to represent the answers you should see printed; the concept being explained is that of linking to new array objects in memory


You'd be forgiven for thinking that a clone would be made, bcause it is for int. int is a value type, whcih means the value is copied when it's used:

int x = 1;
int y = x;
y = y   1;

y is now 2, but x is still 1. It'd be pretty hard work to write C# if it wasn't this way i.e. if every time you incremented some int variable, every other variable that had touched the variable that it came from was also affected.. So I think it's perhaps intrinsically reasonable to assume that whenever an assignment of anything is made, changes that affect the value of the assigned variable don't affect earlier iterations of it.. but that's not the case. There's this clear divide between value types (types whose data is copied/cloned when they're assigned) and reference types (types whose data is not copied/cloned). While int is a value type (cloned), an int[] is a reference type (not cloned)

..and that's something you'll really need to get down with and remember


Roll on the what's ref/out for? query :D

  •  Tags:  
  • Related