(Array.Clone) Shallow Copy vs Deep Copy of an Array - c#

int[] myArray = {1, 2, 3, 4, 5};
Console.WriteLine(myArray[0]);
int[] localArray = (int[])myArray.Clone();
localArray[0] = 10;
Console.WriteLine(myArray[0]);
Console.WriteLine(localArray[0]);
The output of the following was:
1
1
10
As to my understanding, both myArray[0] and localArray[0] should point to the same integer, and if I change localArray[0] to 10, it should reflect upon myArray[0] as well. But as the output suggests they both point to different integers. What's going on here?

A Shallow Copy of an Array is not the same as a copy of an array:
Copying an array, copies the reference to the array to a new variable. Both variables will be pointing to the same values.
The Clone method creates a new, distinct array containing a copy of the elements of the original array. If those elements are value types (like in your case ìnt) the new array will contain the same set of values as the original but stored in another location.
If the elements of the array are of a reference type, the new array will contain copies of the original references. So the first elements of both array would contain the same reference to an object.
See also: https://learn.microsoft.com/en-us/dotnet/api/system.array.clone?view=net-6.0
A shallow copy of an Array copies only the elements of the Array, whether they are reference types or value types, but it does not copy the objects that the references refer to. The references in the new Array point to the same objects that the references in the original Array point to.

