Author avatar

Pavneet Singh

Deep Dive into Array Basics Part 1

Pavneet Singh

  • Aug 28, 2018
  • 17 Min read
  • Aug 28, 2018
  • 17 Min read


Data management is the backbone of all applications. The performance of an application is significantly dependent upon the choice of data structure to access and manipulate data. Every data structure has its own implementation and implications.

In earlier times, CPU's were specifically optimized to work with instruction sets that operate on one-dimensional data, known as vector processing. Modern GPUs are a modified version of a vector processor to support rapid computation.

Arrays (AKA Vectors) are the most important and widely used data-structure and this guide will cover the deep aspects of array data-structure.

Introduction to Arrays

An array is defined as a collection of similar data with fixed length, stored in a linear fashion. Every element in an array is accessed by an index (a numerical value) and every index can be computed by applying a mathematical operation.

In the below example

  • Book is an array
  • Chapters are the data stored inside the Book
  • Every chapter in the Book array is accessible with an index


1char[] book = {'A','B','C','D'};

Array Declarations and Initialization

Declaration is a process of defining a place holder name preceded by it's type and arrays are declared with rectangular brackets as

1type[] name_of_placeholder;
2char[] book;

Initialization means to allocate memory to objects with the help of new keyword or array initializer.

1name_of_placeholder = new data_type[size_of_array];
2book = new char[4];

Array Initializers: Arrays can also be declared using initialization list {array elements separated by comma} and suitable when you have the data while declaring array reference. e.g. create array of length 4 with values as A, B, C, D.

1char[] array = new char[] {'A','B','C','D'};
2char[] array = {'A','B','C','D'};
3char[] array = new[] {'A','B','C','D'};

