Mảng trong C#

Một mảng lưu trữ một tập hợp tuần tự có kích thước cố định của các phần tử cùng loại. Một mảng được sử dụng để lưu trữ một tập hợp dữ liệu, nhưng thường hữu ích hơn khi nghĩ về một mảng là một tập hợp các biến cùng loại được lưu trữ tại các vị trí bộ nhớ liền kề.

Thay vì khai báo các biến riêng lẻ, chẳng hạn như number0, number1, ... đến number99, bạn có thể khai báo một mảng numbers và sử dụng numbers[0], numbers[1] và ..., numbers[99] để biểu thị cho các biến riêng lẻ ở trên. Một phần tử cụ thể trong một mảng được truy cập bởi một chỉ mục.

Tất cả các mảng bao gồm các vị trí bộ nhớ liền kề. Địa chỉ thấp nhất tương ứng với phần tử đầu tiên và địa chỉ cao nhất cho phần tử cuối cùng.

Vị trí bộ nhớ các phần tử trong mảng

Khai báo mảng trong C#

datatype[] arrayName;

Giải thích:

  • datatype được sử dụng để xác định kiểu dữ liệu của các phần tử trong mảng.
  • [ ] chỉ định kích thước của mảng.
  • arrayName chỉ định tên của mảng.

Ví dụ:

double[] balance;

Khởi tạo mảng trong C#

Việc khai báo một mảng không khởi tạo mảng trong bộ nhớ. Khi biến mảng được khởi tạo, bạn có thể gán giá trị cho mảng đó.

Mảng là một kiểu tham chiếu, vì thế bạn cần sử dụng từ khóa new trong C# để tạo một thể hiện của mảng đó. Ví dụ:

double[] balance = new double[10];

Gán giá trị cho một mảng trong C#

Bạn có thể gán giá trị cho các phần tử mảng riêng biệt bởi sử dụng chỉ số mảng, như:

double[] balance = new double[10];
balance[0] = 123.0;

Bạn có thể gán giá trị cho mảng tại thời điểm khai báo mảng, như sau:

double[] balance = { 123.0, 456.69, 789.0};

Bạn cũng có thể tạo và khai báo một mảng, như sau:

int[] marks = new int[6]  { 90, 98, 92, 97, 95, 99 };

Bạn cũng có thể bỏ qua kích cỡ mảng, như:

int[] marks = new int[]  { 90, 98, 92, 97, 95, 99 };

Bạn có thể sao chép một biến mảng vào trong biến mảng khác. Trong tình huống này, cả biến mảng mới và biến mảng nguồn đều trỏ tới cùng vị trí bộ nhớ:

int[] marks = new int[]  { 90, 98, 92, 97, 95, 80 };
int[] score = marks;

Khi bạn tạo một mảng, trình biên dịch C# ngầm định gắn giá trị mặc định cho từng phần tử của mảng phụ thuộc vào kiểu mảng. Ví dụ, với một mảng int, thì tất cả phần tử được gắn giá trị là 0.

Truy cập các phần tử mảng trong C#

Một phần tử được truy cập bởi chỉ mục mảng. Điều này được thực hiện bởi việc đặt vị trí của phần tử bên trong dấu ngoặc vuông ở sau tên mảng. Ví dụ:

double salary = balance[3];

Ví dụ sau minh họa khái niệm về khai báo, gán và truy cập mảng trong C# đã đề cập ở trên:

using System;

namespace ArrayApplication 
{
   class MyArray 
   {
      static void Main(string[] args) 
      {
         int[] numbers = new int[10];

         for (int i = 0; i < 10; i++) 
         {
            numbers[i] = i + 100;
         }
         
         for (int j = 0; j < 10; j++) 
         {
            Console.WriteLine("Element[{0}] = {1}", j, numbers[j]);
         }
         Console.ReadKey();
      }
   }
}

Kết quả khi chạy chương trình trên:

Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109

Sử dụng vòng lặp foreach trong C#

Trong bài Vòng lặp trong C# mình đã trình bày về vòng lặp foreach, nếu bạn chưa biết vòng lặp foreach thì nên đọc bài viết này trước. Dùng vòng lặp foreach duyệt mảng như sau:

using System;

