Lập trình C#

Kiểu mảng array trong lập trình C#

Kiểu mảng array trong lập trình C#
Được viết bởi Minh Hoàng

Series lập trình C#, ngôn ngữ lập trình hiện đại và mạnh mẽ.

Mảng là tập hợp của các phần tử có kích cỡ cố định và có cùng kiểu dữ liệu. Các phần tử trong mảng sẽ nằm tại các vị trí ô nhớ nhớ liền kề nhau. Địa chỉ thấp nhất tương ứng với thành viên đầu tiên và địa chỉ cao nhất tương ứng với thành viên cuối cùng của mảng.

– Dựa vào cách mảng lưu trữ các phần tử mà trong C# mảng được chia thành 2 loại:

  1. Mảng một chiều (Single-dimensional Arrays)
  2. Mảng đa chiều (Multi-dimensional Arrays)
    1. Mảng hai chiều
    2. Jagged Array (Array of Arrays)

– Tất cả các loại mảng trên được dẫn xuất ngầm định từ lớp System.Array (có nguồn gốc từ System.Object). Vì vậy, trong C# mảng thuộc kiểu tham chiếu, được quản lý và cấp phát trên vùng nhớ heap. Xem thêm: Array Types in .NET (link MSDN).

1. Mảng một chiều trong C#
1. Mảng một chiều trong C#

#1. Cú pháp khai báo:

Kiểu_dữ_liệu[] tên_mảng;

・ Kiểu dữ liệu sẽ là kiểu của các phần tử trong mảng (có thể là kiểu giá trị, hoặc kiểu tham chiếu).
・ Cặp dấu ngoặc vuông [] báo cho trình biên dịch biết rằng chúng ta đang khai báo một mảng.

Ví dụ:

int[] arrInt;

=> Đây mới chỉ là khai báo nên mảng sẽ có giá trị là null, do đó lúc này chưa thể sử dụng được, nếu truy xuất vào phần tử của mảng sẽ phát sinh ngoại lệ null exception.

#2. Cấp phát bộ nhớ cho mảng:
Chúng ta dùng từ khóa new với cú pháp:

Kiểu_dữ_liệu[] tên_mảng = new Kiểu_dữ_liệu[Tổng_số_phần_tử];

Ví dụ:
Khai báo và cấp phát 10 ô nhớ cho mảng, tức là mảng có thể chứa được 10 phần tử.

// ① Mảng có kiểu giá trị
int[] arrInt = new int[10];

// ② Mảng có kiểu là tham chiếu
SinhVien[] arrSv = new SinhVien[10];

・ Trường hợp ① Mảng có kiểu giá trị: sẽ tạo ra một mảng có 10 số nguyên, mỗi phần tử sẽ có giá trị mặc định là 0.
・ Trường hợp ② Mảng có kiểu là tham chiếu: sẽ tạo ra một mảng có 10 đối tượng sinh viên, các phần tử này sẽ được khởi tạo giá trị mặc định là null. Nếu bây giờ chúng ta truy xuất các phần tử của mảng sẽ phát sinh ngoại lệ null exception.

#3. Khai báo và khởi tạo giá trị cho mảng:

Chúng ta có thể khởi tạo các phần tử của một mảng ngay lúc khai báo mảng bằng cách đặt những giá trị khởi tạo bên trong dấu ngoặc kép {} bằng một trong các cách sau:

// ①
string[] arrNumber1 = { "One", "Two", "Three" };

// ②
string[] arrNumber2 = new[] { "One", "Two", "Three" };

// ③
string[] arrNumber3 = new string[5] { "One", "Two", "Three" };

#4. Truy cập phần tử và duyệt mảng:

– Phần tử đầu tiên của mảng có chỉ số là 0 và phần tử cuối cùng có chỉ số n – 1 (trong đó n là số lượng phần tử có trong mảng). Do đó, giả sử chúng ta có một mảng 5 phần tử thì giá trị của các phần tử lần lượt là: a[0], a[1], a[2], a[3], a[4].

Minh họa mảng một chiều có 5 phần tử

Minh họa mảng một chiều có 5 phần tử


