11. Array
An array is the most basic collection — fixed-size storage of same-typed elements in a row. Cover 1-D, multi-dim, jagged arrays, the static Array methods, and foreach usage.
What you'll learn
- 1Declare and initialize 1-D arrays and access by index
- 2Build a 2-D array (`int[,]`) and get its dimensions with `GetLength`
- 3Use static methods like `Array.Sort`, `IndexOf`, `Reverse`, `Copy`
- 4Get a one-sentence intuition for `Span<T>` / `ReadOnlySpan<T>` and why it exists
Overview
An array is the most basic data structure that stores values of the same type in a row at a **fixed size**. C# supports 1-D and 2-D arrays, and you can do many operations efficiently with the `Array` class's static methods or modern tools like `Span<T>`.
Core Concepts
1) Array declaration and collection expressions
In .NET 8 you can initialize concisely with **collection expressions** `[...]`.
int[] a = [1, 2, 3, 4, 5]; // collection expression (.NET 8+)
int[] b = { 1, 2, 3 }; // traditional form
int[] c = new int[5]; // length-5 array, zero-filled- Indices are **0-based**; the last index is `Length - 1`.
- `^1` is the first from the end (= `Length - 1`).
2) 2-D array
int[,] grid = new int[3, 4]; // 3 rows, 4 cols
grid[1, 2] = 99;
int rows = grid.GetLength(0); // 3
int cols = grid.GetLength(1); // 4`int[][]` is a **jagged array** where rows can have different lengths. `int[,]` is rectangular.
3) Static `Array` methods
| Method | Description |
|---|---|
| `Array.Sort(arr)` | Sort ascending (in place) |
| `Array.Reverse(arr)` | Reverse order |
| `Array.IndexOf(arr, value)` | Index of first match, `-1` if missing |
| `Array.Copy(src, dst, length)` | Copy the first `length` elements |
4) `Span<T>` / `Memory<T>` intro
`Span<T>` is a thin wrapper that **points to a slice of an array/string without copying**. Saves memory and time since it avoids a new allocation.
ReadOnlySpan<char> slice = "hello".AsSpan(1, 3); // "ell"For now, just remember "efficient slicing." Advanced usage is left for a later topic.
Examples
Example 1 — `ArrayBasics`: 1-D array basics
int[] scores = [85, 92, 78, 90, 88];
Console.WriteLine($"Length: {scores.Length}");
Console.WriteLine($"First: {scores[0]}");
Console.WriteLine($"Last: {scores[^1]}");
int sum = 0;
foreach (int s in scores)
{
sum += s;
}
Console.WriteLine($"Sum: {sum}");**Output**
Length: 5
First: 85
Last: 88
Sum: 433**Note:** `^1` is "1st from the end" — the index-from-end operator introduced in C# 8.
Example 2 — `Array2D`: working with 2-D arrays
int[,] grid = new int[3, 4];
for (int r = 0; r < grid.GetLength(0); r++)
{
for (int c = 0; c < grid.GetLength(1); c++)
{
grid[r, c] = r * 10 + c;
}
}
for (int r = 0; r < grid.GetLength(0); r++)
{
for (int c = 0; c < grid.GetLength(1); c++)
{
Console.Write($"{grid[r, c],3} ");
}
Console.WriteLine();
}**Output**
0 1 2 3
10 11 12 13
20 21 22 23**Note:** `GetLength(0)` is the row count, `GetLength(1)` the column count. `{value,3}` is a 3-wide right-aligned format.
Example 3 — `ArrayMethods`: static `Array` methods
int[] nums = [4, 2, 9, 1, 7];
Array.Sort(nums);
Console.WriteLine($"Sorted: [{string.Join(", ", nums)}]");
Array.Reverse(nums);
Console.WriteLine($"Reversed: [{string.Join(", ", nums)}]");
int idx = Array.IndexOf(nums, 7);
Console.WriteLine($"Index of 7: {idx}");
int[] copy = new int[3];
Array.Copy(nums, copy, 3);
Console.WriteLine($"First 3 copied: [{string.Join(", ", copy)}]");**Output**
Sorted: [1, 2, 4, 7, 9]
Reversed: [9, 7, 4, 2, 1]
Index of 7: 1
First 3 copied: [9, 7, 4]**Note:** `Array.Sort` mutates the **original in place** (returns nothing). Use `string.Join` to pretty-print an array.
Example 4 — `SpanIntro`: slicing with `ReadOnlySpan<char>`
ReadOnlySpan<char> text = "Hello, World!".AsSpan();
ReadOnlySpan<char> hello = text.Slice(0, 5);
ReadOnlySpan<char> world = text.Slice(7, 5);
Console.WriteLine(hello.ToString());
Console.WriteLine(world.ToString());
// Unlike Substring, no new string is allocated — it points into the source.
Console.WriteLine($"Source length: {text.Length}, slice length: {hello.Length}");**Output**
Hello
World
Source length: 13, slice length: 5**Note:** `string.Substring` allocates a new string every time; `Span` shares memory. Useful in heavy text parsing.
Full example code (src/)
src/Array2D/Array2D.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Coll11</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
src/Array2D/Program.cs
#nullable enable
// 3-row, 4-col rectangular array
int[,] grid = new int[3, 4];
for (int r = 0; r < grid.GetLength(0); r++)
{
for (int c = 0; c < grid.GetLength(1); c++)
{
grid[r, c] = r * 10 + c;
}
}
// Print as a table
for (int r = 0; r < grid.GetLength(0); r++)
{
for (int c = 0; c < grid.GetLength(1); c++)
{
Console.Write($"{grid[r, c],3} ");
}
Console.WriteLine();
}
src/ArrayBasics/ArrayBasics.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Coll11</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
src/ArrayBasics/Program.cs
#nullable enable
// Build an array with a collection expression (.NET 8+)
int[] scores = [85, 92, 78, 90, 88];
Console.WriteLine($"Length: {scores.Length}");
Console.WriteLine($"First: {scores[0]}");
Console.WriteLine($"Last: {scores[^1]}"); // 1st from the end
int sum = 0;
foreach (int s in scores)
{
sum += s;
}
Console.WriteLine($"Sum: {sum}");
src/ArrayMethods/ArrayMethods.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Coll11</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
src/ArrayMethods/Program.cs
#nullable enable
int[] nums = [4, 2, 9, 1, 7];
Array.Sort(nums); // in-place sort
Console.WriteLine($"Sorted: [{string.Join(", ", nums)}]");
Array.Reverse(nums); // reverse order
Console.WriteLine($"Reversed: [{string.Join(", ", nums)}]");
int idx = Array.IndexOf(nums, 7); // index of value
Console.WriteLine($"Index of 7: {idx}");
int[] copy = new int[3];
Array.Copy(nums, copy, 3); // copy first 3
Console.WriteLine($"First 3 copied: [{string.Join(", ", copy)}]");
src/SpanIntro/Program.cs
#nullable enable
ReadOnlySpan<char> text = "Hello, World!".AsSpan();
// Point to a portion of the source without creating a new string
ReadOnlySpan<char> hello = text.Slice(0, 5);
ReadOnlySpan<char> world = text.Slice(7, 5);
Console.WriteLine(hello.ToString());
Console.WriteLine(world.ToString());
Console.WriteLine($"Source length: {text.Length}, slice length: {hello.Length}");
src/SpanIntro/SpanIntro.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Coll11</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
Common Mistakes
- Accessing the last+1 index like `arr[arr.Length]` → `IndexOutOfRangeException`.
- Accessing a 2-D array as `grid[1][2]` — for `int[,]` it's `grid[1, 2]`. (`grid[1][2]` is for `int[][]`.)
- Thinking `Array.Sort` returns a new array — it **mutates the original** (returns `void`).
- `int[]` size is fixed once set — for variable length, use `List<T>` from the next lecture.
- `Span<T>` can't cross an `await` in an async method — its usage has limits.
Summary
- Arrays are **same-type, fixed-length** data structures; the collection expression `[1, 2, 3]` makes them concise.
- 2-D arrays use `int[,]` with `GetLength(0/1)` for dimensions.
- Common operations live as `Array` static methods (`Sort`, `IndexOf`, `Reverse`, `Copy`).
- `Span<T>` is the modern tool for slicing without copying.
Practice
**Practice - 11. Array**
Problem 1 — max / min / average
- Project folder: `Homework01/`
- Key concepts: 1-D array, `foreach`, accumulation
Requirements
- Use `int[] data = [42, 17, 89, 23, 65, 8, 50];`.
- Iterate to compute and print **max, min, average** by hand. (`Math.Max` / `Math.Min` are fine.)
- Print the average to one decimal (`F1`).
Expected output
Array: [42, 17, 89, 23, 65, 8, 50]
Max: 89
Min: 8
Average: 42.0Hints
- Seed with `data[0]` and compare from index 1 — that's cleanest.
- Average is `(double)sum / data.Length` — cast to `double` to avoid integer division.
---
Problem 2 — 2-D matrix transpose
- Project folder: `Homework02/`
- Key concepts: `int[,]`, `GetLength`, nested for loops
Requirements
- Create the 2x3 matrix below.
``` 1 2 3 4 5 6 ```
- **Transpose** it into a 3x2 matrix and print it.
- Print both the original and the transposed result as tables.
Expected output
Original (2x3):
1 2 3
4 5 6
Transposed (3x2):
1 4
2 5
3 6Hints
- Build the transposed array as `new int[orig.GetLength(1), orig.GetLength(0)]`.
- The key one-liner is `transposed[c, r] = original[r, c];`.
Check your answer
Try it yourself, then compare against the [`answer/`](./answer/) folder.
Answer (answer/)
homework/answer/Homework01/Homework01.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Coll11</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
homework/answer/Homework01/Program.cs
#nullable enable
int[] data = [42, 17, 89, 23, 65, 8, 50];
int max = data[0];
int min = data[0];
int sum = 0;
foreach (int n in data)
{
max = Math.Max(max, n);
min = Math.Min(min, n);
sum += n;
}
double avg = (double)sum / data.Length;
Console.WriteLine($"Array: [{string.Join(", ", data)}]");
Console.WriteLine($"Max: {max}");
Console.WriteLine($"Min: {min}");
Console.WriteLine($"Average: {avg:F1}");
homework/answer/Homework02/Homework02.csproj
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<RootNamespace>CodingNow.Lecture.Coll11</RootNamespace>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>
homework/answer/Homework02/Program.cs
#nullable enable
int[,] original = { { 1, 2, 3 }, { 4, 5, 6 } };
int rows = original.GetLength(0);
int cols = original.GetLength(1);
int[,] transposed = new int[cols, rows];
for (int r = 0; r < rows; r++)
{
for (int c = 0; c < cols; c++)
{
transposed[c, r] = original[r, c];
}
}
Print("Original (2x3):", original);
Console.WriteLine();
Print("Transposed (3x2):", transposed);
static void Print(string title, int[,] m)
{
Console.WriteLine(title);
for (int r = 0; r < m.GetLength(0); r++)
{
for (int c = 0; c < m.GetLength(1); c++)
{
Console.Write($"{m[r, c]} ");
}
Console.WriteLine();
}
}
Try It Yourself
cd src/ArrayBasics
dotnet run
cd ../Array2D
dotnet run
cd ../ArrayMethods
dotnet run
cd ../SpanIntro
dotnet runNext Lecture
[12_List_Dictionary_HashSet](../12_List_Dictionary_HashSet/) — Variable-length collections and key-value stores.
All lecture materials and example code are openly available on GitHub.
View on GitHub ↗