51

Whenever you allocate a new array in C# with

new T[length]

the array entries are set to the default of T. That is null for the case that T is a reference type or the result of the default constructor of T, if T is a value type.

In my case i want to initialize an Int32 array with the value -1:

var myArray = new int[100];
for (int i=0; i<myArray.Length; i++) { myArray[i] = -1; }

So after the memory is reserved for the array, the CLR loops over the newly allocated memory and sets all entries to default(int) = 0. After that, my code sets all entries to -1.

That makes the initialization redundant. Does the JIT detect this and neglects the initialization to 0 and if not, is there a way to directly initialize a portion of memory with a custom value?

Referring to C# Array initialization - with non-default value , using Enumerable.Repeat(value, length).ToArray() is no option, because Enumerable.ToArray allocates a new array and copies the values to it afterwards.

Community
  • 1
  • 1
Rauhotz
  • 7,914
  • 6
  • 40
  • 44
  • 1
    If you have byte array, then [P/Invoke could help](http://stackoverflow.com/a/19060558/380331). But if array element size is bigger than byte (as in your case) - this method will not help. – Agnius Vasiliauskas Sep 27 '13 at 21:53

6 Answers6

36

Similar to Dan's answer but without the need of using collections:

int[] myArray = Enumerable.Repeat(-1, 100).ToArray();
Taylor Leese
  • 51,004
  • 28
  • 112
  • 141
33

It's not redundant.

Suppose an exception is thrown during your initialization loop. If the CLR hasn't cleared the memory first, you might be able to "see" the original uninitialized memory, which is a very bad idea, particularly from a security standpoint. That's why the CLR guarantees that any newly allocated memory is wiped to a 0 bit pattern.

The same argument holds for fields in an object, by the way.

I suppose in both cases the CLR could check that you're not going to make the array visible elsewhere before finishing initialization, but it's a complicated check to avoid a pretty simple "wipe this area of memory".

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • I don't see where an exception could be thrown. The JIT is intelligent enough to disable range checks on the array within the loop, so it could also detect that no exception can occur. – Rauhotz Mar 15 '09 at 23:47
10

If you buy into Arrays considered somewhat harmful, then your question would be moot as you would write:

var myArray = new List<int>(Enumerable.Repeat(-1, 100));
David
  • 4,665
  • 4
  • 34
  • 60
Ðаn
  • 10,934
  • 11
  • 59
  • 95
  • 4
    Probably worth mentioning his link is to Eric Lippert's blog, which makes a case that Arrays are bad news because, in many cases, "The caller is requesting values. The callee fulfills the request by handing back variables." Lippert then interestingly argues that, due to physical constraints making faster processors, "We’re going to need programming languages that allow mere mortals to write code that is parallelizable to multiple cores [and that] arrays... strongly work against this goal." It's a great read, if barely tangentially related to this question. ;^) – ruffin Sep 28 '13 at 16:04
  • Arrays are a tool like any other. If you're writing performance critical code where you need to access values using a numeric index, array performance simply can't be beaten, not even by a list (it's not a million miles off, but arrays are still faster, and if you're crunching a lot of data, this matters). It's all about your use case and making the appropriate trade-offs. Honestly, I've got quite tired of the "X considered harmful" trope because it's often written from an excessively narrow PoV. – Bart Read Apr 26 '18 at 15:44
3

I highly doubt that the JIT will optimize away the default set for this scenario. The reason being is that this would be an observable difference. Consider the following slightly altered scenario.

obj.myArray = new int[100];
for (int i=0; i<myArray.Length; i++) { obj.myArray[i] = -1; }

It's entirely possible for the loop to throw. At least, it's probably not possible for the JIT to prove it doesn't. If it did throw and the CLR did not default initialize the memory, the result would be observable if you still had a reference to obj.

JaredPar
  • 733,204
  • 149
  • 1,241
  • 1,454
2

I suggest using Array.Fill as a very succint way to fill an array with an initial value:

bool[] isPrime = new bool[MaxNum];
Array.Fill(isPrime, true);

This initializes all values in the isPrime array to true.

Martin Zikmund
  • 38,440
  • 7
  • 70
  • 91
  • 1
    I could not find the Fill method. Can you point me to the document. I think such method does not exist in C#. – Hardik Apr 26 '20 at 15:56
  • @Hardik It is available only for .Net Core: https://learn.microsoft.com/en-us/dotnet/api/system.array.fill?view=netcore-3.1 – Andreas Schwarz Aug 04 '20 at 17:15
0

If you are looking for one liner solution then you could use below:

var myArray = Array.ConvertAll(new int[100], i => -1);
Hardik
  • 764
  • 5
  • 10