– Để truy cập vào phần tử trong mảng chúng ta sử dụng toán tử chỉ mục là 2 dấu ngoặc vuông []. Vị trí phần tử bắt đầu của mảng là 0, do đó chỉ số của phần tử đầu tiên của mảng luôn luôn là 0. Như ví dụ trên thì phần tử đầu tiên là arrNumber1[0] hay arrNumber2[0] hay arrNumber3[0].

– Để duyệt mảng thì chúng ta, sử dụng câu lệnh for hoặc foreach như ví dụ sau:

using System;

namespace MinhHoangBlog
{
	class Program
	{
		static void Main(string[] args)
		{
			// Khai báo mảng
			int[] myArray;

			// Nhập số phần tử cho mảng
			Console.Write( "Nhap so luong phan tu cua mang: " );
			int total = Convert.ToInt32( Console.ReadLine() );

			// Cấp phát vùng nhớ cho mảng
			myArray = new int[total];

			// Duyệt mảng bằng for(), nhập giá trị cho mảng
			Console.WriteLine( "\n--- Nhap mang ---" );
			for ( int ii = 0; ii < myArray.Length; ii++ )
			{
				Console.Write( "Nhap phan tu thu {0}: ", ii );
				myArray[ii] = Convert.ToInt32( Console.ReadLine() );
			}

			// Duyệt mảng bằng foreach(), in giá trị của mảng
			Console.WriteLine( "\n---- In mang ----" );
			foreach ( var item in myArray )
			{
				Console.Write( item + " " );
			}

			Console.ReadKey();
		}
	}
}
Kết quả chương trình

Kết quả chương trình

#5. Hỏi xoáy đáp xoay:
Để hiểu rõ hơn về mảng một chiều chúng ta sẽ xem xét 2 ví dụ bên dưới:

Ví dụ 1:
– Theo bạn kết quả của chương trình dưới thì myArray[0] = ?Size = ?
– Sau khi quyết định xong thì click tab Đáp xoay xem kết quả nhé.

using System;

namespace MinhHoangBlog
{
	class Program
	{
		static void Main(string[] args)
		{
			// Khai báo vào khởi tạo mảng
			int[] myArray = { 1, 2, 3, 4 };

			ChangeValueArray(myArray);
			Console.WriteLine("myArray[0] = {0}", myArray[0]);

			ResizeArray(myArray);
			Console.WriteLine("Size = {0}", myArray.Length);

			Console.ReadKey();
		}

		static void ChangeValueArray(int[] arr)
		{
			arr[0] = 99;
		}

		static void ResizeArray(int[] arr)
		{
			Array.Resize(ref arr, 8);
		}
	}
}

myArray[0] = 99 : Vì kiểu mảng là kiểu tham chiếu, xem thêm: Tham trị, tham chiếu trong lập trình C#

Size = 4 : Bởi vì 2 lý do sau:

  1. Tất cả tham số khi truyền vào hàm thì mặc định được truyền theo kiểu giá trị (truyền bằng tham trị), bất kể nó là loại tham chiếu hay tham trị.
  2. Đối với kiểu Array thì số lượng phần tử đã cấp phát sẽ là cố định không thay đổi được. Khi chúng ta sử dụng phương thức Array.Resize() không phải thực hiện thay đổi kích thước mảng mà nó thực hiện bằng cách:
    1. Tạo một mảng mới, sau đó copy toàn bộ dữ liệu sang.
    2. Cuối cùng gắn tham chiếu vào lại mảng cũ.

=> Do đó, chúng ta muốn thay đổi được kích thước của mảng thì cần chỉ định tham số mảng truyền vào là kiểu tham chiếu bằng cách dùng từ khóa ref, khi đó câu lệnh sẽ được viết lại như sau:

using System;

namespace MinhHoangBlog
{
	class Program
	{
		static void Main(string[] args)
		{
			// Khai báo vào khởi tạo mảng
			int[] myArray = { 1, 2, 3, 4 };

			//ResizeArray(myArray);
			ResizeArray(ref myArray);
			Console.WriteLine("Size = {0}", myArray.Length);    // Size = 8

			Console.ReadKey();
		}

