GIÁO TRÌNH

Giáo trình ngôn ngữ lập trình C#

Science and Technology

Mảng

Tác giả: Khuyet Danh

Ngôn ngữ C# cung cấp cú pháp chuẩn cho việc khai báo những đối tượng Array. Tuy nhiên, cái thật sự được tạo ra là đối tượng của kiểu System.Array. Mảng trong ngôn ngữ C# kết hợp cú pháp khai báo mảng theo kiểu ngôn ngữ C và kết hợp với định nghĩa lớp do đó thể hiện của mảng có thể truy cập những phương thức và thuộc tính của System.Array.

Một số các thuộc tính và phương thức của lớp System.Array

Các phương thức và thuộc tính của System.Array
Thành viên Mô tả
BinarySearch() Phương thức tĩnh public tìm kiếm một mảng một chiều đãsắp thứ tự.
Clear() Phương thức tĩnh public thiết lập các thành phần của mảngvề 0 hay null.
Copy() Phương thức tĩnh public đã nạp chồng thực hiện sao chépmột vùng của mảng vào mảng khác.
CreateInstance() Phương thức tĩnh public đã nạp chồng tạo một thể hiện mớicho mảng
IndexOf() Phương thức tĩnh public trả về chỉ mục của thể hiện đầu tiênchứa giá trị trong mảng một chiều
LastIndexOf() Phương thức tĩnh public trả về chỉ mục của thể hiện cuốicùng của giá trị trong mảng một chiều
Reverse() Phương thức tĩnh public đảo thứ tự của các thành phần trongmảng một chiều
Sort() Phương thức tĩnh public sắp xếp giá trị trong mảng mộtchiều.
IsFixedSize Thuộc tính public giá trị bool thể hiện mảng có kích thướccố định hay không.
IsReadOnly Thuộc tính public giá trị bool thể hiện mảng chỉ đọc haykhông
IsSynchronized Thuộc tính public giá trị bool thể hiện mảng có hỗ trợ thread-safe
Length Thuộc tính public chiều dài của mảng
Rank Thuộc tính public chứa số chiều của mảng
SyncRoot Thuộc tính public chứa đối tượng dùng để đồng bộ truy cậptrong mảng
GetEnumerator() Phương thức public trả về IEnumerator
GetLength() Phương thức public trả về kích thước của một chiều cố địnhtrong mảng
GetLowerBound() Phương thức public trả về cận dưới của chiều xác định trongmảng
GetUpperBound() Phương thức public trả về cận trên của chiều xác định trongmảng
Initialize() Khởi tạo tất cả giá trị trong mảng kiểu giá trị bằng cách gọibộ khởi dụng mặc định của từng giá trị.
SetValue() Phương thức public thiết lập giá trị cho một thành phần xácđịnh trong mảng.

Khai báo mảng

Chúng ta có thể khai báo một mảng trong C# với cú pháp theo sau:

<kiểu dữ liệu>[] <tên mảng>

Ta có khai báo như sau:

int[] myIntArray;

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. Kiểu dữ liệu là kiểu của các thành phần chứa bên trong mảng. Trong ví dụ bên trên. myIntArray được khai báo là mảng số nguyên.

Chúng ta tạo thể hiện của mảng bằng cách sử dụng từ khóa new như sau:

myIntArray = new int[6];

Khai báo này sẽ thiết lập bên trong bộ nhớ một mảng chứa sáu số nguyên.

Dành cho lập trình viên Visual Basic, thành phần đầu tiên luôn bắt đầu 0, không có cách nào thiết lập cận trên và cận dưới của mảng, và chúng ta cũng không thể thiết lập lại kích thước của mảng.

Điều quan trọng để phân biệt giữa bản thân mảng (tập hợp các thành phần) và các thành phần trong mảng. Đối tượng myIntArray là một mảng, thành phần là năm số nguyên được lưu giữ. Mảng trong ngôn ngữ C# là kiểu dữ liệu tham chiếu, được tạo ra trên heap. Do đó myIntArray được cấp trên heap. Những thành phần của mảng được cấp phát dựa trên các kiểu dữ liệu của chúng. Số nguyên là kiểu dữ liệu giá trị, và do đó những thành phần của myIntArray là kiểu dữ liệu giá trị, không phải số nguyên được boxing. Một mảng của kiểu dữ liệu tham chiếu sẽ không chứa gì cả nhưng tham chiếu đến những thành phần được tạo ra trên heap.

