CodeGym /Courses /C# SELF /Advanced Array Handling

Advanced Array Handling

C# SELF
Level 7 , Lesson 2
Available

1. Array of type string

So, real quick, let's talk about arrays of type string.

Like we already said, an array can be of any type. Which means you can totally create an array of type string. Here’s what the code would look like if we needed to write a program that "reads 10 strings from the keyboard and prints them in reverse order."

string[] array = new string[10];	// Create an array object with 10 elements
for (int i = 0; i < 10; i++)		// Loop from 0 to 9
{
   array[i] = Console.ReadLine();	// Read a string from the keyboard and save it in the array cell
}
for (int i = 9; i >= 0; i--)		// Loop from 9 to 0
{
    Console.WriteLine(array[i]);	// Print the current array cell to the screen
}

The code barely changed! The only thing we had to do was swap the int type for string when creating the array. Everything else is exactly the same!

2. string array in memory

And here’s another useful fact. Check out these 3 pics:

Picture 1. How a string object is stored in memory:

string array in memory

Notice that the text of the string isn’t stored right in the variable: it gets its own separate memory block. And the string variable just stores the address (reference) to the object with the text.

Picture 2. How an int array is stored in memory:

int array in memory

You’ve seen this pic before too.

Picture 3. How a string array is stored in memory:

How a string array is stored in memory

On the left, we see a variable-array of type string[] (it stores the address of the array object).
In the middle — the array object of type string.
And on the right — string objects that store some texts.

The cells of the array object of type string don’t store the strings (texts) themselves, but their addresses (references). Just like variables of type string store the addresses of strings (text).

3. Quick array initialization in C#

Arrays are super useful, so the C# devs tried to make working with them as convenient as possible. The first thing they did was make array initialization easier, so you can set up starting values right away.

Because a lot of the time, besides data your program reads from somewhere, it also needs its own internal data. For example, let’s say we need to store the lengths of all the months in an array. Here’s what that code might look like:

int[] months = new int[12];
months[0] = 31; // January
months[1] = 28; // February
months[2] = 31; // March
months[3] = 30; // April
months[4] = 31; // May
months[5] = 30; // June
months[6] = 31; // July
months[7] = 31; // August
months[8] = 30; // September
months[9] = 31; // October
months[10] = 30; // November
months[11] = 31; // December

But there’s a shorter way to write this — thanks to the C# creators:

// month lengths of the year
int[] months = new int[] { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

You can just list all the array values separated by commas!

Pretty handy, right? But wait, there’s more.

Turns out the compiler can figure out the container type (the array object) based on the array variable type. And to figure out the array length — it just counts the number of elements in the curly braces.

So you can write the code even shorter:

// month lengths of the year
int[] months = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };

Isn’t that sweet? 🙂

This is called "quick array initialization." And by the way, it works not just for int...

// month names of the year
string[] months = { "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"};

4. The foreach loop

Looping through all the elements of an array is such a common thing that there’s a special loop for it(!). It’s called foreach. Here’s how it looks:


foreach (int score in scores)
{
    Console.WriteLine($"Points: {score}");
}
        
Looping through array elements with foreach

Here, the loop itself goes through the elements — no manual index needed. You can’t change the elements directly (they’re read-only in the loop), but it’s super convenient for just walking through the array.

The compiler will turn the foreach loop code into this:


for (int i = 0; i < scores.Length; i++)
{
    int score = scores[i];
    Console.WriteLine($"Points: {score}");
}
        
How foreach works "under the hood"

So, no magic here. Now it’s clear why you can’t change array elements through the score variable.

Let’s write another example: let’s find the sum of all the points.


int sum = 0;
foreach (int score in scores)
{
    sum += score;
}
Console.WriteLine($"Sum of all points: {sum}");
        
Summing array elements with foreach

When should you use which loop?

  • If you need the index or want to change elements — use a for loop.
  • If you just want to walk through the values — foreach is faster and cleaner.

5. End-indexing: the ^ operator

For a while now in C#, you can get elements from the end of an array. Back in the day, if you wanted the last element, you’d write something like:


int lastScore = scores[scores.Length - 1];
        
Getting the last element of an array the old-school way

Now it’s way easier. Just put the ^ operator before the index, and it counts from the end:


int lastScore = scores[^1];        // Last element
int penultimate = scores[^2];      // Second-to-last element
        
End-indexing with ^
  • ^1 — that’s the first from the end (the last one).
  • ^2 — second from the end.

Visualization

Index Value in scores array Regular index End index
0 10 0 ^5
1 15 1 ^4
2 8 2 ^3
3 22 3 ^2
4 17 4 ^1

score[^1] = 17, score[^2] = 22 — easy and clear.

Important! Notice that end indexes start from 1, not zero.

6. Ranges: the .. operator

Sometimes you need to get a subarray from the original array. In C#, you can use the special range operator .. — it’s a short and super handy way to get the "slice" you want.

This subarray is sometimes called a slice, and it’s defined by two boundaries: start and end.
Heads up: the right boundary is NOT included in the result!

What it looks like


int[] scores = { 10, 15, 8, 22, 17 };
int[] top3 = scores[0..3]; // Take elements from 0 to 2: {10, 15, 8}
        
Getting an array slice with ..
  • scores[0..3] — we take elements from index 0 (inclusive) up to index 3 (NOT inclusive).
  • The resulting array will have elements with indexes 0, 1, and 2.

Shortcuts

If the left boundary isn’t specified, you start from the very beginning:


int[] firstTwo = scores[..2]; // same as scores[0..2], so {10, 15}
        

If the right boundary isn’t specified, you go all the way to the end:


int[] fromThird = scores[2..]; // {8, 22, 17}
        

Negative indexes

With the ^ symbol, you can count indexes from the end:


int[] lastTwo = scores[^2..]; // {22, 17}
        

Here, ^2 means "second element from the end."

You can also take a range "from and to" using negative indexes on both sides:


int[] mid = scores[1..^1]; // {15, 8, 22} (from the 2nd to the penultimate)
        

What you need to remember

  • The right edge is always not included — so if you write a..b, you get all elements from a to b-1.
  • If you set boundaries that go outside the array, you’ll get an IndexOutOfRangeException.
  • A slice is a new array, the original doesn’t change. Any changes in the new array won’t affect the original.

Practical examples

int[] arr = { 1, 2, 3, 4, 5, 6, 7 };
int[] arr = { 1, 2, 3, 4, 5, 6, 7 };

int[] start = arr[..3];      // {1, 2, 3}
int[] end = arr[^2..];       // {6, 7}
int[] middle = arr[2..5];    // {3, 4, 5}
int[] all = arr[..];         // {1, 2, 3, 4, 5, 6, 7} (full copy)
2
Task
C# SELF, level 7, lesson 2
Locked
Using Indexing from the End and Ranges
Using Indexing from the End and Ranges
2
Task
C# SELF, level 7, lesson 2
Locked
String Array Reverse and Slices
String Array Reverse and Slices
Comments
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION