what is the exact maximum limit of elements in an array - c#

This is a purelly theoretical question, so please do not warn me of that in your answers.
If I am not mistaken, and since every array in .NET is indexed by an Int32, meaning the index ranges from 0 to Int32.MaxValue.
Supposing no memory/GC constraints are involved an array in .NET can have up to 2147483648 (and not 2147483647) elements. Right?

Well, in theory that's true. In fact, in theory there could be support for larger arrays - see this Array.CreateInstance signature which takes long values for the lengths. You wouldn't be able to index such an array using the C# indexers, but you could use GetValue(long).
However, in practical terms, I don't believe any implementation supports such huge arrays. The CLR has a per-object limit a bit short of 2GB, so even a byte array can't actually have 2147483648 elements. A bit of experimentation shows that on my box, the largest array you can create is new byte[2147483591]. (That's on the 64 bit .NET CLR; the version of Mono I've got installed chokes on that.)
EDIT: Just looking at the CLI spec, it specifies that arrays have a lower bound and upper bound of an Int32. That would mean upper bounds over Int32.MaxValue are prohibited even though they can be expressed with the Array.CreateInstance calls. However, it also means it's permissable to have an array with bounds Int32.MinValue...Int.MaxValue, i.e. 4294967296 elements in total.
EDIT: Looking again, ECMA 335 partition III section 4.20 (newarr) specifies that a initializing a vector type with newarr has to take either a native int or int32 value. So it looks like while the normally-more-lenient "array" type in CLI terminology has to have int32 bounds, a "vector" type doesn't.

Related

Are C# arrays guaranteed to be stored sequentially in memory?

According to many sources on the internet, in C# arrays are stored sequentially. That is if I have a pointer to the first element in the array, say int *start = &array[0], then I can access array[i] by doing *(start + i).
However, I was looking through the C# Language Specification which is stored in C:\Program Files (x86)\Microsoft Visual Studio 12.0\VC#\Specifications\1033 and I cannot find anyplace that guarantees that this will be the case.
In practice this might not be an issue, if say Microsoft and Mono keep their implementations in sync, but I was wondering if there is an official source that guarantees that arrays are stored sequentially in memory.
Thanks!
From the ECMA specification for the CLR:
I.8.9.1 Array types
....
Array elements shall be laid out within the array object in row-major
order (i.e., the elements associated with the rightmost array
dimension shall be laid out contiguously from lowest to highest
index). The actual storage allocated for each array element can
include platform-specific padding. (The size of this storage, in
bytes, is returned by the sizeof instruction when it is applied to the
type of that array’s elements.)
So yes in a compliment implementation of ECMA-335 Common Language Infrastructure elements in an a array will be laid out sequentially.
But there may be platform specific padding applied, so implementations on 64 bit platforms may chose to allocate 64bits for each Int32.
Yes, one-dimensional, zero-based arrays (vectors) in .NET are stored sequentially. In fact, you can use unsafe code with pointers to access array elements one-by-one by incrementing the pointer.
ECMA-335 specification of CLI, section 1.8.9.1 says the following about arrays:
Array elements shall be laid out within the array object in row-major order (i.e., the elements associated with the rightmost array dimension shall be laid out contiguously from lowest to highest index). The actual storage allocated for each array element can include platform-specific
padding.

Why does Array.Copy support Long Arguments

From the MSDN:
Parameters sourceArray
The Array that contains the data to
copy. destinationArray
The Array that receives the data.
length
A 64-bit integer that represents the
number of elements to copy. The
integer must be between zero and
Int32.MaxValue, inclusive
Given that the permitted range of values is 0 to Int32.MaxValue, what is the motivation for adding this signature? It did not exist in .Net 1.0 and was only added in .Net 1.1. My only guess is to prepare for 64-bit Framework implementations.
Curiously an array also has overloads for GetItem that take either an Int32 and an Int64. But in practice you cannot have a single object larger than 2 gigabytes in the current implementation of the .NET framework so you can't actually create an array that allows such large indexes.
I guess if this restriction were lifted later then it would mean that they don't need to change the interface.

why does "UInt64[] arr=new UInt64[UInt64.MaxValue];" throw exception?

Why does following code throw exception "Arithmetic operation resulted in an overflow." ?
UInt64[] arr=new UInt64[UInt64.MaxValue];
I guess because totally 8 * UInt64.MaxValue bytes is requested to be allocated, and this multiplication obviously overflows a 64-bit register.
Because indexers only take Int32 values. You can do
UInt64[] arr=new UInt64[Int32.MaxValue];
But thats the limit.
EDIT: Technically you can index an array with value structures that can theoretically be higher than Int32.MaxValue (because you can index an array with a long or a uint for example), however, you will run into that runtime error when the value exceeds Int32.MaxValue.
Because
a) all object are limited to 2GB in .NET
b) You don't have 64 PetaBytes of memory to spend
According to Microsoft's documentation, with framework .NET 4.5 these limitations apply:
The maximum number of elements in an array is UInt32.MaxValue.
The maximum index in any single dimension is 2,147,483,591 (0x7FFFFFC7) for byte arrays and arrays of single-byte structures, and 2,146,435,071 (0X7FEFFFFF) for other types.
The maximum size for strings and other non-array objects is unchanged

Converting to int16, int32, int64 - how do you know which one to choose?