If elements are value type then "Shallow Copy" == "Deep Copy" (as "int' in this case).
In case if elements are reference type then "A Shallow Copy of an Array is not the same as a copy of an array:" and below as wrote the #Johan Donne

Related

Storing lots of Arrays into a List on every Loop

I have a question about storing lots of arrays into a list.
First, I initialize the array and list:
int[] arr = new int[9];
List<int[]> forkarr = new List<int[]>();
then I run through a lot of for loops and modify the array each time in order to produce all possible tic tac toe variations. While looping through all those variations, if the array is a possible board then I print it, and additionally if the array meets certain criteria for being a 'fork', then I will add it to the list like this:
if (ForkCheck.fork(arr)) { forkarr.Add(arr); Console.WriteLine("It's a Fork!");}
which also prints that message letting you know that particular array is a fork.
Now, when I am printing all of the arrays, the ones that are forks are printed properly and labeled as such.
However, when I go to print out all of the int[] elements of my list forkarr like so:
foreach (int[] arry in forkarr)
{
PrintGame.print(arry);//this is my method that prints the array
Console.WriteLine();
}
for some reason each array becomes an identical:
222
222
222
(I'm using 2 as 'X' and 1 as 'O' and 0 as 'empty' btw)
And it just prints that out over and over for all the forks.
So, something is going wrong when I am adding each modification of the array as a new element in the list I think, but I'm not sure why.
Thanks for any help.
Because you are modifying the same array and adding it to the list. Each time you done with one array array you need to create a new instance like this:
arr = new int[9];
This will create a new reference which will be independent from other arrays. And modifying it's elements wont affect the others.
For more information about value vs reference types you can refer to the question below:
What is the difference between a reference type and value type in c#?

Why changing one array changes another array in C#?

I have a two dimensional array namely States in C#. I build a one dimensional array, namely SubState, from States. When I change SubState, States changes too. I want States be unchanged. Thanks
int[] SubState = State [0];
SubState[0]-=1; //State[0][0] is also changed here
In my mind your State definition is:
int[][] State;
Array is a reference type and when you copy an element from the State array you get a reference to the array from the first list and the both references map to the same int[] array. So when you change array stored at SubArray you use a link to the same array.
The simple fix is a copy of the source array
var SubState = State[0].ToArray();
That is because when you assign the array you pass its reference you are not making a copy of it. Look at the msdn link on the array copy method https://msdn.microsoft.com/en-us/library/System.Array.Copy(v=vs.110).aspx
int[] SubState = State [0]; is just another reference to the state array and so can be changed via it as well.
What you probably want to do, is create a separate array from the state array like
int[] substate = new int[state.GetLength(0)];
state.CopyTo(substate, 0);
You are not building a new one-dimensional array. You are simply creating a new reference to the first row of your two-dimensional array. If you actually want to build a new one-dimensional array, you have to iteratively copy the first row of your two-dimensional array.
Try:
int[] SubState = new int[States[0].length];
States[0].CopyTo(SubState, 0);
instead of
int[] SubState = State [0];
try
int[] SubState = new int[State[0].Length];
Array.Copy(State[0],Substate, Substate.Length)
So you are not simply assigning a new reference, but are actually copying the array correctly
Obviously your element at position 0 of State is an array of int which is a reference-type. Thus both SubState and State reference the same array which is why changes to any of their elements are reflected by both. To overcome this problem you may create a copy of your State-array and copy its values to SubState:
States.CopyTo(SubStates, 0);
EDIT: Thius assumes that SubStates was already initialized with the same size as States. e.g:
int[] SubStates = new int[States[0].Length];

Issue when copying a ArrayList to an Array. Elements are not being preserved

I'm experiencing an issue with ArrayList.ToArray where it seems to be reallocating some of the references that are stored in the ArrayList when I convert it to an array. I have an ArrayList of references which are used as keys in a HashTable. At one point the ArrayList is copied to an Array using the line below:
destination.Items = newItems.ToArray(typeof(MyItem)) as MyItem[];
The way I see it references in the target array should have been preserved from the source ArrayList but doesn't always occur. In some instances when I use the references in the target arrays to do a lookup in the HashTable it fails.
But If I use the code below to explicitly copy the items to the source array than the lookups succeed 100% of the times.
MyItem[] Items = destination.Items;
Array.Resize(ref Items, newItems.Count); //First I resize to receive all the elements
int i = 0;
foreach (MyItem newItem in newItems)
{
Items[i++] = newItem;
}
Is there anything being done under the covers by ArrayList.ToArray (reallocation for instance) which could cause the elements to be re-created such that the HashTable lookup would fail ?
Am I missing something ?
It doesn't make sense, unless there's more on this story. For example, if there are other threads changing values, or if you are storing other types that are not compatible, etc.
Can you change your ArrayList to List? That could resolve the issue if it's a bug in ArrayList.
However I would recommend that you create a temp hack in your code so that you always compare all the items of the original list vs all the items on the returned array. If both collections don't match 100%,then dump both Into a log file (dump both the values AND some Metadata such as the total elements, type of the elements, etc)

Does the length of a newly instantiated array resolve to 0 or null?

HOMEWORK: I'm getting and index out-of-bounds on the following code. It's a hangman game, and I'm keeping track of the letters I've guessed in a char array.
Here's the assumptions I made:
In the calling method, I have an unpopulated array (char[] displayGuesses = new char[26];) passing to the method below as the char[] usedLetters parameter.
The first iteration of the letter-guessing, the array will be empty.
It's length will be 0.
I populate usedLetters[0] with the letterGuessed parameter.
The next time I guess, length of the array will be 1, so usedLetters[1] gets populated...and so on.
public char[] trackUsedLetters(char letterGuessed, char[] usedLetters)
{
int letterIndex = usedLetters.Length;
usedLetters[letterIndex] = letterGuessed;
return usedLetters;
}
There's a couple things I think may be going on.
When I try to get the length of usedLetters on the first run, the empty array does
NOT return zero, but null. Boom. Out-of-bounds.
There's some issue with passing a blank array defined with 26
members...? But I'm not sure what that issue would even BE, so I have no idea what to google that will yield relevant results.
I may have a scope issue; I found this link to a similar
question for Java, though using a for loop. I don't quite get
what the Java user was going for, but some of the problems sounded
familiar.
I need a second pair of eyes to look at this and point me in the right direction for solving this.
According to the c# specification: (emphasis mine)
1.8 Arrays
Array types are reference types, and the declaration of an array variable simply sets aside space for a reference to an array instance. Actual array instances are created dynamically at run-time using the new operator. The new operation specifies the length of the new array instance, which is then fixed for the lifetime of the instance. The indices of the elements of an array range from 0 to Length - 1. The new operator automatically initializes the elements of an array to their default value, which, for example, is zero for all numeric types and null for all reference types.
Default Values which gives the char data type default as '\0'
It looks like you want List<char> that can grow (with Add) method.
Arrays have fixed size and following code (that you have in sample) will always throw out of range exception because you are accessing element past last element in array.
usedLetters[usedLetters.Length] = 'c';
More details on array length:
// newArray - array of 0 chars. newArray.Length is 0
var newArray = new char[0];
// nullArray not created, nullArray.Length will throw NullReferenceExcetption
char[] nullArray = null;
// defaultArray = array of 26 characters, each value 0.
// defaultArray.Length is 26;
char[] defaultArray = new char[26];
When you define a new array, but don't manually initialize the items inside of it, it will automatically be initialized with the default values for whatever type the array contains. In your case, you're creating a character array. The default value for a char is '\0', or the null character.
This means that the array is never truly "empty." If you define an array with 26 slots, it will always have that length, unless you make a new array.

in c# ,one array of class and two connected instance of it why?

I wrote the code below :
1. MyClass[] origArr=new MyClass[3];
2. MyClass[] arr1;
3. // filled the array with objects and did some work on it .
4. dgv_1.DataSource=origArr;
5.
6. // Here is the problem :
7. arr1=origArr;
8. // do some work on arr1 ...
9. dgv_2.DataSource=arr1;
For some reason the data in 'origArr' changed when data in 'arr1' change ...
I thought that maybe this happened because 'origArr' and 'arr1' are pointers referring to the same object so I changed line '7' to :
7. origArr.CopyTo(arr1,0);
but it didn't work ... what can i do to make the pointers referring to different objects?
Your line 7 copies the reference to origArr into arr1, so they point to the same physical array.
Even a Clone or CopyTo won't help much: you will get a copy of the array structure, but in there the references to your oringinal classes are copied. So you end up with a new array with still the same objects.
You will need to Clone your MyClass objects and put those clones into a new array.
In c# variable holds reference, not the value. to copy it do
MyClass[] origArr=new MyClass[3];
MyClass[] arr1 = new MyClass[3];
origArr.CopyTo(arr1,0);
you have to allocate memory by yourself
You need to change line 7 to origArr.CopyTo(arr1,0); as you noted. But you also need to initialize the arr1 array.
1. MyClass[] origArr=new MyClass[3];
2. MyClass[] arr1=new MyClass[3];
try to use
Array.Copy(src , dest, lenght)

Categories