Array Declaration and Initialization

Vaibhav • September 9, 2025

Now that we know what an array is, it’s time to learn how to create one and put data into it. This article walks through the forms of declaration and initialization you’ll use every day, explains the subtle differences (allocation vs initialization, literal vs runtime construction), and highlights common pitfalls and useful patterns to keep your code correct and readable.

Two steps: declaration and allocation

Conceptually there are two separate concerns when bringing an array into existence:

  1. Declaration - telling the compiler you want a variable that will hold an array of a certain type, e.g. int[] numbers.
  2. Allocation (construction) - asking the runtime to reserve memory for the elements, usually via the new keyword, e.g. new int[5].
// declaration only (no allocation yet)
int[] numbers;

// declaration + allocation: an array of five integers
numbers = new int[5];

// declare + allocate in one line
int[] scores = new int[5];

Why separate them? Sometimes you declare a variable early (e.g., at top of a block) and allocate later when you know the size. The allocation step is what actually creates the array storage and sets default values.

Array initializers - concise literal syntax

When you know the elements at compile time, the initializer syntax is the shortest and clearest:

// three equivalent initializations
int[] a = new int[] { 1, 2, 3 };
int[] b = { 1, 2, 3 };              // shorthand initializer
var c = new[] { 1, 2, 3 };          // implicitly typed array (type inferred as int[])

Notes:

  • b uses the initializer shorthand - convenient for literals.
  • c uses var with new[] - the compiler infers the element type and yields an int[].

Default element values after allocation

When you allocate with new T[n], the runtime sets each element to the default value for the element type:

  • Numeric types → 0
  • boolfalse
  • Reference types (like string) → null
int[] five = new int[5];
Console.WriteLine(five[0]);       // 0 (default)
string[] s = new string[3];
Console.WriteLine(s[0] == null);  // True

Remember: allocation gives you storage initialized to defaults. Initialization with a literal sets explicit values at creation time.

Indexing, bounds and common runtime errors

Access elements using arr[index]. Indexing is zero-based in C#: the valid indices for new T[n] are 0..n-1. Attempting to access an invalid index throws IndexOutOfRangeException at runtime.

int[] xs = new int[3];   // valid indices: 0,1,2
xs[0] = 10;
xs[2] = 30;

// xs[3] = 40; // ❌ would throw IndexOutOfRangeException

Practical tip: always check length when indexing from a dynamic source: if (index >= 0 && index < array.Length).

Partially populating an array

You can allocate an array of a fixed size and then populate elements later - useful when size is known but content arrives progressively:

int[] buffer = new int[4];   // [0,0,0,0]
buffer[0] = 5;                   // [5,0,0,0]
buffer[3] = 20;                  // [5,0,0,20]

This pattern is common for fixed-size buffers (temporary data, small lookup tables). If the number of elements varies widely, later chapters show dynamic collections that avoid manual resizing.

Formatting long initializers for readability

When you have many literal elements, prefer multi-line initializer formatting for clarity:

int[] primes = new int[]
{
    2,
    3,
    5,
    7,
    11,
    13
};

Type rules and syntax variations

A couple of syntax notes that matter in practice:

  • Preferred declaration style: int[] numbers (the brackets bind to the element type).
  • C# also accepts int numbers[] (C-style), but it’s less idiomatic in C# codebases.
  • Initializer shorthand ({ ... }) can only be used at declaration time (not on a previously declared variable without new).

Example: int[] x; x = {1,2,3}; is invalid. Use x = new int[] {1,2,3}; or initialize at declaration.

Arrays are reference types - what that implies

In C#, arrays are reference types. That means the variable you write holds a reference to the array storage (the contiguous block in memory), not the elements themselves inline. A second variable can point to the same array:

int[] a = { 1, 2, 3 };
int[] b = a;   // b references the same array as a
b[0] = 99;
Console.WriteLine(a[0]); // 99 (visible through a)

This sharing is powerful but requires care: mutating a shared array affects all references that point to it. If you need an independent copy, you must explicitly copy elements (covered in later chapters).

Common beginner pitfalls

  • Confusing declaration vs initializer: make sure to use the correct form when you both declare and initialize.
  • Index out of range: always validate indices or iterate using the array's Length.
  • Assuming resizing is free: arrays are fixed-size; resizing requires creating a new array and copying data.
  • Unintended sharing: assigning one array variable to another copies the reference, not the contents.

Prefer the initializer shorthand for fixed known data (int[] months = {1,2,3}). When you allocate a fixed buffer, explicitly document expected size and usage so readers know whether the array is intended to be filled later or to remain sparse.

Practice exercises

  • Create an array of five integers, populate them with sample values, and print the sum using a loop.
  • Allocate an array of length 10, fill every even index with its index value, and print the array contents.
  • Experiment with assigning one array variable to another, modify one, and observe the effect on both references.

Summary

Declaration tells the compiler you want an array variable; allocation (via new) reserves memory and sets default element values. Use initializer syntax for literal data, be mindful of bounds, remember that arrays are fixed-size and reference types, and format long initializers for readability. In the next article we’ll cover indexing and access patterns, iteration strategies, and safe iteration idioms you can rely on in production code.