Giá trị mặc định

Khi chúng ta tạo một mảng có kiểu dữ liệu giá trị, mỗi thành phần sẽ chứa giá trị mặc định của kiểu dữ liệu (xem bảng 4.2, kiểu dữ liệu và các giá trị mặc định). Với khai báo:

myIntArray = new int[5];

sẽ tạo ra một mảng năm số nguyên, và mỗi thành phần được thiết lập giá trị mặc định là 0, đây cũng là giá trị mặc định của số nguyên.

Không giống với mảng kiểu dữ liệu giá trị, những kiểu tham chiếu trong một mảng không được khởi tạo giá trị mặc định. Thay vào đó, chúng sẽ được khởi tạo giá trị null. Nếu chúng ta cố truy cập đến một thành phần trong mảng kiểu dữ liệu tham chiếu trước khi chúng được khởi tạo giá trị xác định, chúng ta sẽ tạo ra một ngoại lệ.

Giả sử chúng ta tạo ra một lớp Button. Chúng ta khai báo một mảng các đối tượng Button với cú pháp sau:

Button[] myButtonArray;

và chúng ta tạo thể hiện của mảng như sau:

myButtonArray = new Button[3];

Chúng ta có thể viết ngắn gọn như sau:

Button muButtonArray = new Button[3];

Không giống với ví dụ mảng số nguyên trước, câu lệnh này không tao ra một mảng với những tham chiếu đến ba đối tượng Button. Thay vào đó việc này sẽ tạo ra một mảng myButtonArray với ba tham chiếu null. Để sử dụng mảng này, đầu tiên chúng ta phải tạo và gán đối tượng Button cho từng thành phần tham chiếu trong mảng. Chúng ta có thể tạo đối tượng trong vòng lặp và sau đó gán từng đối tượng vào trong mảng.

Truy cập các thành phần trong mảng

Để truy cập vào thành phần trong mảng ta có thể sử dụng toán tử chỉ mục ([]). Mảng dùng cơ sở 0, do đó chỉ mục của thành phần đầu tiên trong mảng luôn luôn là 0. Như ví dụ trước thành phần đầu tiên là myArray[0].

Như đã trình bày ở phần trước, mảng là đối tượng, và do đó nó có những thuộc tính. Một trong những thuộc tính hay sử dụng là Length, thuộc tính này sẽ báo cho biết số đối tượng trong một mảng. Một mảng có thể được đánh chỉ mục từ 0 đến Length –1. Do đó nếu có năm thành phần trong mảng thì các chỉ mục là: 0, 1, 2, 3, 4.

Ví dụ sau minh họa việc sử dụng các khái niệm về mảng từ đầu chương tới giờ. Trong ví dụ một lớp tên là Tester tạo ra một mảng kiểu Employee và một mảng số nguyên. Tạo các đối tượng Employee sau đó in hai mảng ra màn hình.

Làm việc với một mảng.

-----------------------------------------------------------------------------

