C# Arrays
$count++; if($count == 1) { include "../mobilemenu.php"; } if ($count == 2) { include "../sharemediasubfolder.php"; } ?>
Arrays are a fundamental data structure in C# used to store a fixed-size sequential collection of elements of the same type. They provide a way to group related data together, allowing efficient access and manipulation. Understanding arrays is essential for effective programming, as they are used extensively in various applications, from simple data storage to complex algorithms.
1. Introduction to Arrays
An array is a collection of elements, each identified by an index or key. In C#, arrays are zero-based, meaning the first element is accessed with index `0`. Arrays are fixed in size, meaning once they are created, their size cannot be changed.Key Characteristics:
- Fixed Size: The number of elements is defined at the time of creation and cannot be altered.
- Homogeneous Elements: All elements must be of the same type.
- Zero-Based Indexing: Indexing starts at `0`.
- Stored in Contiguous Memory: Elements are stored next to each other in memory, enabling fast access.
2. Declaring and Initializing Arrays
Arrays can be declared and initialized in various ways in C#.2.1 Declaring an Array:
using System;
class Program
{
static void Main()
{
int[] numbers; // Declaration of an integer array
}
}
Explanation:- `int[] numbers;` declares an array of integers named `numbers`. At this point, the array is not initialized and does not reference any memory.
2.2 Initializing an Array:
using System;
class Program
{
static void Main()
{
int[] numbers = new int[5]; // Initializes an integer array with 5 elements
Console.WriteLine($"Length of numbers array: {numbers.Length}"); // Output: 5
}
}
Output:
Length of numbers array: 5
- `new int[5]` creates an integer array with 5 elements, all initialized to `0`.
- `numbers.Length` returns the size of the array, which is `5`.
2.3 Declaring and Initializing with Values:
using System;
class Program
{
static void Main()
{
string[] fruits = { "Apple", "Banana", "Cherry" }; // Array initializer
Console.WriteLine($"First fruit: {fruits[0]}"); // Output: Apple
}
}
Output:
First fruit: Apple
- The array `fruits` is declared and initialized with three string elements using an array initializer.
- `fruits[0]` accesses the first element, which is `"Apple"`.
3. Single-Dimensional Arrays
Single-dimensional arrays are the simplest form of arrays in C#, consisting of a linear sequence of elements.3.1 Accessing Elements:
using System;
class Program
{
static void Main()
{
int[] numbers = { 10, 20, 30, 40, 50 };
Console.WriteLine($"Element at index 2: {numbers[2]}"); // Output: 30
}
}
Output:
Element at index 2: 30
- `numbers[2]` accesses the third element in the array, which is `30`.
3.2 Modifying Elements:
using System;
class Program
{
static void Main()
{
string[] colors = { "Red", "Green", "Blue" };
colors[1] = "Yellow"; // Modifies the second element
Console.WriteLine($"Modified color: {colors[1]}"); // Output: Yellow
}
}
Output:
Modified color: Yellow
- `colors[1] = "Yellow";` changes the second element from `"Green"` to `"Yellow"`.
4. Multi-Dimensional Arrays
C# supports multi-dimensional arrays, which are arrays of arrays. There are two types:- Rectangular Arrays: Arrays with rows and columns, forming a grid-like structure.
- Jagged Arrays: Arrays of arrays, where each "row" can have a different length.
4.1 Rectangular Arrays:
using System;
class Program
{
static void Main()
{
int[,] matrix = new int[3, 2]
{
{ 1, 2 },
{ 3, 4 },
{ 5, 6 }
};
Console.WriteLine($"Element at [1,1]: {matrix[1,1]}"); // Output: 4
}
}
Output:
Element at [1,1]: 4
- `int[,] matrix = new int[3, 2]` declares a 3x2 rectangular array.
- `matrix[1,1]` accesses the element in the second row and second column, which is `4`.
4.2 Jagged Arrays:
using System;
class Program
{
static void Main()
{
int[][] jagged = new int[3][];
jagged[0] = new int[] { 1, 2 };
jagged[1] = new int[] { 3, 4, 5 };
jagged[2] = new int[] { 6 };
Console.WriteLine($"Element at [1][2]: {jagged[1][2]}"); // Output: 5
}
}
Output:
Element at [1][2]: 5
- `int[][] jagged = new int[3][];` declares a jagged array with three rows.
- Each row is initialized with arrays of different lengths.
- `jagged[1][2]` accesses the third element in the second row, which is `5`.
5. Array Methods and Properties
C# provides various methods and properties to work with arrays.5.1 `Length` Property:
Returns the total number of elements in the array.
using System;
class Program
{
static void Main()
{
double[] decimals = { 1.1, 2.2, 3.3 };
Console.WriteLine($"Array length: {decimals.Length}"); // Output: 3
}
}
Output:
Array length: 3
- `decimals.Length` returns the number of elements in the `decimals` array, which is `3`.
5.2 `Rank` Property:
Returns the number of dimensions in the array.
using System;
class Program
{
static void Main()
{
int[,] matrix = new int[2, 3];
int[][] jagged = new int[2][];
Console.WriteLine($"Rank of matrix: {matrix.Rank}"); // Output: 2
Console.WriteLine($"Rank of jagged array: {jagged.Rank}"); // Output: 1
}
}
Output:
Rank of matrix: 2
Rank of jagged array: 1
- `matrix.Rank` returns `2` because it's a two-dimensional array.
- `jagged.Rank` returns `1` because it's an array of arrays, considered single-dimensional.
5.3 `GetLength` Method:
Returns the length of the specified dimension.
using System;
class Program
{
static void Main()
{
int[,] matrix = new int[2, 3];
Console.WriteLine($"Length of first dimension: {matrix.GetLength(0)}"); // Output: 2
Console.WriteLine($"Length of second dimension: {matrix.GetLength(1)}"); // Output: 3
}
}
Output:
Length of first dimension: 2
Length of second dimension: 3
- `matrix.GetLength(0)` returns the size of the first dimension (`2`).
- `matrix.GetLength(1)` returns the size of the second dimension (`3`).
5.4 `IndexOf` and `LastIndexOf` Methods:
Used to find the index of an element within the array. Note that arrays in C# do not have built-in `IndexOf` methods; instead, use `Array.IndexOf` and `Array.LastIndexOf`.
using System;
class Program
{
static void Main()
{
string[] names = { "Alice", "Bob", "Charlie", "Bob" };
int firstBob = Array.IndexOf(names, "Bob");
int lastBob = Array.LastIndexOf(names, "Bob");
Console.WriteLine($"First 'Bob' at index: {firstBob}"); // Output: 1
Console.WriteLine($"Last 'Bob' at index: {lastBob}"); // Output: 3
}
}
Output:
First 'Bob' at index: 1
Last 'Bob' at index: 3
- `Array.IndexOf(names, "Bob")` finds the first occurrence of `"Bob"` at index `1`.
- `Array.LastIndexOf(names, "Bob")` finds the last occurrence of `"Bob"` at index `3`.
5.5 `Sort` Method:
Sorts the elements of the array in ascending order.
using System;
class Program
{
static void Main()
{
int[] numbers = { 5, 2, 8, 1, 4 };
Array.Sort(numbers);
Console.WriteLine("Sorted numbers:");
foreach(var num in numbers)
{
Console.WriteLine(num);
}
// Output:
// 1
// 2
// 4
// 5
// 8
}
}
Output:
Sorted numbers:
1
2
4
5
8
- `Array.Sort(numbers)` sorts the `numbers` array in ascending order.
- The `foreach` loop prints the sorted elements.
5.6 `Reverse` Method:
Reverses the order of the elements in the array.
using System;
class Program
{
static void Main()
{
string[] letters = { "A", "B", "C", "D" };
Array.Reverse(letters);
Console.WriteLine("Reversed letters:");
foreach(var letter in letters)
{
Console.WriteLine(letter);
}
// Output:
// D
// C
// B
// A
}
}
Output:
Reversed letters:
D
C
B
A
- `Array.Reverse(letters)` reverses the order of elements in the `letters` array.
- The `foreach` loop prints the reversed elements.
6. Iterating Over Arrays with Loops
Loops are commonly used to traverse and process array elements.6.1 Using `for` Loop:
using System;
class Program
{
static void Main()
{
double[] temperatures = { 23.5, 25.0, 22.8, 24.3 };
for(int i = 0; i < temperatures.Length; i++)
{
Console.WriteLine($"Day {i+1}: {temperatures[i]}°C");
}
// Output:
// Day 1: 23.5°C
// Day 2: 25°C
// Day 3: 22.8°C
// Day 4: 24.3°C
}
}
Output:
Day 1: 23.5°C
Day 2: 25°C
Day 3: 22.8°C
Day 4: 24.3°C
- The `for` loop iterates over each index of the `temperatures` array.
- It prints the temperature for each day.
6.2 Using `foreach` Loop:
using System;
class Program
{
static void Main()
{
string[] cities = { "New York", "London", "Tokyo", "Sydney" };
foreach(string city in cities)
{
Console.WriteLine($"City: {city}");
}
// Output:
// City: New York
// City: London
// City: Tokyo
// City: Sydney
}
}
Output:
City: New York
City: London
City: Tokyo
City: Sydney
- The `foreach` loop iterates directly over each element in the `cities` array.
- It prints the name of each city.
6.3 Using `while` Loop:
using System;
class Program
{
static void Main()
{
int[] scores = { 85, 90, 78, 92 };
int index = 0;
while(index < scores.Length)
{
Console.WriteLine($"Score {index+1}: {scores[index]}");
index++;
}
// Output:
// Score 1: 85
// Score 2: 90
// Score 3: 78
// Score 4: 92
}
}
Output:
Score 1: 85
Score 2: 90
Score 3: 78
Score 4: 92
- It prints each score and increments the index.
6.4 Using `do-while` Loop:
using System;
class Program
{
static void Main()
{
string[] names = { "Alice", "Bob", "Charlie" };
int i = 0;
do
{
Console.WriteLine($"Name {i+1}: {names[i]}");
i++;
} while(i < names.Length);
// Output:
// Name 1: Alice
// Name 2: Bob
// Name 3: Charlie
}
}
Output:
Name 1: Alice
Name 2: Bob
Name 3: Charlie
- The `do-while` loop executes the block once before checking the condition.
- It prints each name and increments the counter until all names are printed.
7. Array Manipulation: Sorting, Searching, Copying, Reversing
C# provides various methods to manipulate arrays efficiently.7.1 Sorting Arrays:
using System;
class Program
{
static void Main()
{
int[] ages = { 34, 21, 45, 18, 27 };
Array.Sort(ages);
Console.WriteLine("Sorted ages:");
foreach(int age in ages)
{
Console.WriteLine(age);
}
// Output:
// 18
// 21
// 27
// 34
// 45
}
}
Output:
Sorted ages:
18
21
27
34
45
- `Array.Sort(ages)` sorts the `ages` array in ascending order.
- The `foreach` loop prints the sorted ages.
7.2 Searching Arrays:
using System;
class Program
{
static void Main()
{
string[] fruits = { "Apple", "Banana", "Cherry", "Date" };
string searchFruit = "Cherry";
int index = Array.IndexOf(fruits, searchFruit);
if(index != -1)
{
Console.WriteLine($"{searchFruit} found at index {index}"); // Output: Cherry found at index 2
}
else
{
Console.WriteLine($"{searchFruit} not found.");
}
}
}
Output:
Cherry found at index 2
- `Array.IndexOf(fruits, searchFruit)` searches for `"Cherry"` and returns its index `2`.
- If the element is not found, `IndexOf` returns `-1`.
7.3 Copying Arrays:
using System;
class Program
{
static void Main()
{
int[] original = { 1, 2, 3, 4, 5 };
int[] copy = new int[original.Length];
Array.Copy(original, copy, original.Length);
Console.WriteLine("Copied array:");
foreach(int num in copy)
{
Console.WriteLine(num);
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
}
Output:
Copied array:
1
2
3
4
5
- `Array.Copy(original, copy, original.Length)` copies all elements from `original` to `copy`.
- The `foreach` loop prints the copied elements.
7.4 Reversing Arrays:
using System;
class Program
{
static void Main()
{
char[] letters = { 'A', 'B', 'C', 'D' };
Array.Reverse(letters);
Console.WriteLine("Reversed letters:");
foreach(char letter in letters)
{
Console.WriteLine(letter);
}
// Output:
// D
// C
// B
// A
}
}
Output:
Reversed letters:
D
C
B
A
- `Array.Reverse(letters)` reverses the order of elements in the `letters` array.
- The `foreach` loop prints the reversed elements.
8. Array vs. List
While arrays are fixed in size, `List<T>` provides a dynamic array-like structure that can grow or shrink as needed. Comparison:| Feature | Array | List<T> |
|-----------------|----------------------|----------------------------|
| Size | Fixed at creation | Dynamic, can resize |
| Performance | Generally faster | Slight overhead for dynamic sizing |
| Methods | Limited (Array class methods) | Rich set of methods (Add, Remove, etc.) |
| Type | Homogeneous elements | Homogeneous elements |
Example Using List<T>:
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
List<string> names = new List<string> { "Alice", "Bob" };
names.Add("Charlie");
names.Remove("Bob");
Console.WriteLine("Names in list:");
foreach(string name in names)
{
Console.WriteLine(name);
}
// Output:
// Alice
// Charlie
}
}
Output:
Names in list:
Alice
Charlie
- `List<string>` allows adding and removing elements dynamically.
- The `foreach` loop prints the current elements in the list.
9. Array Initializers and Shorthand
C# offers concise ways to initialize arrays.9.1 Implicitly Typed Arrays:
using System;
class Program
{
static void Main()
{
var numbers = new[] { 1, 2, 3, 4, 5 }; // Implicit type inferred as int[]
Console.WriteLine($"Type of numbers: {numbers.GetType()}"); // Output: System.Int32[]
}
}
Output:
Type of numbers: System.Int32[]
- `var numbers = new[] { 1, 2, 3, 4, 5 };` allows the compiler to infer the array type.
9.2 Multi-Dimensional Array Initializers:
using System;
class Program
{
static void Main()
{
int[,] grid = {
{ 1, 2, 3 },
{ 4, 5, 6 }
};
Console.WriteLine($"Element at [0,2]: {grid[0,2]}"); // Output: 3
}
}
Output:
Element at [0,2]: 3
- The `grid` array is initialized with two rows and three columns using a multi-dimensional initializer.
9.3 Jagged Array Initializers:
using System;
class Program
{
static void Main()
{
int[][] jagged = {
new int[] { 1, 2 },
new int[] { 3, 4, 5 },
new int[] { 6 }
};
Console.WriteLine($"Element at [1][2]: {jagged[1][2]}"); // Output: 5
}
}
Output:
Element at [1][2]: 5
- The jagged array `jagged` is initialized with arrays of varying lengths.
- `jagged[1][2]` accesses the third element in the second array, which is `5`.
10. Array Covariance
Array covariance allows an array of a derived type to be assigned to an array of a base type. However, it can lead to runtime exceptions if not handled carefully.Example of Array Covariance:
using System;
class Animal
{
public virtual void Speak()
{
Console.WriteLine("Animal sound");
}
}
class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Dog barks");
}
}
class Program
{
static void Main()
{
Animal[] animals = new Dog[2]; // Array covariance
animals[0] = new Dog(); // Valid
// animals[1] = new Animal(); // Invalid, throws ArrayTypeMismatchException
try
{
animals[1] = new Animal(); // Attempting to assign base type to derived array
}
catch(ArrayTypeMismatchException ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
// Output:
// Exception: Attempted to access an array as a different type.
}
}
Output:
Exception: Attempted to access an array as a different type.
- `Animal[] animals = new Dog[2];` assigns a `Dog` array to an `Animal` array reference.
- Assigning a `Dog` to `animals[0]` is valid.
- Assigning an `Animal` to `animals[1]` is invalid and throws an `ArrayTypeMismatchException` at runtime.
11. Performance Considerations
- Fixed Size: Arrays have less overhead compared to dynamic collections like `List<T>`, making them faster for fixed-size data.- Memory Allocation: Arrays are allocated in contiguous memory, enabling faster access times.
- Cache Performance: Due to their contiguous memory layout, arrays can have better cache performance.
- Avoid Frequent Resizing: Since arrays are fixed in size, avoid scenarios where frequent resizing is needed. Use `List<T>` instead for dynamic sizing.
- Use `foreach` for Read-Only Iteration: `foreach` is optimized for array iteration and can be more readable.
12. Best Practices for Using Arrays
- Use Appropriate Types: Choose single-dimensional arrays for simple lists, multi-dimensional for grids, and jagged arrays for irregular structures.- Initialize Properly: Always initialize arrays before accessing elements to avoid `NullReferenceException`.
- Handle Bounds Carefully: Access elements within valid indices to prevent `IndexOutOfRangeException`.
- Prefer `foreach` for Readability: Use `foreach` loops for simple iteration over arrays.
- Use `Array.Copy` or `Clone` for Safe Copying: Avoid manual copying to prevent errors.
- Leverage Built-In Methods: Utilize `Array` class methods for common operations like sorting, searching, and reversing.
- Minimize Array Mutations: Since arrays are mutable, minimize changes to ensure thread safety and predictability.
- Consider Using `Span<T>` for High-Performance Scenarios: For advanced memory handling and performance optimization.
- Avoid Overusing Arrays: Use other data structures like `List<T>`, `Dictionary<TKey, TValue>`, etc., when dynamic sizing or key-based access is required.
13. Common Mistakes and How to Avoid Them
- Off-by-One Errors: Accessing indices outside the valid range.Example:
using System;
class Program
{
static void Main()
{
int[] numbers = { 1, 2, 3 };
Console.WriteLine(numbers[3]); // Throws IndexOutOfRangeException
}
}
Solution:- Always ensure index is within `0` to `Length - 1`.
- Not Initializing Arrays:
Example:
using System;
class Program
{
static void Main()
{
string[] names;
Console.WriteLine(names.Length); // Compile-time error
}
}
Solution:- Initialize arrays before use:
string[] names = new string[3];
- Modifying Arrays When Not Intended:
Example:
using System;
class Program
{
static void Main()
{
string[] fruits = { "Apple", "Banana", "Cherry" };
fruits[1] = "Blueberry"; // Modifies the original array
}
}
Solution:- Use `readonly` arrays or encapsulate arrays to prevent unintended modifications.
- Confusing Multi-Dimensional and Jagged Arrays:
Example:
using System;
class Program
{
static void Main()
{
int[,] matrix = { { 1, 2 }, { 3, 4 } };
int[][] jagged = { new int[] { 1, 2 }, new int[] { 3, 4 } };
Console.WriteLine(matrix.GetLength(1)); // Output: 2
Console.WriteLine(jagged[1].Length); // Output: 2
}
}
Solution:- Understand the difference between rectangular and jagged arrays and use them appropriately.
- Overlooking Array Immutability for Strings:
Example:
using System;
class Program
{
static void Main()
{
string[] greetings = { "Hello" };
greetings[0] = greetings[0].Replace("H", "J");
Console.WriteLine(greetings[0]); // Output: Jello
}
}
Explanation:- Strings are immutable; `Replace` creates a new string which is then assigned to the array element.
- Assuming Arrays are Automatically Resizable:
Example:
using System;
class Program
{
static void Main()
{
int[] numbers = { 1, 2, 3 };
Array.Resize(ref numbers, 5); // Valid way to resize
numbers[3] = 4;
numbers[4] = 5;
foreach(var num in numbers)
{
Console.WriteLine(num);
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
}
Output:
1
2
3
4
5
- Arrays are fixed in size. To resize, use `Array.Resize` which creates a new array and copies elements.
14. Real-World Example: Matrix Operations
Matrices (two-dimensional arrays) are widely used in applications like graphics, scientific computations, and data processing.Example: Transposing a Matrix
using System;
class Program
{
static void Main()
{
int[,] matrix = {
{ 1, 2, 3 },
{ 4, 5, 6 }
};
int rows = matrix.GetLength(0);
int cols = matrix.GetLength(1);
int[,] transposed = new int[cols, rows];
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
transposed[j, i] = matrix[i, j];
}
}
Console.WriteLine("Original Matrix:");
PrintMatrix(matrix);
Console.WriteLine("Transposed Matrix:");
PrintMatrix(transposed);
}
static void PrintMatrix(int[,] mat)
{
int rows = mat.GetLength(0);
int cols = mat.GetLength(1);
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
Console.Write(mat[i, j] + " ");
}
Console.WriteLine();
}
}
}
Output:
Original Matrix:
1 2 3
4 5 6
Transposed Matrix:
1 4
2 5
3 6
- The `matrix` is a 2x3 array.
- The nested `for` loops transpose the matrix into a 3x2 array `transposed`.
- `PrintMatrix` method displays the original and transposed matrices.
15. Advanced Topics
15.1 `Span<T>` and `Memory<T>` with Arrays: Introduced in C# 7.2 and enhanced in later versions, `Span<T>` and `Memory<T>` provide memory-safe and efficient ways to handle slices of arrays without additional allocations.using System;
class Program
{
static void Main()
{
int[] numbers = { 10, 20, 30, 40, 50 };
Span<int> slice = numbers.AsSpan(1, 3); // Slices elements 20, 30, 40
Console.WriteLine("Slice of array:");
foreach(var num in slice)
{
Console.WriteLine(num);
}
// Output:
// 20
// 30
// 40
}
}
Output:
Slice of array:
20
30
40
- `AsSpan(1, 3)` creates a span that references elements from index `1` to `3` in the `numbers` array.
- The `foreach` loop iterates over the slice without creating a new array.
15.2 Array Covariance and Contravariance:
Arrays are covariant, meaning you can assign an array of a derived type to an array of a base type. However, this can lead to runtime exceptions if not handled carefully.
using System;
class Animal
{
public virtual void Speak()
{
Console.WriteLine("Animal sound");
}
}
class Dog : Animal
{
public override void Speak()
{
Console.WriteLine("Dog barks");
}
}
class Program
{
static void Main()
{
Animal[] animals = new Dog[2]; // Covariance
animals[0] = new Dog(); // Valid
try
{
animals[1] = new Animal(); // Invalid, throws ArrayTypeMismatchException
}
catch(ArrayTypeMismatchException ex)
{
Console.WriteLine($"Exception: {ex.Message}");
}
// Output:
// Exception: Attempted to access an array as a different type.
}
}
Output:
Exception: Attempted to access an array as a different type.
- Assigning a base type (`Animal`) to a derived type array (`Dog[]`) is allowed due to covariance.
- However, inserting a base type instance (`new Animal()`) into a derived type array (`Dog[]`) causes a runtime exception.
15.3 Using `yield return` with Arrays:
Creating custom iterator methods that can be used to generate arrays on-the-fly.
using System;
using System.Collections.Generic;
class Program
{
static void Main()
{
foreach(var number in GetNumbers(3))
{
Console.WriteLine(number);
}
// Output:
// 1
// 2
// 3
}
static IEnumerable<int> GetNumbers(int count)
{
for(int i = 1; i <= count; i++)
{
yield return i;
}
}
}
Output:
1
2
3
- The `GetNumbers` method uses `yield return` to generate a sequence of numbers.
- The `foreach` loop iterates over the generated sequence.
15.4 Jagged Arrays vs. Multi-Dimensional Arrays Performance:
Jagged arrays can offer better performance and flexibility compared to multi-dimensional arrays, especially when the inner arrays vary in size.
using System;
class Program
{
static void Main()
{
// Multi-Dimensional Array
int[,] multiDim = new int[3, 3];
// Jagged Array
int[][] jagged = new int[3][];
jagged[0] = new int[] {1,2,3};
jagged[1] = new int[] {4,5};
jagged[2] = new int[] {6};
// Accessing elements
multiDim[1,2] = 10;
jagged[1][1] = 20;
Console.WriteLine($"multiDim[1,2]: {multiDim[1,2]}"); // Output: 10
Console.WriteLine($"jagged[1][1]: {jagged[1][1]}"); // Output: 20
}
}
Output:
multiDim[1,2]: 10
jagged[1][1]: 20
- `multiDim` is a 3x3 array with uniform row sizes.
- `jagged` is a 3-element array where each element is an array of different lengths.
- Accessing and modifying elements works similarly, but jagged arrays offer more flexibility.
16. Real-World Example: Image Processing with Multi-Dimensional Arrays
Multi-dimensional arrays are commonly used to represent images in terms of pixels.Example: Grayscale Image Representation
using System;
class Program
{
static void Main()
{
// 3x3 Grayscale Image
int[,] image = {
{ 255, 128, 64 },
{ 0, 128, 255 },
{ 64, 128, 0 }
};
Console.WriteLine("Original Image:");
PrintImage(image);
// Invert the image
for(int i = 0; i < image.GetLength(0); i++)
{
for(int j = 0; j < image.GetLength(1); j++)
{
image[i, j] = 255 - image[i, j];
}
}
Console.WriteLine("Inverted Image:");
PrintImage(image);
}
static void PrintImage(int[,] img)
{
int rows = img.GetLength(0);
int cols = img.GetLength(1);
for(int i = 0; i < rows; i++)
{
for(int j = 0; j < cols; j++)
{
Console.Write($"{img[i, j],4}");
}
Console.WriteLine();
}
}
}
Output:
Original Image:
255 128 64
0 128 255
64 128 0
Inverted Image:
0 127 191
255 127 0
191 127 255
- The nested `for` loops invert the image by subtracting each pixel value from `255`.
- The `PrintImage` method displays the image before and after inversion.
17. Advanced Topics
17.1 `Span<T>` and `Memory<T>` with Arrays:`Span<T>` provides a type-safe and memory-efficient way to work with slices of arrays without additional allocations.
using System;
class Program
{
static void Main()
{
int[] numbers = { 10, 20, 30, 40, 50 };
Span<int> slice = numbers.AsSpan(1, 3); // Slices elements 20, 30, 40
Console.WriteLine("Slice of array:");
foreach(var num in slice)
{
Console.WriteLine(num);
}
// Output:
// 20
// 30
// 40
}
}
Output:
Slice of array:
20
30
40
- `AsSpan(1, 3)` creates a span that references a subset of the `numbers` array.
- The `foreach` loop iterates over the slice without creating a new array.
17.2 Using `Array.Resize`:
Resizing an array by creating a new array and copying elements.
using System;
class Program
{
static void Main()
{
int[] numbers = { 1, 2, 3 };
Array.Resize(ref numbers, 5);
numbers[3] = 4;
numbers[4] = 5;
Console.WriteLine("Resized array:");
foreach(var num in numbers)
{
Console.WriteLine(num);
}
// Output:
// 1
// 2
// 3
// 4
// 5
}
}
Output:
Resized array:
1
2
3
4
5
- New elements are initialized to default values (`0` for integers) before being assigned.
17.3 Using `Array.CopyTo` Method:
Copies elements from one array to another.
using System;
class Program
{
static void Main()
{
int[] source = { 1, 2, 3 };
int[] destination = new int[5];
source.CopyTo(destination, 1); // Copies to destination starting at index 1
Console.WriteLine("Destination array:");
foreach(var num in destination)
{
Console.WriteLine(num);
}
// Output:
// 0
// 1
// 2
// 3
// 0
}
}
Output:
Destination array:
0
1
2
3
0
- `source.CopyTo(destination, 1)` copies elements from `source` to `destination` starting at index `1`.
- The `destination` array now has the copied elements in the specified positions.
17.4 Using `Array.Find` and `Array.FindAll` Methods:
Finds elements in an array that match a specified condition.
using System;
class Program
{
static void Main()
{
int[] numbers = { 5, 12, 8, 130, 44 };
int found = Array.Find(numbers, element => element > 10);
Console.WriteLine($"First number > 10: {found}"); // Output: 12
int[] allFound = Array.FindAll(numbers, element => element > 10);
Console.WriteLine("All numbers > 10:");
foreach(var num in allFound)
{
Console.WriteLine(num);
}
// Output:
// 12
// 130
// 44
}
}
Output:
First number > 10: 12
All numbers > 10:
12
130
44
- `Array.Find` returns the first element that matches the condition (`> 10`), which is `12`.
- `Array.FindAll` returns all elements that match the condition, resulting in `12`, `130`, and `44`.
18. Common Mistakes and How to Avoid Them
- Off-by-One Errors:Example:
using System;
class Program
{
static void Main()
{
int[] numbers = { 1, 2, 3 };
for(int i = 0; i <= numbers.Length; i++) // Incorrect condition
{
Console.WriteLine(numbers[i]); // Throws IndexOutOfRangeException when i = 3
}
}
}
Solution:- Use `<` instead of `<=` in loop conditions:
for(int i = 0; i < numbers.Length; i++)
- Not Initializing Arrays:
Example:
using System;
class Program
{
static void Main()
{
string[] names;
Console.WriteLine(names.Length); // Compile-time error
}
}
Solution:
- Initialize arrays before use:
string[] names = new string[3];
- Assuming Arrays are Automatically Resizable:
Example:
using System;
class Program
{
static void Main()
{
int[] numbers = { 1, 2, 3 };
numbers[3] = 4; // Throws IndexOutOfRangeException
}
}
Solution:- Use `Array.Resize` or `List<T>` for dynamic sizing.
- Modifying Arrays When Not Intended:
Example:
using System;
class Program
{
static void Main()
{
string[] fruits = { "Apple", "Banana", "Cherry" };
fruits[1] = "Blueberry"; // Modifies the original array
}
}
Solution:- Use `readonly` arrays or encapsulate arrays to prevent unintended modifications.
- Confusing Multi-Dimensional and Jagged Arrays:
Solution:
- Understand the difference and use them appropriately based on the data structure requirements.
- Ignoring Array Immutability for Strings:
Solution:
- Remember that strings are immutable. Use methods that return new strings instead of trying to modify existing ones.
19. Real-World Example: Inventory Management System
Consider an inventory management system where products are stored in a two-dimensional array representing different categories and items.Example: Managing Product Inventory
using System;
class Program
{
static void Main()
{
// Categories: 0 - Electronics, 1 - Clothing, 2 - Groceries
string[,] inventory = {
{ "Laptop", "Smartphone", "Tablet" },
{ "Shirt", "Jeans", "Jacket" },
{ "Apples", "Bread", "Milk" }
};
Console.WriteLine("Inventory:");
PrintInventory(inventory);
// Add a new product to Electronics
inventory[0, 2] = "Smartwatch";
Console.WriteLine("\nUpdated Inventory:");
PrintInventory(inventory);
}
static void PrintInventory(string[,] inv)
{
int categories = inv.GetLength(0);
int items = inv.GetLength(1);
string[] categoryNames = { "Electronics", "Clothing", "Groceries" };
for(int i = 0; i < categories; i++)
{
Console.WriteLine($"{categoryNames[i]}:");
for(int j = 0; j < items; j++)
{
Console.WriteLine($" - {inv[i, j]}");
}
}
}
}
Output:
Inventory:
Electronics:
- Laptop
- Smartphone
- Tablet
Clothing:
- Shirt
- Jeans
- Jacket
Groceries:
- Apples
- Bread
- Milk
Updated Inventory:
Electronics:
- Laptop
- Smartphone
- Smartwatch
Clothing:
- Shirt
- Jeans
- Jacket
Groceries:
- Apples
- Bread
- Milk
- `PrintInventory` method displays the inventory by category.
- Updating `inventory[0, 2]` changes "Tablet" to "Smartwatch".
20. Advanced Topics
20.1 Using `Array.IndexOf` with Custom Types:For arrays of custom objects, override the `Equals` method to enable `Array.IndexOf` to work correctly.
using System;
class Person
{
public string Name { get; set; }
public override bool Equals(object obj)
{
if(obj is Person p)
{
return this.Name == p.Name;
}
return false;
}
public override int GetHashCode()
{
return Name.GetHashCode();
}
}
class Program
{
static void Main()
{
Person[] people = {
new Person { Name = "Alice" },
new Person { Name = "Bob" },
new Person { Name = "Charlie" }
};
Person search = new Person { Name = "Bob" };
int index = Array.IndexOf(people, search);
Console.WriteLine($"Index of Bob: {index}"); // Output: 1
}
}
Output:
Index of Bob: 1
- `Person` class overrides `Equals` and `GetHashCode` to enable proper comparison.
- `Array.IndexOf` uses these methods to find the index of the `search` person.
20.2 Using `Array.Find` with Custom Conditions:
using System;
class Product
{
public string Name { get; set; }
public double Price { get; set; }
}
class Program
{
static void Main()
{
Product[] products = {
new Product { Name = "Laptop", Price = 999.99 },
new Product { Name = "Smartphone", Price = 599.99 },
new Product { Name = "Tablet", Price = 399.99 }
};
Product expensive = Array.Find(products, p => p.Price > 500);
Console.WriteLine($"Expensive product: {expensive.Name}, Price: {expensive.Price}");
// Output: Expensive product: Laptop, Price: 999.99
}
}
Output:
Expensive product: Laptop, Price: 999.99
- `Array.Find` searches for the first `Product` with a `Price` greater than `500`.
- It returns the `Laptop` product.
20.3 Using `Array.TrueForAll` Method:
Checks if all elements in the array satisfy a specified condition.
using System;
class Program
{
static void Main()
{
int[] numbers = { 2, 4, 6, 8 };
bool allEven = Array.TrueForAll(numbers, n => n % 2 == 0);
Console.WriteLine($"All numbers are even: {allEven}"); // Output: True
}
}
Output:
All numbers are even: True
- `Array.TrueForAll(numbers, n => n % 2 == 0)` checks if all elements in `numbers` are even.
20.4 Using `Array.ForEach` Method:
Performs a specified action on each element of the array.
using System;
class Program
{
static void Main()
{
string[] names = { "Alice", "Bob", "Charlie" };
Array.ForEach(names, name => Console.WriteLine($"Name: {name}"));
// Output:
// Name: Alice
// Name: Bob
// Name: Charlie
}
}
Output:
Name: Alice
Name: Bob
Name: Charlie
- `Array.ForEach` applies the lambda expression to each element in the `names` array.
21. Summary
Arrays in C# are powerful and versatile structures that provide efficient storage and access to collections of homogeneous elements. They are essential for various programming tasks, including data storage, iteration, and manipulation. Understanding the different types of arrays (single-dimensional, multi-dimensional, jagged), their methods and properties, and best practices ensures that developers can effectively utilize arrays to build robust and high-performance applications.Key points
- Fixed Size and Homogeneous Elements: Arrays have a predetermined size and store elements of the same type.- Single-Dimensional vs. Multi-Dimensional vs. Jagged Arrays: Choose the appropriate array type based on data structure requirements.
- Array Methods and Properties: Utilize built-in methods like `Sort`, `Reverse`, `Copy`, and properties like `Length` for efficient operations.
- Iterating with Loops: Use `for`, `foreach`, `while`, and `do-while` loops to traverse arrays effectively.
- Array Manipulation: Perform sorting, searching, copying, and reversing using `Array` class methods.
- Performance Considerations: Arrays offer high performance due to contiguous memory allocation and minimal overhead.
- Best Practices: Initialize arrays properly, handle indices carefully, prefer `foreach` for readability, and use advanced features like `Span<T>` for high-performance scenarios.
- Common Mistakes: Off-by-one errors, uninitialized arrays, incorrect resizing, and misunderstanding array covariance can lead to runtime errors.
- Advanced Topics: Leverage `Span<T>`, `Memory<T>`, and other advanced features for optimized memory and performance.
- Real-World Applications: Arrays are used in various domains, including image processing, inventory management, and data parsing.
Mastering arrays in C# enables developers to handle data efficiently, write optimized code, and build complex applications with ease.