namespace ArrayApplication 
{
   class MyArray 
   {
      static void Main(string[] args) 
      {
         int[] numbers = new int[10];
         
         for (int i = 0; i < 10; i++) 
         {
            numbers[i] = i + 100;
         }
         
         int j = 0;
         foreach (int item in numbers) 
         {
            Console.WriteLine("Element[{0}] = {1}", j, item);
            j++;
         }
         Console.ReadKey();
      }
   }
}

Kết quả khi chạy đoạn mã trên:

Element[0] = 100
Element[1] = 101
Element[2] = 102
Element[3] = 103
Element[4] = 104
Element[5] = 105
Element[6] = 106
Element[7] = 107
Element[8] = 108
Element[9] = 109

Một số khái niệm về mảng C#

Có một số khái niệm quan trọng sau đây liên quan đến mảng cần phải hiểu rõ ràng đối với lập trình viên C#:

Khái niệm Miêu tả
Mảng đa chiều C# hỗ trợ mảng đa chiều. Mẫu đơn giản nhất của mảng đa chiều là mảng hai chiều
Mảng răng cưa C# hỗ trợ mảng đa chiều, mà là mảng của các mảng
Truyền mảng cho phương thức Bạn có thể truyền cho phương thức một con trỏ tới một mảng bằng việc xác định tên mảng mà không cần chỉ số của mảng
Mảng tham số Được sử dụng để truyền một số lượng tham số chưa biết trước tới một phương thức
Lớp Array Được định nghĩa trong namespace System, nó là lớp cơ sở cho tất cả mảng, và cung cấp các thuộc tính và phương thức để làm việc với mảng

Mảng đa chiều trong C#

C# hỗ trợ các mảng đa chiều. Các mảng đa chiều cũng được gọi là mảng hình chữ nhật. Bạn có thể khai báo một mảng chuỗi hai chiều như sau:

string[,] name;

Hoặc, một mảng các biến int 3 chiều, như sau:

int[,,] name;

Mảng hai chiều trong C#

Mẫu đơn giản nhất của mảng đa chiều là mảng hai chiều. Một mảng hai chiều về bản chất là danh sách của các mảng một chiều.

Một mảng 2 chiều có thể được nghĩ như là một bảng, có x hàng và y cột. Dưới đây là một mảng hai chiều có 3 hàng và 4 cột.

Mảng hai chiều trong C#

Như vậy, mỗi phần tử trong mảng a được định danh bởi một tên phần tử trong kiểu mẫu a[i][j], với a là tên mảng và i, j là các chỉ số được xác định duy nhất mỗi phần tử trong mảng a.

Khởi tạo mảng hai chiều trong C#

Các mảng đa chiều có thể được khởi tạo bởi chỉ định các giá trị trong dấu móc vuông cho mỗi hàng. Sau đây là một mảng với 3 hàng và 4 cột.

int[,] a = new int [3,4] 
{
   {0, 1, 2, 3},    /*  initializers for row indexed by 0 */
   {4, 5, 6, 7},    /*  initializers for row indexed by 1 */
   {8, 9, 10, 11}   /*  initializers for row indexed by 2 */
};

Truy cập các phần tử của mảng hai chiều trong C#

Các phần tử mảng hai chiều được truy cập bằng cách sử dụng các chỉ số, đó là chỉ mục hàng và chỉ mục cột. Ví dụ:

int val = a[2,3];

Lệnh trên sẽ truy cập vào phần tử ở hàng 3 và cột 4 của mảng. Bạn có thể kiểm tra lại nó trong sơ đồ trên. Bây giờ chúng ta xem xét ví dụ dưới đây, chúng tôi đã sử dụng các vòng lặp lồng vào nhau để xử lý một mảng hai chiều:

using System;

namespace ArrayApplication 
{
   class MyArray 
   {
      static void Main(string[] args) 
      {
         int[,] a = new int[5,2] {{0,0}, {1,2}, {2,4}, {3,6}, {4,8}};
         
         for (int i = 0; i < 5; i++) 
         {            
            for (int j = 0; j < 2; j++) 
            {
               Console.WriteLine("a[{0},{1}] = {2}", i, j, a[i,j]);
            }
         }
         Console.ReadKey();
      }
   }
}

Đây là kết quả khi chạy chương trình trên:

