Chương 2. Các kiểu dữ liệu đơn giản chuẩn
9.3. Dữ liệu kiểu bản ghi (Record)
Kiểu dữ liệu mảng nh− đã xét chỉ mô tả đ−ợc một nhóm các phần tử có cùng một kiểu giá trị. Bản ghi cho phép xử lý các đối t−ợng bao gồm nhiều kiểu dữ liệu khác nhau. Khái niệm bản ghi (Record) của Turbo Pascal là một công cụ mạnh để mô tả và xử lý các cấu trúc dữ
liệu phức tạp th−ờng gặp trong các bài toán quản lý.
9.3.1. Định nghĩa vμ khai báo một bản ghi
Để khai báo bản ghi có hai cách:
a. Khai báo thông qua định nghĩa kiểu
Kiểu bản ghi đ−ợc định nghĩa sau từ khóa Type theo mẫu sau:
Type
Tên_kiểu_bản_ghi = record tên_tr−ờng_1: kiểu;
tên_tr−ờng_2: kiểu;
...
Ch−ơng 9: Kiểu dữ liệu có cấu trúc 91
tên_tr−ờng_n: kiểu;
end;
Var
Tên_biến_bản_ghi: Tên_kiểu_bản_ghi;
Ví dụ: Đoạn ch−ơng trình:
Type
Ngay = Record Ngay: 1..31;
Thang: String[10];
Nam: Integer;
end;
Mô tả kiểu bản ghi ngay gồm 3 tr−ờng:
- Trường "ngay": thu nhận các giá trị nguyên từ 1 đến 31
- Trường "thang" có kiểu chuỗi ký tự có độ dài tối đa là 10 ký tự - Tr−ờng "nam" có kiểu là kiểu số nguyên Integer.
Cả ba trường nói trên đều là các trường cơ bản, có độ dài của chúng lần l−ợt là 1, 11 và 2. Độ dài của kiểu bản ghi ngay là:
1 + 11 + 2 = 14.
b. Khai báo trực tiếp var
tên_biến_bản_ghi: record tên_tr−ờng_1: kiểu;
tên_tr−ờng_2: kiểu;
...
tên_tr−ờng_n: kiểu;
end;
Một kiểu bản ghi đã định nghĩa có thể dùng để khai báo các trường của một bản ghi khác. Khi đó ta có các bản ghi lồng nhau.
Có thể sử dụng các bản ghi đã thiết kế trong mục Type để khai báo các bản ghi trong phần khai báo biến Var, coi các bản ghi là kiểu dữ liệu mới đã đ−ợc định nghĩa.
Ví dụ: Đoạn ch−ơng trình sau:
Type
Nhan_Su = record Ho_Ten: String[30];
Ngay_Sinh: Ngay Gioi_Tinh: Boolean;
Luong: Real;
end;
Var
Nguoi1, Nguoi2, CN: Nhan_Su;
Cho phép khai báo Nguoi1, Nguoi2, CN là các biến ghi tên công nhân với Ngày_Sinh của công nhân đó là một bản ghi kiểu Ngay đã
đ−ợc định nghĩa ở trên.
Ta có thể dùng hàm SizEOF để xác định độ dài của một kiểu dữ
liệu hoạt động độ dài của một biến bản ghi.
9.3.2. Sử dụng Record
Truy nhập tới từng tr−ờng của Record
Để truy nhập tới từng tr−ờng của Record, ta cần phải dùng tên biến kiểu Record, sau đó là dấu chấm (.) và tên trường của Record.
Cách viết nh− sau:
tên_bản_ghi.tên_tr−ờng;
Ví dụ: Để nhập dữ liệu cho tr−ờng Ho_Ten của bản ghi có tên là CN đã khai báo, ta sử dụng lệnh sau: Readln(CN.Ho_Ten);
Ch−ơng 9: Kiểu dữ liệu có cấu trúc 93
Các phép toán xử lý với toμn Record
Dòng lệnh Ng−ơi2:= Ng−ơi1 cho phép ta copy hai biến với nhau.
Thực chất của 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 chỉ là thâm nhập vào một trường riêng lẻ nào đó của biến kiểu bản ghi.
Ta có thể dùng phép so sánh:
IF Ng−ơi2 = Ng−ơi1 THEN Writeln('Cùng một ng−ời');
Hoặc
IF Ng−ơi2.Ho_Ten = Ng−ơi1.Ho_Ten THEN Writeln('Hai ng−ời trùng tên 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(Ng−ơi1) hoặc Writeln(Ng−ơi1);
+ So sánh các Record bằng các phép toán quan hệ: <, >, <=, >=.
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− mảng để 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[1..100] of Nhan_Su;
Trong đó Nhan_su là kiểu dữ liệu Record đ−ợc khai báo ở trên.
Như vậy để nhập dữ liệu họ tên và ngày sinh của người có số thứ tự là 50, ta có thể viết:
Canbo[50].Ho_Ten:='NguyÔn V¨n A';
Canbo[50].NgaySinh.Ngay:= 31;
9.3.3. Câu lệnh with trong xử lý Record
Việc truy nhập vào các tr−ờng của một biến kiểu Record nh− trên là tương đối phức tạp và dài dòng do phải dùng nhiều lần tên biến cùng với tên các tr−ờng.
Để đơn giản cách viết, Turbo Pascal đ−a ra lệnh with... do... cho phép ta rút ngắn liệt kê tên các bản ghi chứa thành phần mà ta muốn truy nhËp tíi.
Câu lệnh with dạng:
with tên_bản_ghi do begin
...
{Các câu lệnh xử lý chỉ cần ghi tên tr−ờng}
....
end;
Ví dụ: Để nhập họ tên và ngày sinh vào Canbo[50], thay vì phải viết:
Canbo[50].Ho_Ten:='NguyÔn V¨n A';
Canbo[50].NgaySinh.Ngay:= 31;
Ta cã thÓ viÕt nh− sau:
with Canbo[50] do Begin
Ho_Ten:='NguyÔn V¨n A';
NgaySinh.Ngay:= 31;
End;
9.3.4. Các ví dụ đối với kiểu dữ liệu Record
Ví dụ 1: Viết chương trình nhập hồ sơ cán bộ của một đơn vị. Mỗi hồ sơ có hai thành phần là: họ tên, ngày sinh (ngày, tháng, năm); sắp xếp theo tuổi giảm dần và in danh sách đó ra màn hình.
Ch−ơng 9: Kiểu dữ liệu có cấu trúc 95
Program sapxeptuoi;
Type
Ngay_sinh = Record Ngay, Thang, nam: Integer;
End;
DonVi= Record Hoten: String[24];
Ngaysinh: Ngay_sinh;
End;
Var
i, j, n: Integer;
Tam: Donvi;
Nv: array[1..100] of Don vi;
Begin
Write('Nhap so can bo='); Readln(n);
for i:=1 to N Do With Nv[i] Do Begin
Write(' Ho ten nhan vien thu:',i,'la:'); Readln(Hoten);
Writeln(' Nhap ngay, thang, nam sinh');
With Ngaysinh Do Begin
Write('Ngay:'); Readln(ngay);
Write('Thang:'); Readln(Thang);
Write('Nam:'); Readln(Nam);
End;
End;
For i:= 1 to N-1 Do For j:= i+1 to N Do
If (Nv[i].Ngaysinh.Nam>Nv[j].Ngaysinh.Nam)
OR ((Nv[i].Ngaysinh.Nam=Nv[j].Ngaysinh.Nam) AND (Nv[i].Ngaysinh.Thang>Nv[j].Ngaysinh.Thang)) OR
((Nv[i].Ngaysinh.Nam=Nv[j].Ngaysinh.Nam) AND (Nv[i].Ngaysinh.thang>Nv[j].Ngaysinh.Thang) AND (Nv[i].Ngaysinh.Ngay>Nv[j].Ngaysinh.Ngay)) Then Begin
tam:= Nv[i];
nv[i]:= Nv[i+1];
Nv[j+1]:= Tam;
End;
For i:= 1 to N do With Nv[i] Do
Write{'-', Hoten:24, ',sinh ngay:',Ngaysinh.ngay,'/',Ngaysinh.thang, '/ ',Ngaysinh.Nam);
Readln;
End.
Ví dụ 2: Lập ch−ơng trình nhập từ bàn phím một danh sách sinh viên gồm Họ và tên, năm sinh. Đ−a ra màn hình họ và tên các sinh viên lớn tuổi nhất.
Program Sviennhieutuoi;
uses crt;
type ho_so = record ho_ten:string;
nam_sinh: integer;
end;
var
sv: array[1..100] of ho_so;
i,n,min,dem: integer;
Begin clrscr;
write('Cho so luong sinh vien:'); readln(n) for i:= 1 to n do with sv[i] do
With Sv[i] Do
Ch−ơng 9: Kiểu dữ liệu có cấu trúc 97
Begin
Write(' Ho ten nhan vien thu:',i,'la:'); Readln(Ho_ten);
Write(' Nam sinh cua sinh vien thu:',i,'la:'); Readln(nam_sinh);
end;
i:=1; min:=sv[i].nam_sinh;
for i:=2 to n do
if sv[i].nam_sinh <min then min:=sv[i].nam_sinh;
writeln(' Cac sinh vien nhieu tuoi nhat la:');
dem:=0;
for i:=2 to n do
if sv[i].nam_sinh = min then begin
dem:=dem+1;
writeln(dem:10, sv[i].ho_ten:40);
end;
writeln;
readln;
End.