1. KHÁI NIỆM VÀ ĐỊNH NGHĨA
Chúng ta đã học về các kiểu cấu trúc dữ liệu như mảng (Array), kiểu tập hợp (SET). Các kiểu cấu trúc dữ liệu này đều được tạo ra bằng một tập hợp các phần tử có cùng (mô tả), kiểu. Ví dụ: các phần tử của một Array [1..100] of Integer là các số nguyên (Integer)...
Để tạo ra một kiểu cấu trúc dữ liệu mới với các phần tử dữ liệu có kiểu khác nhau nhưng có liên kết với nhau, người ta định nghĩa ra bản ghi hay còn gọi là Thẻ ghi, Phiếu ghi (tiếng Anh là Record). Nói một cách khác, để mô tả các kiểu khác nhau, chúng ta phải dùng cấu trúc kiểu Record. Như vậy Record là một phương tiện linh hoạt nhất để xây dựng các kiểu dữ liệu mới.
Cấu trúc dữ liệu Record được gắn liền với cấu trúc dữ liệu kiểu Tệp (File) (sẽ được trình bày ở chương sau) để lưu trữ dữ liệu. Không giống một số ngôn ngữ bậc cao khác nhứ FORTRAN, ngôn ngữ Pascal còn cho phép Record có thể được mô tả và sử dụng một cách độc lập với File.
2. MÔ TẢ RECORD
Mô tả Record được viết bằng chữ Record, theo sau là danh sách mô tả các phần tử dữ liệu của Record mà ta gọi là các trường. Mỗi một trường có một tên trường và được dùng để chọn các phần tử dữ liệu của Record, tiếp theo là mô tả kiểu trường. Mô tả Record bao giờ cũng được kết thúc bằng chữ END (có dấu chấm phẩy để kết thúc).
Để mô tả một kiểu T có cấu trúc Record với danh sách các trường có tên là s1, s2, ..., sn và có các mô tả kiểu tương ứng là T1, T2, ..., Tn, ta có thể viết tổng quát như sau:
■ Ví dụ 1:
Một địa chỉ bao gồm các dữ liệu như số nhà, tên phố, thành phố.
Ta mô tả RECORD Dia_chi như sau:
TYPE
Đia_chi = Record
So_nha: integer;
Pho: String[20];
Thanh_pho: String[15J;
End;
Như vậy chúng ta có 3 trường là So_nha, Pho và Thanh_pho với kiểu khác nhau (integer, string[20], string[15]) và chúng được liên kết lại với nhau để mô tả địa chỉ.
■ Ví dụ 2:
Để mô tả thời gian Date, ta có 3 trường: Ngày, Tháng và Năm.
TYPE
Date = RECORD
Ngay: 1..31;
Thang: 1..12;
Nam: integer;
END;
Hoặc theo kiểu tiếng Anh, người ta hay dùng tháng với tên gọi tháng:
TYPE
Date = RECORD
Day: 1..31;
Month: (Jan, Fer, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec);
Year: integer;
END;
■ Ví dụ 3:
Để mô tả nhân sự hay phiếu cán bộ của phòng tổ chức, ta phải dùng các trường: Họ tên, Ngày sinh, Chỗ ở, Lương... Ở đây ta ví dụ với 5 trường. Giả sử ta đã có mô tả kiểu Date và Dia_chi như ở trên.
TYPE
Nhan_su = RECORD
Ho_ten: String[30];
Ngay_sinh: Date;
Gioi_tinh: (Nam, Nu);
O_tai: Dia_chi;
Luong: Reals;
END;
Thí dụ 3 cho ta thấy điểm đặc biệt là việc mồ tả lồng nhau của cấu trúc dữ liệu. Trong mô tả RECORD của nhân sự, ta có thể mô tả các phần tử (các trường) của RECORD là một kiểu RECORD khác như các trường Ngày sinh và Chỗ ở. Mức lương được mô tả là Real (số thực) vì có thể đếm hàng xu, hàng hào.
Ta cũng có thể viết trực tiếp mô tả trường Ngay_sinh nếu như có mô tả kiểu Date:
TYPE
Nhan_su = RECORD
Ho_ten: String[30];
Ngay_sinh: Record
Ngay: 1..31;
Thang: 1..12;
Nam: integer;
end;
Gioi_tinh: (Nam, Nu);
O_tai: Diạ_chi;
Luong: Reals;
END.
3. SỬ DỤNG RECORDS
Để thâm nhập vào môi trường của RECORD, ta cần phải dùng tên biến kiểu Record, sau đó dấu chấm (.) và tên trường của Record.
■ Ví dụ 6
Với mô tả kiểu được nêu ở trên, ta tiếp tục khai báo biến và thực hiện một đoạn chương trình để đọc dữ liệu vào các biến như sau: VAR
Nguoi_l, Nguoi_2, Nhan_su;
Ta thấy muốn thâm nhập vào trường Ho_ten của biến Nguoi_l, ta phải viết Nguoi_l. Ho_ten. Ở đây, Nguoi_l là tên biến kiểu nhân sự và Ho_ten là tên thường. Nguoi_l. Ho_ten là một biến kiểu String[30]. Còn Nguoi_l. O_tai. Pho cho ta thâm nhập vào trường Phố của trường O_tai của biến Nguoi_l. Trong đó trường O_tai có mô tả kiểu Dia_chi.
• Dòng lệnh Nguoi_2 := Nguoi_l cho phép ta copy 2 biến với nhau. Thực chất dòng lệnh này là việc thâm nhập vào cả một biến kiểu Record chứ không phải là việc thâm nhập vào môi trường riêng lẻ nào đó của biến Record đó (là Nguoi_l và Nguoi_2 ở đây).
Ta có thể dùng phép so sánh:
If Nguoi_l = Nguoi_2 then Writeln ('Cung mot nguoi !);
hoặc:
If Nguoi_2. Ho_ten = Nguoi_l. Ho_ten then
Writeln (hai nguoi trung ten nhau !)
• Tuy nhiên cần lưu ý là không thể dùng các thao tác sau:
- Viết ra màn hình hoặc đọc từ bàn phím cả một biến kiểu Record như:
Readln (Nguoi_1) or Writeln (Nguoi_1);
- So sánh các Record bằng các phép toán quan hệ như sau: <, >, <=, >=.
Riêng các phép so sánh <> (khác nhau) và = (bằng nhau) thì có thề được dùng với hai biến có cùng một kiểu Record.
- Tất cả các phép toán số học và logic.
Chúng ta cũng có thể kết hợp kiểu Record với các kiểu dữ liệu khác như lập một mảng các Record. Để mô tả một đội ngũ cán bộ của một cơ quan nào đó có số người nhiều nhất là 100 chẳng hạn, ta có thể viết:
VAR
Canbo: Array [l..100] of Nhan_su;
TG: Nhan_su; {ô nhớ trung gian}
i, j: integer;
BEGIN
For i:= 1 to 99 do
For j := i + 1 to 100 do
If Canbo[i]. Ho_ten > Canbo[j]. Ho_ten then
Begin
TG:= Canbo[i];
Canbo[i] = Canbo[j];
Canbo[j]:= TG;
End;
4. CÂU LỆNH WITH
Qua ví dụ trước ta thấy việc thâm nhập vào các trường của một biến kiểu Record là tương đối phức tạp và có phần tẻ nhạt vì phải dùng nhiều lần tên biến (Nguoi_1 trong ví dụ này) cùng với tên các trường. Để đơn giản cách viết, Pascal đưa ra lệnh WITH... DO... xét cùng với thí dụ 5 trên.
■ Ví dụ:
WITH Nguoi_1 Do
Begin
Write ('Ho va ten nguoi_l');
Readln (Ho_ten);
With Ngay_sinh Do
Begin
Write ('Ngay sinh:’);
Readln (Ngay);
Write ('Thang sinh');
Readln (Thang);
Write ('Nam sinh:');
Readln (Nam);
End;
End;
Như vậy chúng ta còn có lồng các chỉ thị WITH... DO... vào với nhau để thâm nhập vào các trường ở sâu trong Record phức tạp như biến Nguoi_1. Nó có dạng viết:
WITH A DO
WITH B DO
…
Với A, B đều được mô tả là Record, song B là một trường của A (ở thí dụ trên B là Ngay_sinh, A là Nguoi_1)
Ta có thể ghi gọn lại:
WITH A DO
WITH A, B DO
WITH B DO
Begin
Begin...
…
End;
End;
Với thí dụ 3, ta có thể thâm nhập vào các trường của trường Ngay_sinh trực tiếp như sau:
WITH Nguoi_1, Ngay_sinh DO
Begin
Ngay := 12;
Thang := 5;
Nam := 1960;
End;
Hoặc với mảng Canbo[50], ta có thể viết:
WITH CanBo[50] DO
Begin
Ho_ten:= 'Le Thi Tam';
End;