a[0,0]: 0
a[0,1]: 0
a[1,0]: 1
a[1,1]: 2
a[2,0]: 2
a[2,1]: 4
a[3,0]: 3
a[3,1]: 6
a[4,0]: 4
a[4,1]: 8

Mảng răng cưa trong C#

Một mảng răng cưa là một mảng của các mảng. Bạn có thể khai báo một mảng răng cưa có tên scores có kiểu int như sau:

int[][] scores;

Khai báo một mảng, không tạo mảng trong bộ nhớ:

int[][] scores = new int[5][];
for (int i = 0; i < scores.Length; i++) 
{
   scores[i] = new int[4];
}

Bạn có thể khởi tạo một mảng răng cưa như sau:

int[][] scores = new int[2][]
{
	new int[]{92,93,94},
    new int[]{85,66,87,88}
};

Trong đó, scores là một mảng của hai mảng integer: trong đó, scores[0] là một mảng 3 integer và scores[1] là một mảng 4 integer.

Ví dụ

using System;

namespace ArrayApplication 
{
   class MyArray 
   {
      static void Main(string[] args) 
      {
         int[][] a = new int[][]
         {
         	new int[]{0,0},
            new int[]{1,2},
            new int[]{2,4},
            new int[]{3,6},
            new int[]{4,8} 
         };
         
         for (int i = 0; i < 5; i++) 
         {
            for (int j = 0; j < 2; j++) 
            {
               Console.WriteLine("a[{0}][{1}] = {2}", i, j, a[i][j]);
            }
         }
         Console.ReadKey();
      }
   }
}

Đây là kết quả khi chạy chương trình trên:

a[0][0]: 0
a[0][1]: 0
a[1][0]: 1
a[1][1]: 2
a[2][0]: 2
a[2][1]: 4
a[3][0]: 3
a[3][1]: 6
a[4][0]: 4
a[4][1]: 8

Truyền mảng như là các tham số phương thức trong C#

Bạn có thể truyền một mảng như là một tham số phương thức trong C#. Dưới đây là ví dụ minh họa khái niệm này:

using System;

namespace ArrayApplication 
{
   class MyArray 
   {
      double GetAverage(int[] arr, int size) 
      {
         int sum = 0;         
         for (int i = 0; i < size; i++) 
         {
            sum += arr[i];
         }
         double avg = (double)sum / size;
         return avg;
      }
      
      static void Main(string[] args) 
      {
         MyArray app = new MyArray();
         
         int[] balance = new int[] {1000, 2, 3, 17, 50};
         double avg = app.GetAverage(balance, balance.Length);

         Console.WriteLine("Average value is: {0} ", avg);
         Console.ReadLine();
      }
   }
}

Kết quả khi chạy chương trình:

Average value is: 214.4

Mảng tham số trong C#

Đôi khi, trong khi khai báo một phương thức, bạn không chắc chắn về số lượng đối số được truyền dưới dạng tham số. Các mảng tham số trong C# sẽ giúp giải quyết vấn đề này.

Ví dụ sau đây minh họa điều này:

using System;

namespace ArrayApplication 
{
   class ParamArray 
   {
      public int AddElements(params int[] arr) 
      {
         int sum = 0;         
         foreach (int i in arr) 
         {
            sum += i;
         }
         return sum;
      }
   }
   class TestClass 
   {
      static void Main(string[] args) 
      {
         ParamArray app = new ParamArray();
         int sum = app.AddElements(512, 720, 250, 567, 889);
         
         Console.WriteLine("The sum is: {0}", sum);
         Console.ReadKey();
      }
   }
}

Kết quả khi chạy chương trình trên:

The sum is: 2938

Lớp Array trong C#

Lớp Array là lớp cơ sở cho tất cả các mảng trong C#. Nó được định nghĩa trong namespace System. Lớp Array cung cấp các thuộc tính và phương thức khác nhau để làm việc với mảng.

Thuộc tính của lớp Array

Bảng sau đây mô tả một số thuộc tính được sử dụng phổ biến nhất của lớp Array:

STT Thuộc tính Mô tả
1 IsFixedSize Cho biết Array có kích thước cố định hay không.
2 IsReadOnly Cho biết Array chỉ đọc.
3 Length Tổng số phần tử của Array (integer)
4 LongLength Tổng số phần tử của Array (long)
5 Rank Lấy số chiều của Array

