Khái niệm
Các phần trình bày trước cho thấy ngôn ngữ Pascal rất mạnh trong việc giải quyết các bài toán thiên về tính toán. Trong phần này chúng ta sẽ thấy thêm một khả năng mạnh mẽ nữa của ngôn ngữ Pascal trong lĩnh vực quản lý: quản lý nhân sự, quản lý vật tư, quản lý tài chánh,.v.v.
Hàng ngày chúng ta rất quen thuộc với một danh sách sinh viên như dưới đây:
Mỗi dòng liệt kê các dữ liệu về một người, mỗi cột là một dữ liệu thành phần cung cấp thông tin về một thuộc tính cụ thể của những người đó.
Trong ngôn ngữ Pascal, mỗi dòng được gọi là một RECORD (dịch là bản ghi hay thẻ ghi), mỗi cột là một FIELD (dịch là trường hay thành phần, hay thuộc tính cho sát với thực tế).
Nói tổng quát, mỗi bản ghi là một tập gồm nhiều trường (field), các trường có thể có kiểu dữ liệu khác nhau.
14.1.2. Mô tả bản ghi :
Kiểu bản ghi được mô tả bằng cách dùng từ khóa RECORD kèm theo một danh sách khai báo các tên trường và kiểu dữ liệu tương ứng, kết thúc bằng từ khóa END; , tức là:
TYPE
Tênkiểu = RECORD
Têntrường1 : Kiểudliệu1;
Têntrường2 : Kiểudliệu2;
...
Têntrườngk : Kiểudliệuk;
End;
Ví dụ 1: Ta định nghĩa một kiểu KSVIEN như sau:
TYPE
KSVIEN = RECORD
Hoten:String[20];
Maso : String[8];
Toan, Ly, DTB: Real;
End;
Theo mô tả trên, ta có một kiểu dữ liệu mới đặt tên là KSVIEN có cấu trúc bản ghi gồm 5 trường (thuộc tính) là:
Ví dụ 2:
Ta mô tả thời gian là kiểu KDATE có ba trường ngày , tháng, năm như sau:
TYPE
KDATE = RECORD
Ngay : 1..31;
Thang : 1..12;
Nam : Integer;
End;
Ví dụ 3:
Ðể quản lý các sách trong một thư viện, ta xây dựng một kiểu bản ghi KSACH như sau:
TYPE
KSACH = RECORD
Ma_so_sach: String[6];
Ten_doc_gia: String[20];
Nam_xban :Integer;
Gia_tien: Real;
Ngay_muon : KDATE;
End;
Kiểu KSACH là một bản ghi có 5 trường mô tả 5 thuộc tính của sách là: mã số sách, tên độc giả, năm xuất bản, gía tiền và ngày mượn.
Ví dụ này cho thấy các bản ghi có thể được mô tả lồng nhau: kiểu dữ liệu của một trường của bản ghi này lại có thể là một kiểu bản ghi khác đã được định nghĩa trước đó. Trong bản ghi KSACH, Ngay_muon là một trường có kiểu dữ liệu là một bản ghi kiểu KDATE.
Mỗi đối tượng cần quản lý có thể có nhiều trường, song tùy yêu cầu quản lý mà ta chỉ lựa chọn và khai báo những trường thật sự cần thiết. Khai báo thừa thì hao phí bộ nhớ, nhưng nếu thiếu thì công tác quản lý sẽ khó khăn do thiếu thông tin. Vì vậy, nên khai báo các trường với số lượng ít nhất nhưng đủ dùng.
14.1.3. Sử dụng bản ghi :
Kiểu bản ghi sau khi đã được định nghĩa có thể dùng khai báo cho các biến. Ví dụ :
Var
X, Y, Z : KSVIEN;
Trong đó KSVIEN là bản ghi đã mô tả ở phần trên.
Theo khai báo này, X ,Y và Z là ba biến kiểu bản ghi KSVIEN, mỗi biến đều có 5 trường Hoten, Maso, Toan, Ly và DTB.
Ðể thâm nhập vào một trường của bản ghi ta viết tên biến kiểu bản ghi, sau đó là dấu chấm ‘.’ và tên trường, tức là :
Tênbiến .Têntrường
Các lệnh dưới đây gán gía trị cho từng trường của biến X :
X.Hoten :=‘Nguyen Van An’;
X.Maso :=‘1973208’;
X.Toan :=8.0;
X.Ly :=7.0;
X.DTB :=(X.Toan+X.Ly)/2;
Ðể nhập dữ liệu cho trường Hoten của biến Y, ta viết:
Write(‘Nhap ho ten sinh vien Y : ‘);
Readln(Y.Hoten);
Sở dĩ phải viết tên biến bản ghi ở trước tên trường là để xác định trường đó là của biến bản ghi nào. Mỗi biến X, Y, Z đều có trường Hoten, nên nếu chỉ viết Hoten thôi thì không biết đó là Hoten của ai: X, Y hay Z ?. Còn viết X.Hoten là chỉ rõ đây là Hoten của biến X.
Như vậy, mỗi trường của biến bản ghi có thể thâm nhập và sử dụng như một biến bình thường. X.Hoten là biến kiểu String[20], X.Maso là biến kiểu String[8], ..., X.DTB là biến kiểu Real.
Ðối với các bản ghi lồng nhau, cách truy xuất đến từng trường cũng tương tự.
Ví dụ: Cho khai báo biến S kiểu KSACH:
Var
S : KSACH ;
Ðể truy nhập đến các trường Ngay, Thang, Nam của Ngay_muon ta viết :
S.Ngay_muon.Têntrường
Chẳng hạn gán :
S.Ngay_muon.Ngay := 2;
S.Ngay_muon.Thang := 9;
S.Ngay_muon.Nam := 1999;
Hai biến bản ghi cùng kiểu có thể gán cho nhau. Lệnh :
Y:=X;
gán gía trị của từng trường của biến X cho trường tương ứng của biến Y. Vậy lệnh trên tương đương với khối 5 lệnh sau :
begin
Y.Hoten :=X.Hoten;
Y.Maso :=X.Maso;
Y.Toan :=X.Toan;
Y.Ly :=X.Ly;
Y.DTB :=X.DTB;
end;
Các bản ghi có thể so sánh bằng nhau hoặc khác nhau:
Ví dụ:
If X=Y then writeln(‘ X và Y là một người ‘);
If X<>Y then writeln(‘ X khác Y ‘);
Tuy nhiên không có phép so sánh <, <=, >, >= cho các bản ghi.
Hai bản ghi có thể hoán đổi gía trị cho nhau theo nghĩa hoán đổi từng cặp gía trị của các trường tương ứng.
Giống như các biến đơn giản, để hoán đổi hai bản ghi X và Y ta dùng ba lệnh:
Z:=X; X:=Y; Y:=Z;
trong đó Z là biến trung gian cùng kiểu bản ghi với X và Y.
Ví dụ: Nếu biến X và Y có các trường tương ứng là :
X.Hoten =‘Nguyen Van An’ X.Maso =‘1973208’ X.Toan =8.0 X.Ly =7.0 X.DTB =7.5 | Y.Hoten =‘Tran Thi Nga’ Y.Maso =‘1974564’ Y.Toan =5.0 Y.Ly =8.0 Y.DTB =6.5 |
thì sau khi hoán đổi, ta được :
X.Hoten =‘Tran Thi Nga’ X.Maso =‘1974564’ X.Toan =5.0 X.Ly =8.0 X.DTB =6.5 | Y.Hoten =‘Nguyen Van An’ Y.Maso =‘1973208’ Y.Toan =8.0 Y.Ly =7.0 Y.DTB =7.5 |
14.1.4. Câu lệnh WITH :
Khi làm việc với nhiều trường của một biến bản ghi thì cách thâm nhập ở trên tỏ ra rườm rà vì phải viết nhiều lần tên biến trước tên trường.
Ðể đơn giản cách viết, Pascal đưa ra câu lệnh :
WITH Tênbiến DO LệnhP;
Tên biến thuộc kiểu bản ghi.
Nếu LệnhP có truy xuất đến các trường của Tên biến thì không cần phải viết Tên biến và dấu chấm trước các tên trường.
Ví dụ, thay vì viết:
X.Hoten:= ‘Nguyen Van An’;
ta có thể viết :
WITH X DO Hoten:= ‘Nguyen Van An’;
Ðể in các trường của biến X lên màn hình, ta viết:
WITH X DO
Begin
Writeln(‘ Họ và tên :’ , Hoten);
Writeln(‘ Mã số sinh viên :’ , Maso);
Writeln(‘ Ðiểm Toán :’ , Toan: 4:1);
Writeln(‘ Ðiểm Lý :’ , Ly: 4:1);
Writeln(‘ Ðiểm trung bình : ‘ , DTB :4:1);
End;
Tất cả các tên trường nằm trong khối begin và end được hiểu là các trường của biến X (nếu không ghi rõ tên biến nào khác).
Các lệnh sau gán các gía trị cho các trường của biến S kiểu KSACH là một bản ghi lồng nhau:
WITH S DO
begin
Ma_so_sach:=‘TH-435’;
Ten_doc_gia:=‘Nguyen van Mai’;
Nam_xban :=1999;
Gia_tien:= 15000;
WITH Ngay_muon DO
begin
Ngay:=2;
Thang:=9;
Nam:=1999;
end;
end;
14.1.5. Mảng các bản ghi :
Trong thực tế, ta thường phải quản lý một danh sách sinh viên của một lớp, một danh sách các quyển sách trong thư viện. Ví thế mảng các bản ghi được dùng rất phổ biến.
Khi khai báo :
VAR
DS : Array[1..50] of KSVIEN;
hoặc :
TYPE
KMang = Array[1..50] of KSVIEN;
VAR
DS: KMang;
thì ta có một mảng DS gồm 50 phần tử DS[1],..., DS[50] cùng kiểu bản ghi KSVIEN. Mỗi DS[i], i=1,..., 50 là một bản ghi có 5 trường Hoten, Maso, Toan, Ly, DTB lưu trữ các thông tin về sinh viên thứ i trong danh sách.
Ðể nhập dữ liệu ( Hoten, Maso, Toan, Ly ) rồi tính Ðiểm trung bình cho 50 sinh viên này, ta dùng vòng lặp For phối hợp với câu lệnh WITH :
For i:=1 to 50 do
WITH DS[i] DO
begin
Write(‘Nhap ho ten sinh vien thu ‘,i,’ : ‘); Readln(Hoten);
Write(‘Nhap ma so sinh vien thu ‘,i,’ : ‘); Readln(Maso);
Write(‘Nhap điểm Toan, Ly sinh vien thu ‘,i,’ : ‘);
Readln(Toan, Ly);
DTB:=(Toan + Ly)/2;
end;
Ðể sắp xếp danh sách sinh viên theo trật tự giảm của DTB sao cho người có DTB cao thì đứng trước, người có DTB thấp thì đứng sau, ta có thể áp dụng phương pháp sắp xếp mảng, song chỉ lấy trường DTB làm tiêu chuẩn so sánh:
For i:=1 to 49 do
For j:=i+1 to 50 do
If DS[i].DTB < DS[j].DTB then
begin { Ðổi chỗ DS[i] và DS[j] }
Z:=DS[i];
DS[i]:=DS[j];
DS[j]:=Z;
end;
Ở đây Z là biến bản ghi cùng kiểu với các phần tử DS[i].
Khi sắp xếp theo DTB tăng hoặc giảm thì trường DTB được gọi là "khóa" ( key) sắp xếp.
Một cách tương tự, có thể sắp xếp danh sách sinh viên theo khóa là điểm Toan, hoặc điểm Ly, hoặc Maso, hoặc theo Hoten.
Ðể in danh sách đã sắp xếp lên màn hình, ta dùng lệnh :
For i:=1 to 50 do WITH DS[i] DO
Writeln( i:2, Hoten:25, Maso:9 , Toan:5:1, Ly:5:1, DTB:5:1);
(nguồn: http://www.uit.edu.vn/
)