namespace Programming_CSharp { using System; // tạo một lớp đơn giản để lưu trữ trong mảng public class Employee { // bộ khởi tạo lấy một tham số public Employee( int empID ) { this.empID = empID; } public override string ToString() { return empID.ToString(); } // biến thành viên private private int empID; private int size; } public class Tester { static void Main() { int[] intArray; Employee[] empArray; intArray = new int[5]; empArray = new Employee[3]; // tạo đối tượng đưa vào mảng for( int i = 0; i < empArray.Length; i++) { empArray[i] = new Employee(i+5); } // xuất mảng nguyên for( int i = 0; i < intArray.Length; i++) { Console.Write(intArray[i].ToString()+"\t"); } // xuất mảng Employee for( int i = 0; i < empArray.Length; i++) { Console.WriteLine(empArray[i].ToString()+"\t"); } } } }

-----------------------------------------------------------------------------

Kết quả:

0 0 0 0 0 5 6 7

-----------------------------------------------------------------------------

Ví dụ bắt đầu với việc định nghĩa một lớp Employee, lớp này thực thi một bộ khởi dựng lấy một tham số nguyên. Phương thức ToString() được kế thừa từ lớp Object được phủ quyết để in ra giá trị empID của đối tượng Employee.

Các kiểu tạo ra là khai báo rồi mới tạo thể hiện của hai mảng. Mảng số nguyên được tự động thiết lập giá trị 0 mặc định cho từng số nguyên trong mảng. Nội dung của mảng Employee được tạo bằng các lệnh trong vòng lặp.

Cuối cùng, nội dung của cả hai mảng được xuất ra màn hình console để đảm bảo kết quả như mong muốn; năm giá trị đầu của mảng nguyên, ba số sau cùng là của mảng Employee.

Khởi tạo thành phần của mảng

Chúng ta có thể khởi tạo nội dung của một mảng ngay lúc tạo thể hiện của mảng bằng cách đặt những giá trị bên trong dấu ngoặc ({}). C# cung cấp hai cú pháp để khởi tạo các thành phần của mảng, một cú pháp dài và một cú pháp ngắn:

int[] myIntArray = new int[5] { 2, 4, 6, 8, 10};

int[] myIntArray = { 2, 4, 6, 8, 10};

Không có sự khác biệt giữa hai cú pháp trên, và hầu hết các chương trình đều sử dụng cú pháp ngắn hơn do sự tự nhiên và lười đánh nhiều lệnh của người lập trình.

Sử dụng từ khóa params

Chúng ta có thể tạo một phương thức rồi sau đó hiển thị các số nguyên ra màn hình console bằng cách truyền vào một mảng các số nguyên và sử dụng vòng lặp foreach để duyệt qua từng thành phần trong mảng. Từ khóa params cho phép chúng ta truyền một số biến của tham số mà không cần thiết phải tạo một mảng.

Trong ví dụ kế tiếp, chúng ta sẽ tạo một phương thức tên DisplayVals(), phương thức này sẽ lấy một số các biến của tham số nguyên:

public void DisplayVals( params int[] intVals)

Phương thức có thể xem mảng này như thể một mảng được tạo ra tường minh và được truyền vào tham số. Sau đó chúng ta có thể tự do lặp lần lượt qua các thành phần trong mảng giống như thực hiện với bất cứ mảng nguyên nào khác:

foreach (int i in intVals)

{

Console.WriteLine("DisplayVals: {0}", i);

}

Tuy nhiên, phương thức gọi không cần thiết phải tạo tường minh một mảng, nó chỉ đơn giản truyền vào các số nguyên, và trình biên dịch sẽ kết hợp những tham số này vào trong một mảng cho phương thức DisplayVals, ta có thể gọi phương thức như sau:

t.DisplayVals(5,6,7,8);

và chúng ta có thể tự do tạo một mảng để truyền vào phương thức nếu muốn:

int [] explicitArray = new int[5] {1,2,3,4,5};

t.DisplayArray(explicitArray);

Ví dụ sau cung cấp tất cả mã nguồn để minh họa sử dụng cú pháp params.

Minh họa sử dụng params.

-----------------------------------------------------------------------------

namespace Programming_CSharp { using System; public class Tester { static void Main() { Tester t = new Tester(); t.DisplayVals(5,6,7,8); int[] explicitArray = new int[5] {1,2,3,4,5}; t.DisplayVals(explicitArray); } public void DisplayVals( params int[] intVals) { foreach (int i in intVals) { Console.WriteLine("DisplayVals {0}", i); } } } }

-----------------------------------------------------------------------------

Kết quả:

DisplayVals 5

DisplayVals 6

DisplayVals 7

DisplayVals 8

DisplayVals 1

DisplayVals 2

DisplayVals 3

DisplayVals 4

DisplayVals 5

-----------------------------------------------------------------------------

Câu lệnh lặp foreach

Câu lệnh lặp foreach khá mới với những người đã học ngôn ngữ C, từ khóa này được sử dụng trong ngôn ngữ Visual Basic. Câu lệnh foreach cho phép chúng ta lặp qua tất cả các mục trong một mảng hay trong một tập hợp.

Cú pháp sử dụng lệnh lặp foreach như sau:

foreach (<kiểu dữ liệu thành phần> <tên truy cập> in <mảng/tập hợp> ) { // thực hiện thông qua <tên truy cập> tương ứng với // từng mục trong mảng hay tập hợp }

Do vậy, chúng ta có thể cải tiến ví dụ trước bằng cách thay việc sử dụng vòng lặp for bằng vòng lặp foreach để truy cập đến từng thành phần trong mảng.

Sử dụng foreach.

-----------------------------------------------------------------------------

namespace Programming_CSharp { using System; // tạo một lớp đơn giản để lưu trữ trong mảng public class Employee { // bộ khởi tạo lấy một tham số public Employee( int empID ) { this.empID = empID; } public override string ToString() { return empID.ToString(); } // biến thành viên private private int empID; private int size; } public class Tester { static void Main() { int[] intArray; Employee[] empArray; intArray = new int[5]; empArray = new Employee[3]; // tạo đối tượng đưa vào mảng for( int i = 0; i < empArray.Length; i++) { empArray[i] = new Employee(i+10); } // xuất mảng nguyên foreach (int i in intArray) { Console.Write(i.ToString()+"\t"); } // xuất mảng Employee foreach ( Employee e in empArray) { Console.WriteLine(e.ToString()+"\t"); } } } }

Kết quả của ví dụ trên cũng tương tự như ví dụ trước. Tuy nhiên, với việc sử dụng vòng lặp for ta phải xác định kích thước của mảng, sử dụng biến đếm tạm thời để truy cập đến từng thành phần trong mảng:

for (int i = 0 ; i < empArray.Length; i++) { Console.WriteLine(empArray[i].ToString()); }

Thay vào đó ta sử dụng foreach , khi đó vòng lặp sẽ tự động trích ra từng mục tuần tự trong mảng và gán tạm vào một tham chiếu đối tượng khai báo ở đầu vòng lặp:

foreach ( Employee e in empArray) { Console.WriteLine(e.ToString()+"\t"); }

Đối tượng được trích từ mảng có kiểu dữ liệu tương ứng. Do đó chúng ta có thể sử dụng bất cứ thành viên public của đối tượng.

Mảng đa chiều

Từ đầu chương đến giờ chúng ta chỉ nói đến mảng các số nguyên hay mảng các đối tượng. Tất cả các mảng này đều là mảng một chiều. Mảng một chiều trong đó các thành phần của nó chỉ đơn giản là các đối tượng kiểu giá trị hay đối tượng tham chiếu. Mảng có thể được tổ chức phức tạp hơn trong đó mỗi thành phần là một mảng khác, việc tổ chức này gọi là mảng đa chiều.

Mảng hai chiều được tổ chức thành các dòng và cột, trong đó các dòng là được tính theo hàng ngang của mảng, và các cột được tính theo hàng dọc của mảng.

Mảng ba chiều cũng có thể được tạo ra nhưng thường ít sử dụng do khó hình dung. Trong mảng ba chiều những dòng bây giờ là các mảng hai chiều.

Ngôn ngữ C# hỗ trợ hai kiểu mảng đa chiều là:

Mảng đa chiều cùng kích thước: trong mảng này mỗi dòng trong mảng có cùng kích thước với nhau. Mảng này có thể là hai hay nhiều hơn hai chiều.

Mảng đa chiều không cùng kích thước: trong mảng này các dòng có thể không cùng kích thước với nhau.

Mảng đa chiều cùng kích thước

Mảng đa chiều cùng kích thước còn gọi là mảng hình chữ nhật (rectanguler array). Trong mảng hai chiều cổ điển, chiều đầu tiên được tính bằng số dòng của mảng và chiều thứ hai được tính bằng số cột của mảng.

Để khai báo mảng hai chiều, chúng ta có thể sử dụng cú pháp theo sau:

<kiểu dữ liệu> [,] <tên mảng>

Ví dụ để khai báo một mảng hai chiều có tên là myRectangularArray để chứa hai dòng và ba cột các số nguyên, chúng ta có thể viết như sau:

int [ , ] myRectangularArray;

Ví dụ tiếp sau đây minh họa việc khai báo, tạo thể hiện, khởi tạo và in nội dung ra màn hình của một mảng hai chiều. Trong ví dụ này, vòng lặp for được sử dụng để khởi tạo các thành phần trong mảng.

Mảng hai chiều.

-----------------------------------------------------------------------------

namespace Programming_CSharp { using System; public class Tester { static void Main() { // khai báo số dòng và số cột của mảng const int rows = 4; const int columns = 3; // khai báo mảng 4x3 số nguyên int [,] rectangularArray = new int[rows, columns]; // khởi tạo các thành phần trong mảng for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { rectangularArray[i,j] = i+j; } } // xuất nội dung ra màn hình for(int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { Console.WriteLine("rectangularArray[{0},{1}] = {2}", i, j, rectangularArray[i, j]); } } } } }

-----------------------------------------------------------------------------

Kết quả:

rectangularArray[0,0] = 0

rectangularArray[0,1] = 1

rectangularArray[0,2] = 2

rectangularArray[1,0] = 1

rectangularArray[1,1] = 2

rectangularArray[1,2] = 3

rectangularArray[2,0] = 2

rectangularArray[2,1] = 3

rectangularArray[2,2] = 4

rectangularArray[3,0] = 3

rectangularArray[3,1] = 4

rectangularArray[3,2] = 5

-----------------------------------------------------------------------------

Trong ví dụ này, chúng ta khai báo hai giá trị:

const int rows = 4;

const int columns = 3;

hai giá trị này được sử dụng để khai báo số chiều của mảng:

int [,] rectangularArray = new int[rows, columns];

Trong cú pháp này, dấu ngoặc vuông trong int[,] chỉ ra rằng đang khai báo một kiểu dữ liệu là mảng số nguyên, và dấu phẩy (,) chỉ ra rằng đây là mảng hai chiều (hai dấu phẩy khai báo mảng ba chiều, và nhiều hơn nữa). Việc tạo thể hiện thực sự của mảng ở lệnh new int[rows,columns] để thiết lập kích thước của mỗi chiều. Ở đây khai báo và tạo thể hiện được kết hợp với nhau.

Chương trình khởi tạo tất cả các giá trị các thành phần trong mảng thông qua hai vòng lặp for. Lặp thông qua mỗi cột của mỗi dòng. Do đó, thành phần đầu tiên được khởi tạo là rectangularArray[0,0], tiếp theo bởi rectangularArray[0,1] và đến rectangularArray[0,2]. Một khi điều này thực hiện xong thì chương trình sẽ chuyển qua thực hiện tiếp ở dòng tiếp tục: rectangularArray[1,0], rectangularArray[1,1], rectangularArray[1,2]. Cho đến khi tất cả các cột trong tất cả các dòng đã được duyệt qua tức là tất cả các thành phần trong mảng đã được khởi tạo.

Như chúng ta đã biết, chúng ta có thể khởi tạo mảng một chiều bằng cách sử dụng danh sách các giá trị bên trong dấu ngoặc ({}). Chúng ta cũng có thể làm tương tự với mảng hai chiều. Trong ví dụ sau khai báo mảng hai chiều rectangularArray, và khởi tạo các thành phần của nó thông qua các danh sách các giá trị trong ngoặc, sau đó in ra nội dung của nội dung.

Khởi tạo mảng đa chiều.

-----------------------------------------------------------------------------

namespace Programming_CSharp { using System; public class Tester { static void Main() { // khai báo biến lưu số dòng số cột mảng const int rows = 4; const int columns = 3; // khai báo và định nghĩa mảng 4x3 int[,] rectangularArray = { {0,1,2}, {3,4,5}, {6,7,8},{9,10,11} }; // xụất nội dung của mảng for( int i = 0; i < rows; i++) { for(int j = 0; j < columns; j++) { Console.WriteLine("rectangularArray[{0},{1}] = {2}", i, j, rectangularArray[i,j]); } } } } }

Kết quả:

rectangularArray[0,0] = 0

rectangularArray[0,1] = 1

rectangularArray[0,2] = 2

rectangularArray[1,0] = 3

rectangularArray[1,1] = 4

rectangularArray[1,2] = 5

rectangularArray[2,0] = 6

rectangularArray[2,1] = 7

rectangularArray[2,2] = 8

rectangularArray[3,0] = 9

rectangularArray[3,1] = 10

rectangularArray[3,2] = 11

-----------------------------------------------------------------------------

Ví dụ trên cũng tương tự như ví dụ trước, nhưng trong ví dụ này chúng ta thực hiện việc khởi tạo trực tiếp khi tạo các thể hiện:

int[,] rectangularArray = { {0,1,2}, {3,4,5}, {6,7,8},{9,10,11} };

Giá trị được gán thông qua bốn danh sách trong ngoặc móc, mỗi trong số đó là có ba thành phần, bao hàm một mảng 4x3.

Nếu chúng ta viết như sau:

int[,] rectangularArray = { {0,1,2,3}, {4,5,6,7}, {8,9,10,11} };

thì sẽ tạo ra một mảng 3x4.

Mảng đa chiều có kích khác nhau

Cũng như giới thiệu trước kích thước của các chiều có thể không bằng nhau, điều này khác với mảng đa chiều cùng kích thước. Nếu hình dạng của mảng đa chiều cùng kích thước có dạng hình chữ nhật thì hình dạng của mảng này không phải hình chữ nhật vì các chiều của chúng không điều nhau.

Khi chúng ta tạo một mảng đa chiều kích thước khác nhau thì chúng ta khai báo số dòng trong mảng trước. Sau đó với mỗi dòng sẽ giữ một mảng, có kích thước bất kỳ. Những mảng này được khai báo riêng. Sau đó chúng ta khởi tạo giá trị các thành phần trong những mảng bên trong.

Trong mảng này, mỗi chiều là một mảng một chiều. Để khai báo mảng đa chiều có kích thước khác nhau ta sử dụng cú pháp sau, khi đó số ngoặc chỉ ra số chiều của mảng:

<kiểu dữ liệu> [] [] ...

Chúng ta có thể khai báo mảng số nguyên hai chiều khác kích thước tên myJagged- Array như sau:

int [] [] myJaggedArray;

Chúng ta có thể truy cập thành phần thứ năm của mảng thứ ba bằng cú pháp: myJagged- Array[2][4].

Ví dụ sau tạo ra mảng khác kích thước tên myJaggedArray, khởi tạo các thành phần, rồi sau đó in ra màn hình. Để tiết kiệm thời gian, chúng ta sử dụng mảng các số nguyên để các thành phần của nó được tự động gán giá trị mặc định. Và ta chỉ cần gán một số giá trị cần thiết.

Mảng khác chiều.

-----------------------------------------------------------------------------

namespace Programming_CSharp { using System; public class Tester { static void Main() { const int rows = 4; // khai báo mảng tối đa bốn dòng int[][] jaggedArray = new int[rows][]; // dòng đầu tiên có 5 phần tử jaggedArray[0] = new int[5]; // dòng thứ hai có 2 phần tử jaggedArray[1] = new int[2]; // dòng thứ ba có 3 phần tử jaggedArray[2] = new int[3]; // dòng cuối cùng có 5 phần tử jaggedArray[3] = new int[5]; // khởi tạo một vài giá trị cho các thành phần của mảng jaggedArray[0][3] = 15; jaggedArray[1][1] = 12; jaggedArray[2][1] = 9; jaggedArray[2][2] = 99; jaggedArray[3][0] = 10; jaggedArray[3][1] = 11; jaggedArray[3][2] = 12; jaggedArray[3][3] = 13; jaggedArray[3][4] = 14; for(int i = 0; i < 5; i++) { Console.WriteLine("jaggedArray[0][{0}] = {1}", i, jaggedArray[0][i]); } for(int i = 0; i < 2; i++) { Console.WriteLine("jaggedArray[1][{0}] = {1}", i, jaggedArray[1][i]); } for(int i = 0; i < 3; i++) { Console.WriteLine("jaggedArray[2][{0}] = {1}", i, jaggedArray[2][i]); } for(int i = 0; i < 5; i++) { Console.WriteLine("jaggedArray[3][{0}] = {1}", i, jaggedArray[3][i]); } } } }

-----------------------------------------------------------------------------

Kết quả:

jaggedArray[0][0] = 0

jaggedArray[0][1] = 0

jaggedArray[0][2] = 0

jaggedArray[0][3] = 15

jaggedArray[0][4] = 0

jaggedArray[1][0] = 0

jaggedArray[1][1] = 12

jaggedArray[2][0] = 0

jaggedArray[2][1] = 9

jaggedArray[2][2] = 99

jaggedArray[3][0] = 10

jaggedArray[3][1] = 11

jaggedArray[3][2] = 12

jaggedArray[3][3] = 13

jaggedArray[3][4] = 14

-----------------------------------------------------------------------------

Trong ví dụ này, mảng được tạo với bốn dòng:

int[][] jaggedArray = new int[rows][];

Chiều thứ hai không xác định. Do sau đó chúng ta có thể khai báo mỗi dòng có kích thước khác nhau. Bốn lệnh sau tạo cho mỗi dòng một mảng một chiều có kích thước khác nhau:

// dòng đầu tiên có 5 phần tử

jaggedArray[0] = new int[5];

// dòng thứ hai có 2 phần tử

jaggedArray[1] = new int[2];

// dòng thứ ba có 3 phần tử

jaggedArray[2] = new int[3];

// dòng cuối cùng có 5 phần tử

jaggedArray[3] = new int[5];

Sau khi tạo các dòng cho mảng xong, ta thực hiện việc đưa các giá trị vào các thành phần của mảng. Và cuối cùng là xuất nội dung của mảng ra màn hình.

Khi chúng ta truy cập các thành phần của mảng kích thước bằng nhau, chúng ta đặt tất cả các chỉ mục của các chiều vào trong cùng dấu ngặc vuông:

rectangularArray[i,j]

Tuy nhiên với mảng có kích thước khác nhau ta phải để từng chỉ mục của từng chiều trong đấu ngoặc vuông riêng:

jaggedArray[i][j]

Chuyển đổi mảng

Những mảng có thể chuyển đổi với nhau nếu những chiều của chúng bằng nhau và nếu các kiểu của các thành phần có thể chuyển đổi được. Chuyển đổi tường minh giữa các mảng xảy ra nếu các thành phần của những mảng có thể chuyển đổi tường minh. Và ngược lại, chuyển đổi ngầm định của mảng xảy ra nếu các thành phần của những mảng có thể chuyển đổi ngầm định.

Nếu một mảng chứa những tham chiếu đến những đối tượng tham chiếu, một chuyển đổi có thể được tới một mảng của những đối tượng cơ sở. Ví dụ sau minh họa việc chuyển đổi một mảng kiểu Button đến một mảng những đối tượng.

Chuyển đổi giữa những mảng.

-----------------------------------------------------------------------------

namespace Programming_CSharp { using System; // tạo lớp để lưu trữ trong mảng public class Employee { public Employee( int empID) { this.empID = empID; } public override string ToString() { return empID.ToString(); } // biến thành viên private int empID; private int size; } public class Tester { // phương thức này lấy một mảng các object // chúng ta truyền vào mảng các đối tượng Employee // và sau đó là mảng các string, có sự chuyển đổi ngầm // vì cả hai điều dẫn xuất từ lớp object public static void PrintArray(object[] theArray) { Console.WriteLine("Contents of the Array: {0}", theArray.ToString()); // in ra từng thành phần trong mảng foreach (object obj in theArray) { // trình biên dịch sẽ gọi obj.ToString() Console.WriteLine("Value: {0}", obj); } } static void Main() { // tạo mảng các đối tượng Employee Employee[] myEmployeeArray = new Employee[3]; // khởi tạo các đối tượng của mảng for (int i = 0; i < 3; i++) { myEmployeeArray[i] = new Employee(i+5); } // hiểu thị giá trị của mảng PrintArray( myEmployeeArray ); // tạo mảng gồm hai chuỗi string[] array ={ "hello", "world"}; // xuất ra nội dung của chuỗi PrintArray( array ); } } }

-----------------------------------------------------------------------------

Kết quả:

Contents of the Array Programming_CSharp.Employee[]

Value: 5

Value: 6

Value: 7

Contents of the Array Programming_CSharp.String[]

Value: hello

Value: world

-----------------------------------------------------------------------------

Ví dụ trên bắt đầu bằng việc tạo một lớp đơn giản Employee như các ví dụ trước. Lớp Tester bây giờ được thêm một phương thức tĩnh PrintArray() để xuất nội dung của mảng, phương thức này có khai báo một tham số là mảng một chiều các đối tượng object:

public static void PrintMyArray( object[] theArray)

object là lớp cơ sở ngầm định cho tất cả các đối tượng trong môi trường .NET, nên nó được khai báo ngầm định cho cả hai lớp string và Employee.

Phương thức PrintArray thực hiện hai hành động. Đầu tiên, là gọi phương thức ToString() của mảng:

Console.WriteLine("Contents of the Array {0}", theArray.ToString());

Tên của kiểu dữ liệu mảng được in ra:

Contents of the Array Programming_CSharp.Employee[]

...

Contents of the Array System.String[]

Sau đó phương thức PrintArray thực hiện tiếp việc gọi phương thức ToString() trong mỗi thành phần trong mảng nhận được. Do ToString() là phương thức ảo của lớp cơ sở object, và chúng ta đã thực hiện phủ quyết trong lớp Employee. Nên phương thức ToString() của lớp Employee được gọi. Việc gọi ToString() có thể không cần thiết, nhưng nếu gọi thì cũng không có hại gì và nó giúp cho ta đối xử với các đối tượng một cách đa hình.

System.Array

Lớp mảng Array chứa một số các phương thức hữu ích cho phép mở rộng những khả năng của mảng và làm cho mảng mạnh hơn những mảng trong ngôn ngữ khác (xem bảng 9.1). Hai phương thức tĩnh hữu dụng của lớp Array là Sort() và Reverse(). Có một cách hỗ trợ đầy đủ cho những kiểu dữ liệu nguyên thủy như là kiểu. Đưa mảng làm việc với những kiểu khác như Button có một số khó khăn hơn. Ví dụ sau minh họa việc sử dụng hai phương thức để thao tác đối tượng chuỗi.

Sử dụng Array.Sort() và Array.Reverse().

-----------------------------------------------------------------------------

namespace Programming_CSharp { using System; public class Tester { public static void PrintArray(object[] theArray) { foreach( object obj in theArray) { Console.WriteLine("Value: {0}", obj); } Console.WriteLine("\n"); } static void Main() { string[] myArray = { "Who", "is","Kitty","Mun" }; PrintArray( myArray ); Array.Reverse( myArray ); PrintArray( myArray ); string[] myOtherArray = { "Chung", "toi", "la", "nhung","nguoi","lap","trinh", "may", "tinh" }; PrintArray( myOtherArray ); Array.Sort( myOtherArray ); PrintArray( myOtherArray ); } } }

-----------------------------------------------------------------------------

Kết quả:

Value: Who

Value: is

Value: Kitty

Value: Mun

Value: Mun

Value: Kitty

Value: is

Value: Who

Value: Chung

Value: toi

Value:la

Value: nhung

Value: nguoi

Value: lap

Value: trinh

Value: may

Value: tinh

Value: Chung

Value: la

Value: lap

Value: may

Value: nguoi

Value: nhung

Value: tinh

Value: toi

Value: trinh

-----------------------------------------------------------------------------

Ví dụ bắt đầu bằng việc tạo mảng myArray, mảng các chuỗi với các từ sau:

“Who”, “is”, “Kitty”, ”Mun”

mảng này được in ra, sau đó được truyền vào cho hàm Array.Reverse(), kết quả chúng ta thấy là kết quả của chuỗi như sau:

Value: Mun

Value: Kitty

Value: is

Value: Who

Tương tự như vậy, ví dụ cũng tạo ra mảng thứ hai, myOtherArray, chứa những từ sau:

“Chung”, “toi”, “la”, “nhung”,”nguoi”,”lap”,”trinh”, “máy”, “tính”

Sau khi gọi phương thức Array.Sort() thì các thành phần của mảng được sắp xếp lại theo thứ tự alphabe:

Value: Chung

Value: la

Value: lap

Value: may

Value: nguoi

Value: nhung

Value: tinh

Value: toi

Value: trinh