Các phương thức của lớp Array

Bảng sau đây mô tả một số phương thức được sử dụng phổ biến nhất của lớp Array:

STT Phương thức Mô tả
1 Clear Thiết lập một dãy các phần tử trong Array về 0, về false hoặc về null, phụ thuộc vào kiểu phần tử
2 Copy(Array, Array, Int32) Sao chép một dãy các phần tử từ một Array bắt đầu từ phần tử đầu tiên và paste chúng vào trong Array khác bắt đầu tại phần tử đầu tiên. Độ dài (length) được xác định là một integer (32 bit)
3 CopyTo(Array, Int32) Sao chép tất cả phần tử của Array một chiều hiện tại tới Array một chiều đã xác định bắt đầu tại chỉ mục mảng đích đến đã cho. Chỉ mục được xác định là một integer (32 bit)
4 GetLength Lấy một số integer (32 bit) mà biểu diễn số phần tử trong chiều đã xác định của Array
5 GetLongLength Lấy một số integer (64 bit) mà biểu diễn số phần tử trong chiều đã xác định của Array
6 GetLowerBound Lấy giới hạn thấp hơn của chiều đã xác định trong Array
7 GetType Lấy kiểu của instance (sự thể hiện) hiện tại (được kế thừa từ Object)
8 GetUpperBound Lấy giới hạn ở trên của chiều đã xác định trong Array
9 GetValue(Int32) Lấy giá trị tại vị trí đã xác định trong mảng một chiều. Chỉ mục được xác định là số integer (32)
10 IndexOf(Array, Object) Tìm kiếm object đã cho và trả về chỉ mục về sự xuất hiện đầu tiên bên trong cả mảng một chiều đó
11 Reverse(Array) ngược dãy phần tử trong cả mảng một chiều đó
12 SetValue(Object, Int32) Thiết lập giá trị cho phần tử tại vị trí đã cho trong mảng một chiều. Chỉ mục được xác định là một số integer (32 bit)
13 Sort(Array) Sắp xếp các phần tử trong cả mảng một chiều bởi sử dụng IComparable implementation của mỗi phần tử của mảng đó
14 ToStringk Trả về một chuỗi mà biểu diễn object hiện tại (được kế thừa từ Object)

Để có danh sách đầy đủ các thuộc tính và phương thức của lớp Array, bạn tham khảo tài liệu của Microsoft về C#.

Ví dụ

using System;

namespace ArrayApplication 
{
   class MyArray 
   {
      static void Main(string[] args) 
      {
         int[] list = { 34, 72, 13, 44, 25, 30, 10 };
         int[] temp = list;
         Console.Write("Original Array: ");
         
         foreach (int i in list) 
         {
            Console.Write(i + " ");
         }
         Console.WriteLine();
         
         // reverse the array
         Array.Reverse(temp);
         Console.Write("Reversed Array: ");
         
         foreach (int i in temp) 
         {
            Console.Write(i + " ");
         }
         Console.WriteLine();
         
         //sort the array
         Array.Sort(list);
         Console.Write("Sorted Array: ");
         
         foreach (int i in list) 
         {
            Console.Write(i + " ");
         }
         Console.WriteLine();
         Console.ReadKey();
      }
   }
}

Kết quả khi chạy chương trình trên:

Original Array: 34 72 13 44 25 30 10
Reversed Array: 10 30 25 44 13 72 34
Sorted Array: 10 13 25 30 34 44 72

Bạn có muốn xem bài viết tiếp theo không? Nó ở dưới đây nè.

Chuỗi trong C# | Comdy
Chuỗi được sử dụng rất thường xuyên trong C#. Bài viết này sẽ giúp bạn nắm vững các kiến thức về chuỗi trong C#.


Bài viết liên quan:

Hướng dẫn này sẽ giúp bạn tìm hiểu về đọc ghi file (File I/O) trong C# và sử dụng các lớp tiện ích để đọc ghi file.

Reflection trong C#

  • 6 min read

Reflection trong C# là gì? Ứng dụng của Reflection trong C#. Cách khai báo và sử dụng Reflection trong C#.

Attribute trong C#

  • 7 min read

Attribute trong C# là gì? Có những loại attribute nào trong C#? Làm sao để sử dụng attribute trong C#.