Arrays in C#
A basic data structure in C#, an array is used to hold a set number of literal values (elements) of the same data type. An array is made to retain several linked data items under a single name, as opposed to a standard variable, which only saves one value.
Key Characteristics of Arrays in C#
Homogeneous Collection: Regardless of whether they are reference types or primitive types, every element in an array must belong to the same data type.
Fixed Length: An array’s length, or the total number of entries, is fixed once it is instantiated and cannot be altered while the application is running.
Zero-Indexed: Index 0 is where array elements are numbered. For an array of N elements, the first member is at index 0, the second at index 1, and so on, up to N-1.
Contiguous Memory: The items of an array are sequentially stored in memory, with the first element having the lowest memory address and the last element having the highest.
Reference Types: As reference types in C#, arrays are objects that are derived from the abstract base type System.array. The heap is where they are kept.
Default Initialization: Like all variables in C#, dynamically allocated arrays are initialized to a default value by default (e.g., 0 for numeric types, null for reference types, and false for boolean types).
Automatic Bounds Checking: Automatic range-checking is done by C# compilers when accessing array elements. A System will appear if an invalid (non-existent) index is attempted to be accessed.Throwing an IndexOutOfRangeException. By avoiding memory access mistakes, which are common in languages like C++, this improves software robustness.
Types of Arrays in C#
Three primary array types are supported by C#:
Single-dimensional Arrays: With just one index needed to identify an element, they store elements in a linear form.
Multidimensional Arrays: These arrays, which have several dimensions (such as rows and columns), are also referred to as matrices. Up to 32 dimensions can be used in C#. For instance, [,] declares a two-dimensional array, and [,,] declares a three-dimensional array. They are declared by inserting commas inside the square brackets.
Jagged Arrays: Each inner array in these “arrays of arrays” may vary in size or dimension. A jagged array’s reference type elements are initially set to null by default.
Declaring and Initializing Arrays
Before being used, arrays need to be declared. The data type in the declaration is followed by square brackets [].
Declaration Syntax
dataType[] arrayName; // For single-dimensional
dataType[,] arrayName; // For two-dimensional
dataType[][,] arrayName; // For jagged array of two-dimensional arrays
Creation and Initialization
The new keyword is used when creating arrays. Curly braces {} can be used to initialise them at declaration time.
Single-dimensional Arrays
using System;
public class SingleDimensionalArrayExample
{
public static void Main(string[] args)
{
Console.WriteLine("--- Single-Dimensional Array Examples ---");
// Method 1: Declare, then Create (elements initialized to default)
int[] numbers; // Declaration
numbers = new int[5]; // Creation: Allocates space for 5 integers (defaulted to 0)
numbers[0] = 10; // Initialization of individual elements
numbers[1] = 20;
// numbers[2], numbers[3], numbers[4] remain 0
Console.WriteLine($"numbers[0]: {numbers[0]}"); // Output: 10
Console.WriteLine($"numbers[2]: {numbers[2]}"); // Output: 0
Console.WriteLine();
// Method 2: Declare and Create at once (elements initialized to default)
double[] prices = new double[3]; // Creates 3 doubles, initialized to 0.0
prices[0] = 1.99;
prices[1] = 5.49;
Console.WriteLine($"prices[0]: {prices[0]}"); // Output: 1.99
Console.WriteLine($"prices[2]: {prices[2]}"); // Output: 0.0
Console.WriteLine();
// Method 3: Declare and Initialize at once (using an array initializer)
string[] daysOfWeek = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" }; // Size is 7
Console.WriteLine($"daysOfWeek[0]: {daysOfWeek[0]}"); // Output: Mon
Console.WriteLine($"daysOfWeek[6]: {daysOfWeek[6]}"); // Output: Sun
Console.WriteLine($"Length of daysOfWeek: {daysOfWeek.Length}"); // Output: 7
Console.WriteLine();
// Method 4: Implicitly Typed Array (using 'var' - type inferred by compiler)
var temperatures = new [] { 25.5, 28.0, 22.3 }; // Compiler infers double[]
Console.WriteLine($"temperatures[1]: {temperatures[1]}"); // Output: 28
Console.WriteLine($"Type of temperatures: {temperatures.GetType()}"); // Output: System.Double[]
}
}
Output
--- Single-Dimensional Array Examples ---
numbers[0]: 10
numbers[2]: 0
prices[0]: 1.99
prices[2]: 0
daysOfWeek[0]: Mon
daysOfWeek[6]: Sun
Length of daysOfWeek: 7
temperatures[1]: 28
Type of temperatures: System.Double[]
Multidimensional Arrays
using System;
public class MultiDimensionalArrayExample
{
public static void Main(string[] args)
{
Console.WriteLine("--- Multi-Dimensional Array (Matrix) Examples ---");
// Method 1: Declare and Create (elements initialized to default)
// Creates a 3x4 integer matrix (3 rows, 4 columns)
int[,] matrix = new int[3, 4]; // All elements initialized to 0
// Initialize specific elements
matrix[0, 0] = 1; // Row 0, Column 0
matrix[0, 1] = 2; // Row 0, Column 1
matrix[1, 2] = 7; // Row 1, Column 2
matrix[2, 3] = 12; // Row 2, Column 3
Console.WriteLine($"matrix[0,0]: {matrix[0,0]}");
Console.WriteLine($"matrix[1,2]: {matrix[1,2]}");
Console.WriteLine($"matrix[0,2]: {matrix[0,2]}");
Console.WriteLine();
// Method 2: Declare and Initialize at once
// A 2x3 integer matrix
int[,] initializedGrid = {
{ 10, 20, 30 }, // Row 0
{ 40, 50, 60 } // Row 1
};
Console.WriteLine($"initializedGrid[0,2]: {initializedGrid[0,2]}");
Console.WriteLine($"initializedGrid[1,1]: {initializedGrid[1,1]}");
Console.WriteLine($"Number of rows: {initializedGrid.GetLength(0)}");
Console.WriteLine($"Number of columns: {initializedGrid.GetLength(1)}");
}
}
Output
--- Multi-Dimensional Array (Matrix) Examples ---
matrix[0,0]: 1
matrix[1,2]: 7
matrix[0,2]: 0
initializedGrid[0,2]: 30
initializedGrid[1,1]: 50
Number of rows: 2
Number of columns: 3
Jagged Arrays
using System;
public class JaggedArrayExample
{
public static void Main(string[] args)
{
Console.WriteLine("--- Jagged Array (Array of Arrays) Examples ---");
// Method 1: Declare the outer array, then create and assign inner arrays
// Declares an outer array that will hold 3 inner arrays
int[][] jaggedNumbers = new int[3][]; // Inner arrays are initially null
// Create and assign each inner array
jaggedNumbers[0] = new int[] { 1, 2, 3 }; // Inner array 0 has 3 elements
jaggedNumbers[1] = new int[] { 10, 20, 30, 40, 50 }; // Inner array 1 has 5 elements
jaggedNumbers[2] = new int[] { 100, 200 }; // Inner array 2 has 2 elements
Console.WriteLine($"jaggedNumbers[0][2]: {jaggedNumbers[0][2]}");
Console.WriteLine($"jaggedNumbers[1][4]: {jaggedNumbers[1][4]}");
Console.WriteLine($"jaggedNumbers[2][0]: {jaggedNumbers[2][0]}");
Console.WriteLine($"Length of inner array 1: {jaggedNumbers[1].Length}");
Console.WriteLine();
// Method 2: Declare and initialize a jagged array at once
int[][] anotherJaggedArray = new int[][]
{
new int[] { 5, 6 },
new int[] { 7, 8, 9, 10 },
new int[] { 11 }
};
Console.WriteLine($"anotherJaggedArray[0][1]: {anotherJaggedArray[0][1]}");
Console.WriteLine($"anotherJaggedArray[1][2]: {anotherJaggedArray[1][2]}");
Console.WriteLine($"anotherJaggedArray[2][0]: {anotherJaggedArray[2][0]}");
}
}
Output
--- Jagged Array (Array of Arrays) Examples ---
jaggedNumbers[0][2]: 3
jaggedNumbers[1][4]: 50
jaggedNumbers[2][0]: 100
Length of inner array 1: 5
anotherJaggedArray[0][1]: 6
anotherJaggedArray[1][2]: 9
anotherJaggedArray[2][0]: 11
Accessing Array Elements
The zero-based index for each element, wrapped in square brackets [], is used to access it directly.
using System; // Needed for Console.WriteLine
public class ArrayCorrectionExample
{
public static void Main(string[] args)
{
// 1. Single-dimensional Array
int[] numbers = { 10, 20, 30, 40, 50 }; // Indices: 0, 1, 2, 3, 4
// Issue 1: Console.WriteLine(numbers); prints the array's type, not its contents.
// Issue 2: Comment said "Accesses the first element: 10", but code would print "System.Int32[]"
// Corrected: Access the first element using its index [0]
Console.WriteLine($"Accessing the first element: {numbers[0]}");
Console.WriteLine(); // For better readability in output
// Issue 3: numbers[10] is an IndexOutOfRangeException because array size is 5 (indices 0-4).
// Issue 4: Comment said "Modifies the third element". The third element is at index 2.
// Corrected: Modify the third element (at index 2)
numbers[2] = 100; // Modifies the third element (original 30 becomes 100)
// Issue 5: numbers[10] would also cause an IndexOutOfRangeException.
// Corrected: Access the modified third element (at index 2)
Console.WriteLine($"Modified third element (numbers[2]): {numbers[2]}");
Console.WriteLine();
// Accessing multidimensional array elements
int[,] myMatrix = { {1, 2}, {3, 4} }; // This is a 2x2 matrix
// Indices: [0,0], [0,1]
// [1,0], [1,1]
// Issue 6: myMatrix[14] is incorrect syntax for multidimensional arrays.
// They require two indices: [row, column].
// Issue 7: Even if it were single-dimensional, index 14 is out of bounds for a 2x2 array.
// Corrected: Access an element using valid row and column indices.
Console.WriteLine($"Accessing myMatrix[0,1]: {myMatrix[0,1]}");
Console.WriteLine($"Accessing myMatrix[1,0]: {myMatrix[1,0]}");
Console.WriteLine();
// Accessing jagged array elements
// Issue 8: 'jaggedArray' was not declared or initialized in the provided snippet.
// Corrected: Declare and initialize a sample jagged array first.
int[][] jaggedArray = new int[2][]; // Outer array can hold 2 inner arrays
jaggedArray[0] = new int[] { 5, 6, 7 }; // First inner array
jaggedArray[1] = new int[] { 8, 9 }; // Second inner array
// Issue 9: jaggedArray[14] is an IndexOutOfRangeException.
// To access an element, you need two sets of brackets: [outer_index][inner_index].
// Corrected: Access an element using valid outer and inner indices.
Console.WriteLine($"Accessing jaggedArray[0][2]: {jaggedArray[0][2]}");
Console.WriteLine($"Accessing jaggedArray[1][0]: {jaggedArray[1][0]}");
Console.WriteLine();
}
}
Output
Accessing the first element: 10
Modified third element (numbers[2]): 100
Accessing myMatrix[0,1]: 2
Accessing myMatrix[1,0]: 3
Accessing jaggedArray[0][2]: 7
Accessing jaggedArray[1][0]: 8
You can also read What Are The C# Identifiers, Rules for Creating Identifiers
Iterating Through Arrays
There are several looping constructs that can be used to traverse arrays:
for
loop: This is frequently used when iterating a predetermined number of times or when you need to access elements by their index.
foreach
loop: This loop eliminates the need for explicit index management by immediately delivering the value of each element, making it easier to iterate over elements in arrays and collections. You cannot change the items directly within the body of a foreach loop because the iteration variable is read-only.
The System.Array
Class:
In C#, the abstract base class System is the implicit source of all arrays.array. For standard array operations, this class offers a wide range of methods and properties.
Common Properties of System.Array
:
Length
: Gives back a 32-bit value that indicates how many elements there are in the array across all dimensions.
Rank
: Gives back how many dimensions the array has.
IsFixedSize
: Shows whether the array’s size is fixed.
IsReadOnly
: Shows if the array is read-only or not.
Common Methods of System.Array
:
Sort()
: Sorts a one-dimensional array’s elements.
Reverse()
: Flips a one-dimensional array’s elemental order.
Copy()
: Copies the contents of one array to another.
Clear()
: A range of elements can be set to null, false, or zero.
IndexOf()
: Returns the index of the object’s initial occurrence after searching for the supplied object.
using System; // This line is necessary to use Array and Console classes
public class ArrayOperations
{
public static void Main(string[] args)
{
int[] data = { 34, 72, 13, 44, 25 };
Console.Write("Original Array: ");
foreach (int i in data)
{
Console.Write(i + " ");
}
Console.WriteLine(); // New line after printing original array
Array.Reverse(data); // Reverses the array in place
Console.Write("Reversed Array: ");
foreach (int i in data)
{
Console.Write(i + " ");
}
Console.WriteLine(); // New line after printing reversed array
Array.Sort(data); // Sorts the array in place (ascending)
Console.Write("Sorted Array: ");
foreach (int i in data)
{
Console.Write(i + " ");
}
Console.WriteLine(); // New line after printing sorted array
// Properties of the array
Console.WriteLine("Rank of sorted array: " + data.Rank);
Console.WriteLine("Length of sorted array: " + data.Length);
}
}
Output
Original Array: 34 72 13 44 25
Reversed Array: 25 44 13 72 34
Sorted Array: 13 25 34 44 72
Rank of sorted array: 1
Length of sorted array: 5
Passing Arrays as Function Arguments
A copy of the reference (pointer) to the array is passed when an array is passed as an argument to a method since arrays are reference types. This implies that the original array outside the function will be impacted by changes made to the array components inside the method. The elements’ values can be altered by the technique.
using System; // Required for Console.WriteLine
public class ArrayPassingExample
{
// The method signature is correct.
// 'arr' is a parameter that is a reference to the original array.
static void ModifyArray(int[] arr)
{
// Issue 1: arr = 999; is an error. 'arr' is an array reference,
// you cannot assign a single integer to it.
// Issue 2: To modify the ORIGINAL array, you must change one of its elements.
arr[0] = 999; // Correctly modifies the FIRST element of the array
// Issue 3: Printing just 'arr' prints its type name, not its value.
// Corrected: Print the element we just modified.
Console.WriteLine($"Inside method: arr[0] = {arr[0]}");
}
static void Main(string[] args)
{
int[] originalArray = { 10, 20, 30 };
// Issue 4: Printing 'originalArray' prints its type name.
// Corrected: Print the first element of the array.
Console.WriteLine($"Before method call: originalArray[0] = {originalArray[0]}");
ModifyArray(originalArray); // Pass the array reference
// Issue 5: The comment was wrong. The array's first element is now 999.
// Corrected: Print the first element after the method call.
Console.WriteLine($"After method call: originalArray[0] = {originalArray[0]}");
}
}
Output
Before method call: originalArray[0] = 10
Inside method: arr[0] = 999
After method call: originalArray[0] = 999
Methods can reassign the array variable itself (i.e., point to a new array object) by passing arrays to them using the ref and out keywords.
Unsafe Code and Pointers with Arrays
In an unsafe context, C# permits the use of pointers to access arrays in a manner similar to that of C. The fixed keyword is crucial when utilising pointers. In order to prevent the garbage collector from moving the object and invalidating any references to it, it instructs the C# compiler to “pin” the object in memory. The lack of automatic bounds checking when using pointers for array access is a noteworthy feature. This can result in speedier code, but it can also cause undefined behaviour or crashes if out-of-bounds access happens.
using System; // Required for Console.WriteLine
public class UnsafeArrayAccess
{
static void Main(string[] args)
{
int[] numbers = { 1, 2, 3, 4, 5 };
// The 'unsafe' keyword is necessary for using pointers
// To compile this, you must enable the 'Allow unsafe code' option in your project settings,
// or compile from the command line with 'csc /unsafe YourProgram.cs'
unsafe // Requires /unsafe compiler option
{
// Corrected: 'fixed' must point to a specific element's address
// '&numbers[0]' gets the memory address of the first element of the 'numbers' array.
fixed (int* ptr = &numbers[0]) // Pin the array in memory and get pointer to its first element
{
for (int i = 0; i < numbers.Length; i++)
{
// Access elements using pointer arithmetic
Console.WriteLine($"Element at index {i}: {*(ptr + i)}");
// Alternatively, you can use pointer indexing (syntactic sugar for pointer arithmetic)
// Console.WriteLine($"Element at index {i}: {ptr[i]}");
}
// Example of potential danger: Out-of-bounds access with pointer - no exception
// This will read/write memory outside the array bounds and can lead to crashes or data corruption.
// Console.WriteLine($"Potentially out-of-bounds access (e.g., ptr[10]): {ptr[10]}");
// The above line is commented out because it's dangerous and for demonstration of unsafe nature.
}
}
}
}
Output
main.cs(12,9): error CS0227: Unsafe code requires the `unsafe' command line option to be specified
Compilation failed: 1 error(s), 0 warnings
You can also read Understanding C# File I/O: Input and Output Operations