Implicit typed array: var is the variable type placeholder (introduced in C# 3) whose type can be obtained from the right side of the expression using type inference which allows us to eliminate the explicit data type. The above examples can be declared using var as:

1var array = new char[4]; // creates array of length 4
2var array = new char[4] {'A','B','C','D'};
3var array = new char[] {'A','B','C','D'};
4var array = new[] {'A','B','C','D' };

An array initializer cannot be used with the var keyword, so var array = { 'A', 'B' , 'C', 'D' }; is invalid. The decision was made by the design team to avoid the use of array initializer and its side effects on the parser to avoid parsing nested blocks of {}. The solution was the usage of new keyword with var for implicit types syntax.

Memory Allocation

The main memory is divided into separate logical sections and a heap is known as dynamic memory. Meaning that memory requested at runtime is allocated in heap.

Memory for arrays is allocated in a continuous manner. Meaning that if you create an array of four char elements then the application will allocate: On 32 bit OS, char is of 2 byte and 4 byte for reference variable so (2 * 4) + 4 = 12 bytes On 64 bit OS, char is of 2 byte and 8 byte for reference variable so (2 * 4) + 8 = 16 bytes and may be stored at memory address 2000 to 2008 (2008 is exclusive), look like this:

1index    Data      Memory addresses
2       _____
30     |  A  |     4000  <=  name of the array
4      |_____|               pointing to initial address
51     |  B  |     4002
6      |_____|
72     |  C  |     4004
8      |_____|
93     |  D  |     4006
10      |_____|

This is a general scenario, the actual allocation might slightly differ according to OS implementation.

Read and Write

The value of an array is read by using the array name followed by index within rectangular brackets:

2e.g       output
3book[2]     C

The memory address of C can be computed using initial address of memory, index and size:

1initial address + (index * size of data type)
24000            + (2 * 2)
34000            +    4
4=> 4004

In order to modify array elements, an assignment(=) operator is used along with the array name and index:

1array_name[numeric_index] = new_element
2book[0]  =  'P' // Replace A with P

A modified book array will be:


Important: There are two types of data in C#:

  1. Value Type: ValueType elements always have a fixed default value when initialized e.g. The default value of an int element is 0 and bool is false.

  2. Reference Type: The default value of reference type is null.

Array fundamentals

  • Zero-based numbering: Array index always starts at 0 and the value of the last index will be length_of_array - 1.

  • Fix length: Once an array is created, its size cannot be altered to increase the length. A larger array is required to store the values from the smaller array using a copy operation.

  • By default, every element in array is initialized to their default value.

  • Every array object is derived from Array class and inherits the data member (length,Rank) and methods (GetLowerBound, GetUpperBound) of the Array class.

  • An array can also represent matrix data as a two dimensional, multi-dimensional, or jagged array. In a jagged array, the size of each row can be different and can be defined at run time as per requirement.

  • The default maximum size of an Array is two gigabytes (GB) in a 32 bit environment and in a 64 bit environment, gcAllowVeryLargeObjects method can be invoked to expand the limit to four billion entries.

  • Arrays are not thread safe; multiple-threads can modify the data at the same type which can cause inconsistency issues.

Array Class and Structure of an Array

Every array variable has Array class as the base type and can access the properties and methods. In C or C++, you cannot get the array length from the array object, so being an object type of a class allows array objects to store additional information like length, IsReadOn, and helpful methods like Clone and Equals.

Clone will provide a shallow copy which is suitable for one dimensional arrays. For a multi-dimensional array, you need to copy each and every element from the source array to the newarray. This is known as deep copy.

  • Array class: An array class implements various methods from interfaces to provide a fixed set of features for consistency across any supported framework and platform.

  • IList: To support collections like dynamic list with no size limit, supported by using System.Linq which is used to convert data from one type to another.
1using System.Linq;
3int[] intArr = new [] { 11, 2, 0, 14, 112 };
4List<int> intList = intArr.OfType<int>().ToList(); // convert array to List
  • ICloneable: To support clone method.
1int[] arr = new int[2];
2int[] temp = (int[])arr.Clone();
  • IStructuralEquatable: To compare array values as per index.
1StructuralComparisons.StructuralEqualityComparer.Equals(new int[]{1,2}, new int[]{2,1}); // False
3StructuralComparisons.StructuralEqualityComparer.Equals(new int[]{1,2}, new int[]{1,2}); // True
  • IStructuralComparable: To support methods like sort to define the order or create customize ordering.
1StructuralComparisons.StructuralComparer.Compare(new int[]{1,2}, new int[]{2,1}); // -1 first comes before in a second
3StructuralComparisons.StructuralComparer.Compare(new int[]{1,2}, new int[]{1,2}); // 0 both are equals
5StructuralComparisons.StructuralEqualityComparer.Equals(new int[]{2,1}, new int[]{1,2}); // 1, first comes after second

Array Traversal

Traversal is the process of accessing each element of an array to perform a read or update operation. To print the book array, you can write:

1Console.WriteLine("["+book[0]+","+book[1]+","+book[2]+","+book[3]+"]"); // direct access
2Console.WriteLine("[{0},{1},{2},{3}]",book[0],book[1],book[2],book[3]); // interpolated string
3Console.WriteLine("[{0}]", string.Join(",", book)); // get array string and use comma as separator
5[A,B,C,D] // for all 3 statements

As you can observe, the only dynamic part to access the array is the index value. So, we just need to execute the book[index_value] statement with an index value in an increasing order. This can be achieved by simply using for loop.

Loops allow us to execute the same set of instructions several times in a defined sequence. A simple for loop syntax is:

1for(int i = initial_value ; exit_condtion ; increment/decrement){
2  // statement

Below is a simple program to replace the value of book array with any random alphabet:

1Random rand = new Random();
3for(int i = 0 ; i < book.Length ; i++){
4  // Note : FormattableString string instance is reused to display new values
5  Console.Write("book[{0}] = {1}",i,book[i]);
6  // random number between 0 - 25
7  int randomOndex = rand.Next(strA_Z.Length);
8  // replace element with random alphabet
9  book[i] = strA_Z[randomOndex];
10  Console.WriteLine(" : book[{0}] = {1}",i,book[i]);
12Output: Its random, so output may differ
13book[0] = A : book[0] = H
14book[1] = B : book[1] = U
15book[2] = C : book[2] = G
16book[3] = D : book[3] = O

Note: String objects can be used as an array because of inbuilt indexer support in string class.

Use of Out, Ref, and Param Keyword

Arrays can be passed from one method to another as a parameter to process array data. Passing an array as a parameter means the callee method can only access or manipulate the array data but cannot assign a new array object to the passed array reference.

Note: Caller is the method that calls another method - e.g. Main is a caller and ChangeReference is a callee method, invoked by Main method.

For example:

1static void Main(string[] args){
2  char[] book = new[]{'A','B','C','D'};
3  Console.WriteLine("[{0}]",string.Join(",",book)); // [A,B,C,D]
4  ChangeReference(book); // no change after this executes
5  Console.WriteLine("[{0}]",string.Join(",",book)); // [A,B,C,D]
7static void ChangeReference(char[] book){
8  Console.WriteLine("[{0}]",string.Join(",",book)); // [A,B,C,D]
9  book = new[]{'W','X','Y','Z'};

In the above example, the book array is passed to another method where a new array object is assigned to the book reference. Though this will not change the original book reference pointing to A,B,C,D, the ChangeReference method can access or modify the elements inside of the book array.

There is the possibility that an uninitialized array could be passed or that a method needs to initialize the array reference before using it and make the changes that reflect in the caller method. Fortunately, C# introduced keywords like ref and out in version 7 to apply constrains on references at compilation time.


out indicates to the compiler that the received array reference (in callee method) should be initialized before use and if you try to use the array reference before initialization then it will cause a compilation error.

1static void Main(string[] args){
2  char[] book = new[]{'A','B','C','D'};
3  Console.WriteLine("[{0}]",string.Join(",",book)); // [A,B,C,D]
4  ChangeReference(out book);
5  Console.WriteLine("[{0}]",string.Join(",",book)); // [W,X,Y,Z]
6  ChangeReference(out null); // compile time error, un-assignable reference
7  ChangeReferenceErr(out book);
9static void ChangeReference(out char[] book){
10  book = new[]{'W','X','Y','Z'};
12static void ChangeReferenceErr(out char[] book){
13  Console.WriteLine("[{0}]",string.Join(",",book)); // compilation error, Cannot use before initialization
14  book = new[]{'W','X','Y','Z'}; // do this before using book


  • The passed reference should be an assignable reference, meaning you cannot pass null as a parameter with out although you can assign null value to reference inside callee method.

  • It doesn't matter whether the array reference was initialized before or not, the callee method has to initialize the reference before using it.


ref acts as a constraint so that the array reference should be initialized before passing it to another method.

1static void Main(string[] args){
2  char[] book = new[]{'A','B','C','D'};
3  PrintArrayValues(ref book); // [A,B,C,D]
4  char[] bookNull;
5  PrintArrayValues(ref bookNull); // compile time error, use of unassigned local variable
6  char[] upComingBooks = null;
7  PrintArrayValues(ref upComingBooks); // Runtime error, ArgumentNullException, because books is null
9static void PrintArrayValues(ref char[] book){
10  Console.WriteLine("[{0}]",string.Join(",",book));


  • Caller method can initialize the reference as null which will crash the application if you perform any operation which required a not-null reference

  • ref is useful when one method wants to send data and receive modified data; it's two way communication. Whereas out is one way communication every time a reference should be initialized

  • ref and out are also applicable on value type data

  • A method cannot be overloaded on the basis of ref and out
1static void add (ref int a){}
2static void add (out int a){} // compilation error, ref and out are not enough to overload a method


The params keyword allows us to receive any arbitrary number of parameters as an array.

1static void Main(string[] args){
2  TotalAnyLengthArray(1,2,3);          // 6
3  TotalAnyLengthArray(1,2,3,3,4,5,5);  // 23
4  TotalAnyLengthArray();               // 0
6static void TotalAnyLengthArray(params int[] ints){
7 long sum = 0;
8 for(int i = 0 ; i < ints.Length ; i++){
9     sum += ints[i];
10 }
11 Console.WriteLine("Total is {0}",sum);

You can pass separate int parameters by keeping params as the last parameter:

1static void Main(string[] args){
2  TotalAnyLengthArrayAndVerify(6,1,2,3);           // True
3  TotalAnyLengthArrayAndVerify(20,1,2,3,3,4,5,5);  // False, total is 23 not 20
5static void TotalAnyLengthArrayAndVerify(int expectedTot, params int[] ints){
6 long sum = 0;
7 for(int i = 0 ; i < ints.Length ; i++){
8     sum += ints[i];
9 }
10 Console.WriteLine("Match is {0}", sum == expectedTot);

Key Points

  • Arrays index starts from 0 and type of data can be restricted by the type of the array.
1object[] all = new object[]{1,true,""}; // object can store any type
2object[] listInt = new int[] {1, 2}; // not possible
  • Looping an array is almost twice as fast as lists.

  • Never compare reference type with == . Instead, use SequenceEqual with arrays as:
1char[] nName = new[]{'P', 'A', 'V' };
2Console.WriteLine(nName == new char[]{'P','A','V'}); // False
3Console.WriteLine(nName.SequenceEqual(new char[]{'P','A','V'})); // True
  • It's good practice to return an empty array instead of null (to avoid null checks) in case there is an issue with data availability or consistency.
1char[] a = new char[]{}; // create empty array
  • You can convert char array to string to perform string manipulations.
1char[] chars = {'P','A','V','N','E','E','T'};
2string name = new string(chars); //PAVNEET

Share your appreciation and press like on this guide. Thank you for reading!