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:
- Declaration - telling the compiler you want a variable that will hold an array of a certain
type, e.g.
int[] numbers
. - 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
usesvar
withnew[]
- the compiler infers the element type and yields anint[]
.
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
bool
→false
- 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 withoutnew
).
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.