I often have to convert a retreived value (usually as a string) - and then convert it to an int. But in C# (.Net) you have to choose either int16, int32 or int64 - how do you know which one to choose when you don't know how big your retrieved number will be?
Everyone here who has mentioned that declaring an Int16 saves ram should get a downvote.
The answer to your question is to use the keyword "int" (or if you feel like it, use "Int32").
That gives you a range of up to 2.4 billion numbers... Also, 32bit processors will handle those ints better... also (and THE MOST IMPORTANT REASON) is that if you plan on using that int for almost any reason... it will likely need to be an "int" (Int32).
In the .Net framework, 99.999% of numeric fields (that are whole numbers) are "ints" (Int32).
Example: Array.Length, Process.ID, Windows.Width, Button.Height, etc, etc, etc 1 million times.
EDIT: I realize that my grumpiness is going to get me down-voted... but this is the right answer.
Just wanted to add that... I remembered that in the days of .NET 1.1 the compiler was optimized so that 'int' operations are actually faster than byte or short operations.
I believe it still holds today, but I'm running some tests now.
EDIT: I have got a surprise discovery: the add, subtract and multiply operations for short(s) actually return int!
Repeatedly trying TryParse() doesn't make sense, you have a field already declared. You can't change your mind unless you make that field of type Object. Not a good idea.
Whatever data the field represents has a physical meaning. It's an age, a size, a count, etc. Physical quantities have realistic restraints on their range. Pick the int type that can store that range. Don't try to fix an overflow, it would be a bug.
Contrary to the current most popular answer, shorter integers (like Int16 and SByte) do often times take up less space in memory than larger integers (like Int32 and Int64). You can easily verify this by instantiating large arrays of sbyte/short/int/long and using perfmon to measure managed heap sizes. It is true that many CLR flavors will widen these integers for CPU-specific optimizations when doing arithmetic on them and such, but when stored as part of an object, they take up only as much memory as is necessary.
So, you definitely should take size into consideration especially if you'll be working with large list of integers (or with large list of objects containing integer fields). You should also consider things like CLS-compliance (which disallows any unsigned integers in public members).
For simple cases like converting a string to an integer, I agree an Int32 (C# int) usually makes the most sense and is likely what other programmers will expect.
If we're just talking about a couple numbers, choosing the largest won't make a noticeable difference in your overall ram usage and will just work. If you are talking about lots of numbers, you'll need to use TryParse() on them and figure out the smallest int type, to save ram.
All computers are finite. You need to define an upper limit based on what you think your users requirements will be.
If you really have no upper limit and want to allow 'unlimited' values, try adding the .Net Java runtime libraries to your project, which will allow you to use the java.math.BigInteger class - which does math on nearly-unlimited size integer.
Note: The .Net Java libraries come with full DevStudio, but I don't think they come with Express.

Why is Array.Length an int, and not an uint [duplicate]

This question already has answers here:
Why does .NET use int instead of uint in certain classes?
(7 answers)
Closed 9 years ago.
Why is Array.Length an int, and not a uint. This bothers me (just a bit) because a length value can never be negative.
This also forced me to use an int for a length-property on my own class, because when you
specify an int-value, this needs to be cast explicitly...
So the ultimate question is: is there any use for an unsigned int (uint)? Even Microsoft seems not to use them.
Unsigned int isn't CLS compliant and would therefore restrict usage of the property to those languages that do implement a UInt.
See here:
Framework 1.1
Introduction to the .NET Framework Class Library
Framework 2.0
.NET Framework Class Library Overview
Many reasons:
uint is not CLS compliant, thus making a built in type (array) dependent on it would have been problematic
The runtime as originally designed prohibits any object on the heap occupying more than 2GB of memory. Since the maximum sized array that would less than or equal to this limit would be new byte[int.MaxValue] it would be puzzling to people to be able to generate positive but illegal array lengths.
Note that this limitation has been somewhat removed in the 4.5 release, though the standard Length as int remains.
Historically C# inherits much of its syntax and convention from C and C++. In those arrays are simply pointer arithmetic so negative array indexing was possible (though normally illegal and dangerous). Since much existing code assumes that the array index is signed this would have been a factor
On a related note the use of signed integers for array indexes in C/C++ means that interop with these languages and unmanaged functions would require the use of ints in those circumstances anyway, which may confuse due to the inconsistency.
The BinarySearch implementation (a very useful component of many algorithms) relies on being able to use the negative range of the int to indicate that the value was not found and the location at which such a value should be inserted to maintain sorting.
When operating on an array it is likely that you would want to take a negative offset of an existing index. If you used an offset which would take you past the start of the array using unit then the wrap around behaviour would make your index possibly legal (in that it is positive). With an int the result would be illegal (but safe since the runtime would guard against reading invalid memory)
I think it also might have to do with simplifying things on a lower level, since Array.Length will of course be added to a negative number at some point, if Array.Length were unsigned, and added to a negative int (two's complement), there could be messy results.
Looks like nobody provided answer to "the ultimate question".
I believe primary use of unsigned ints is to provide easier interfacing with external systems (P/Invoke and the like) and to cover needs of various languages being ported to .NET.
Typically, integer values are signed, unless you explicitly need an unsigned value. It's just the way they are used. I may not agree with that choice, but that's just the way it is.
For the time being, with todays typical memory constraints, if your array or similar data structure needs an UInt32 length, you should consider other data structures.
With an array of bytes, Int32 will give you 2GB of values

Categories

Resources