		//static void ResizeArray(int[] arr)
		static void ResizeArray(ref int[] arr)
		{
			Array.Resize(ref arr, 8);
		}
	}
}
Ví dụ 2:
– Theo bạn kết quả của chương trình dưới thì ở các lần in ra màn hình thì kết quả của t1 , t2 bằng bao nhiêu ?
– Sau khi quyết định xong thì click tab Đáp xoay xem kết quả nhé.

using System;

namespace MinhHoangBlog
{
	class Program
	{
		static void Main(string[] args)
		{
			string[] array = new[] { "One", "Two" };

			var t1 = array[0];

			Console.WriteLine("t1 = {0}", t1);

			var t2 = t1;
			t2 = "Three";

			Console.WriteLine("t2 = {0}", t2);

			Console.WriteLine("t1 = {0}", t1);

			Console.ReadKey();
		}
	}
}

– Kết quả là:

t1 = One

t2 = Three

t1 = One

– Kiểu String cũng là một reference type. Nên khi viết:

var t1 = data[0];

– Tức là khai báo một biến mới t1 cho tham chiếu đến cùng một chuỗi như data[0]. Tiếp theo:

var t2 = t1;

– Khai báo một biến mới t2 cho tham chiếu đến cùng một chuỗi như t1. Và bây giờ chúng ta sẽ có một object String trên vùng nhớ heap, mà có 3 tham chiếu đến object này là: data[0], t1t2. Tiếp theo:

t2 = "Three";

– Sau câu lệnh này thì t2 sẽ trỏ đến một object String khác trên vùng nhớ heap có giá trị là “Three”. Tuy nhiên, data[0]t1 vẫn đang cùng trỏ đến object String ban đầu.

– Để dễ hình dung, các bạn có thể theo dõi hình bên dưới:

Minh họa

Minh họa

2. Mảng hai chiều trong C#
2. Mảng hai chiều trong C#

– Không giống như mảng một chiều, mảng hai chiều cho phép chúng ta lưu trữ dữ liệu trên nhiều dòng. Kích thước của mảng được xác định dựa vào số dòng và số cột tương tự như một sheet trong Microsoft Excel.

– Các cách khai báo mảng hai chiều như sau:

// Khai báo
int[,] array1;

// Khai báo và cấp phát vùng nhớ: 3 hàng, 4 cột
int[,] array2 = new int[3, 4];

// Khai báo, cấp phát vùng nhớ và khởi tạo
int[,] array3 = new int[3, 4] { {0, 8, 0, 6},
								{2, 0, 1, 7},
								{6, 7, 8, 9} };

– Truy cập phần tử của mảng cũng dùng cặp dấu ngoặc vuông [chỉ số dòng,chỉ số cột]. Ví dụ chúng ta muốn truy cập vào phần tử ở dòng 2, cột 3 thì sẽ ghi là: array[2,3].

– Để duyệt mảng thì chúng ta sẽ dùng 2 vòng for như sau:

using System;

namespace MinhHoangBlog
{
	class Program
	{
		static void Main(string[] args)
		{
			// Khai báo, cấp phát vùng nhớ và khởi tạo
			int[,] arr = new int[3, 4] { {0, 8, 0, 6},
										 {2, 0, 1, 7},
										 {6, 7, 8, 9} };

			// In mảng
			for ( int row = 0; row < 3; row++ )
			{
				for ( int col = 0; col < 4; col++ )
				{
					Console.Write( arr[row,col] + " " );
				}
				Console.WriteLine();
			}

			Console.ReadKey();
		}
	}
}
3. Jagged Array trong C#
3. Jagged Array trong C#

– Chúng ta thấy mảng hai chiều được ứng nhiều trong thực tế. Tuy nhiên, mảng hai chiều cũng có sự cứng nhắc về cách khai báo. Đó là: hàng đầu tiên của mảng hay bất kỳ hàng nào cũng phải có cùng số cột (số cột phải giống nhau).

– Trong trường hợp chúng ta mong muốn một cấu trúc mảng mà hàng đầu tiên có 2 cột, hàng thứ 2 có 3 cột, hàng thứ 3 có 4 cột,… thì với cách khai báo của mảng hai chiều sẽ không đáp ứng được yêu cầu như vậy.

