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ẽ.

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

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ụ:
[code language=”csharp”]int[] arrInt;[/code]

=> Đâ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ử.

[code language=”csharp”] // ① 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];
[/code]

・ 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:

[code language=”csharp”] // ①
string[] arrNumber1 = { "One", "Two", "Three" };

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

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

#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:

[code language=”csharp” highlight=”21,29″] 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();
}
}
}
[/code]

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 = ?
[code language=”csharp” highlight=”12,15″] 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);
}
}
}
[/code]

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:
[code language=”csharp” highlight=”13,20″] 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);
}
}
}
[/code]

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 ?
[code language=”csharp” highlight=”13,18,20″] 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();
}
}
}
[/code]

– 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:

[code language=”csharp”] // 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} };
[/code]

– 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:

[code language=”csharp” highlight=”15,17,19″] 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();
}
}
}
[/code]

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!

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 bạn đọ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[...]

3 bình luận

Translate »