– Do đó, đã ra đời cách khai báo Jagged Array trong C#. Và cũng giống mảng hai chiều là một Jagged Array trong C# là một mảng của các mảng.

– Cách khai báo một Jagged Array

Kiểu_dữ_liệu[][] tên_mảng;

– Khai báo, cấp phát vùng nhớ và khởi tạo một Jagged Array

int[][] jaggedArr = new int[2][]
{
	new int[] { 97, 98, 99 },
	new int[] { 1, 2, 3, 4 }
};

Trong đó:

  • jaggedArr là một mảng có 2 dòng (mỗi dòng là một mảng integer) và số cột bao nhiêu là chưa biết.
  • jaggedArr[0] là một mảng 3 số nguyên integer: 97, 98, 99
  • jaggedArr[1] là một mảng 4 số nguyên integer: 1, 2, 3, 4

– Minh họa Jagged Array:
Ví dụ 1:

using System;

namespace MinhHoangBlog
{
	class Program
	{
		static void Main(string[] args)
		{
			/* Khai báo một jagged array gồm 5 mảng con kiểu integer */
			int[][] a = new int[][]
			{
				new int[] { 0, 0 },
				new int[] { 1, 2 },
				new int[] { 2, 4 },
				new int[] { 3, 6 },
				new int[] { 4, 8 }
			};

			/* In giá trị từng mảng con của jagged array */
			for (int row = 0; row < 5; row++)
			{
				for (int col = 0; col < 2; col++)
				{
					Console.Write("a[{0}][{1}] = {2}\t", row, col, a[row][col]);
				}
				Console.WriteLine();
			}
			Console.ReadKey();
		}
	}
}
Kết quả chương trình

Kết quả chương trình

Ví dụ 2:

using System;

namespace MinhHoangBlog
{
	class Program
	{
		static void Main(string[] args)
		{
			// Khai báo một jagged array A kiểu integer
			int[][] A;

			// Khởi tạo mảng A: 5 dòng, số cột chưa biết
			A = new int[5][];

			/* Khởi tạo số cột cho từng dòng:
			 * row đầu tiên có 1 col
			 * row thứ 2 có 2 col 
			 * row thứ 3 có 3 col
			 * row thứ 4 có 4 col
			 * row thứ 5 có 5 col
			 */
			for (int row = 0; row < A.Length; row++)
			{
				A[row] = new int[row + 1];
			}

			// Nhập liệu và in mảng ra màn hình
			for ( int row = 0; row < 5; row++ )
			{
				for ( int col = 0; col < A[row].Length; col++ )
				{
					A[row][col] = row + col;
					Console.Write( A[row][col] + " " );
				}
				Console.WriteLine();
			}

			Console.ReadKey();
		}
	}
}
Kết quả chương trình

Kết quả chương trình

Cảm ơn bạn đã theo dõi. Đừng ngần ngại hãy cùng thảo luận với chúng tôi! Minh Hoàng Blog | Nào cùng vui hehe


Giới thiệu

Minh Hoàng

Xin chào, tôi là Hoàng Ngọc Minh, hiện đang làm BrSE, tại công ty Toyota, Nhật Bản. Những gì tôi viết trên blog này là những trải nghiệm thực tế tôi đã đúc rút ra được trong cuộc sống, quá trình học tập và làm việc. Các bài viết được biên tập một cách chi tiết, linh hoạt để giúp người đọc có thể tiếp cận một cách dễ dàng nhất. Hi vọng nó sẽ có ích hoặc mang lại một góc nhìn khác cho bạn[…]

Bình luận của bạn

1 bình luận cho bài viết "Kiểu mảng array trong lập trình C#"

avatar
Sắp xếp theo:   Mới nhất | Cũ nhất | Thích nhiều nhất
trackback

[…] – Nếu chúng ta muốn viết một tham số kiểu như vậy thì trong C# cung cấp từ khóa params để thực hiện điều này. Và tham số được truyền vào đi kèm với từ khóa params chỉ được phép là mảng một chiều. […]

Chúc bạn có một cuộc sống ngoại hạng!