Bản ghi có cấu trúc thay đổ

Một phần của tài liệu TIN HỌC ĐẠI CƯƠNG (TẬP 2) (Trang 44 - 50)

IV. KIỂU BẢN GHI (RECORD) 1 Ðịnh nghĩa và khai báo

5. Bản ghi có cấu trúc thay đổ

Cấu trúc của bản ghi là các trường với tên, kiểu dữ liệu và độ rộng. Các kiểu record nêu ở trên là kiểu bản ghi cố định, không thay đổi. Trong thực tế, ta thường gặp một số bản ghi có đến hàng chục trường, mà trong đó chỉ có một số trường là mọi đối tượng đều có (phần cố định), còn lại một số trường khác thì mỗi đối tượng lại có phần khác nhau (phần thay đổi). Việc tổ chức một bản ghi cố định theo cách đã học ở trên sẽ gây lãng phí bộ nhớ. Ngôn ngữ Pascal cho phép thành lập các bản ghi có một phần cấu trúc thay đổi được hay còn gọi là record thay đổi.

Chẳng hạn, để ghi kết quả môn thi của sinh viên, trong đó 3 ngành: - Nông nghiệp: Trồng trọt, Chăn nuôi, Thủy sản, Chế biến, Anh văn, Tin học - Sư phạm: Toán học, Vật lý, Hoá học, Sinh học, Anh văn, Tin học

- Công nghệ: Xây dựng, Cơ khí, Thủy lợi, Môi trường, Anh văn, Tin học

Như vậy, trong 3 ngành trên đều có chung môn Anh văn và Tin học (phần cố định), còn lại là mỗi ngành lại có môn học phân biệt khác nhau (phần thay đổi). Thay vì khai báo 18 môn học cho 3 ngành khác nhau, ta có thể tổ chức cách khác bằng cách tạo ra một cấu trúc record thay đổi. Trước hết, ta xét các định nghĩa trong một bản ghi có cấu trúc thay đổi:

· Phần cố định (các trường cố định) là phần giống nhau trong mọi trường hợp của tất cả mọi đối tượng. Trong record có cấu trúc thay đổi, phần này có thể có hoặc không, nếu có thì phần cố định sẽ được khai báo trước. Phần cố định được viết bình thường như đã trình bày ở phần trên.

· Trong các trường cố định, ta chọn một trường làm chỉ tiêu để phân loại cho các trường hợp mà mỗi trường hợp có một số trường khác nhau (trường thay đổi) tương ứng với từng giá trị mà trường làm chỉ tiêu phân loại nhận. Trường làm chỉ tiêu phân loại này được gọi là trường phân loại, như vậy trường phân loại này cũng chính là trường cố định. Trường phân loại này luôn được đặt sau cùng trong các trường cố định.

· Phần thay đổi (các trường thay đổi ) luôn được đặt sau trường phân loại. Trường phân loại này được đặt trong từ khóa CASE .. OF. Tùy theo trường phân loại này nhận giá trị nào thì sẽ có các trường thay đổi tương ứng.

Dạng tổng quát của record thay đổi sau: TYPE

<tên kiểu> = <kiểu trường> ; ...

<tên kiểu record> = RECORD

<Tên trường 1a>[,<Tên trường1b>,...] : <Tên kiểu> ; <Tên trường 2a>[,<Tên trường2b>,...] : <Tên kiểu> ;

... {các trường cố định}... ; CASE <tên trường phân loại> : <tên kiểu> OF

<giá trị 1> : (<danh sách các trường thay đổi 1>:< Tên kiểu >); <giá trị 2> : (<danh sách các trường thay đổi 2>:< Tên kiểu >); ...{Các trường thay đổi}... ; END;

Ghi chú: Danh sách của trường thay đổi tùy thuộc vào từng giá trị cụ thể của trường phân loại, dấu ngoặc đơn ( ... ) bao danh sách của trường thay đổi là bắt buộc phải có kể cả khi nó rỗng.

Với ví dụ trên ta thấy thay vì ghi một bản ghi 18 môn học, ta chỉ cần dùng record biến đổi có số lượng môn học là 6 theo thực tế của mỗi sinh viên.

Ví dụ 8.43: Trong ví dụ trên, bài toán lập trình có thể viết như sau: TYPE

Diemthi= REAL; NGANH = (NN, SP, CN) ;

DSMONHOC = RECORD

AVan, TINHOC: Diemthi; CASE MONHOC : NGANH OF

NN : (TTrot, CNuoi, TSan, CBien: Diemthi) ; SP : (toan, ly, hoa, sinh: Diemthi) ;

cn : (Xdung, ckhi, tloi, mtruong: Diemthi) ; end ;

Ở bản ghi DSMONHOC, ta có 2 trường cố định là AVAN và TINHOC, một trường phân loại là MONHOC, và 4 trường thay đổi tương ứng tùy theo trường phân loại MONHOC nhận gía trị là NN, SP, hay CN.

Ví dụ 8.44: Xét một lớp các loại hình phẳng là gồm các cá thể : tam giác, chữ nhật, và hình tròn. Mỗi loại hình đều có :

* Các chỉ tiêu chung là: Tên hình, diện tích, chu vi. * Các chỉ tiêu riêng là:

- Chiều dài, chiều rộng đối với hình chữ nhật. - Bán kính đối với hình tròn.

Ta dùng kiểu bản ghi có cấu trúc thay đổi, để viết chương trình tính tính diện tích và chu vi cho từng loại hình như sau:

PROGRAM BAN_GHI_THAY_DOI; USES CRT;

TYPE Cathe = RECORD Dt,cv:real; Case kieu:(TG,CN,HT) of TG: (c1,c2,c3:real); CN: (cr,cd:real); HT: (bk:real); End; VAR Doituong: Cathe; Tenhinh:string[2]; i:byte;ds:boolean; BEGIN Clrscr; Repeat

Write('Nhập loại hình "TG/CN/HT" vào: ');readln(tenhinh); For i:=1 to length(tenhinh) do tenhinh[i]:=upcase(tenhinh[i]); Until (tenhinh='TG') OR (tenhinh='CN') OR (tenhinh='HT'); If tenhinh='TG' then doituong.kieu:=TG;

If tenhinh='CN' then doituong.kieu:=CN; If tenhinh='HT' then doituong.kieu:=HT; With doituong do

Case kieu of TG: begin

Writeln('ÐỐI TƯỢNG LÀ HÌNH TAM GIÁC'); Write(' Nhập cạnh thứ nhất = ');readln(c1); Write(' Nhập cạnh thứ hai = ');readln(c2); Write(' Nhập cạnh thứ ba = ');readln(c3);

If (c1+c2>c3) AND (c1+c3>c2) and (c2+c3>c1) then Begin

Cv:=(c1+c2+c3)/2; {nửa chu vi}

Dt:=SQRT(cv*(cv-c1)*(cv-c2)*(cv-c3)); Cv:=cv*2; {chu vi};

Writeln(' Chu vi = ',cv:6:2); Writeln(' Diện tích = ',dt:6:2);

End

Else writeln(' Không thỏa tính chất tam giác'); End;

CN: begin

Writeln('ÐỐI TƯỢNG LÀ HÌNH CHỮ NHẬT'); Write('Nhập chiều rộng = ');readln(cr);

Write('Nhập chiều dài = ');readln(cd); Dt:=cr*cd; Cv:=(cd+cr)*2; Writeln(' Chu vi = ',cv:6:2); Writeln(' Diện tích = ',dt:6:2); End; HT: begin

Writeln(' ÐỐI TƯỢNG LÀ HÌNH TRÒN'); Write('Nhập bán kính = ');readln(bk); Cv:=2*Pi*bk; dt:=pi*SQR(bk);

Writeln(' Chu vi = ',cv:6:2); Writeln(' Diện tích = ',dt:6:2); End; End; Readln; END.

Ví dụ 8.45: (Xem xét kỹ hơn ở trường hợp ví dụ 8.37)

Một Công ty bán hàng trả góp cần lập trình một Hệ thống Hóa đơn Khách hàng (Customer Billing System). Chương trình này đòi hỏi tạo một record về khách hàng vào máy tính. Mỗi khách hàng sẽ được cân đối số tiền nợ tồn hàng ngày dựa vào các số tiền chi trả trước và mức phải chi trả hiện hành. Mỗi tài khoản sẽ được xem xét là đúng kỳ hạn, trừ khi :

- Mức chi trả hiện hành là lớn hơn 0 nhưng nhỏ hơn 10% của cân đối nợ tồn lần trước. Trong trường hợp này, tài khoản sẽ được xem như quá hạn (overdue).

- Nếu cân đối tồn nợ vẫn còn và giá trị chi trả hiện hành là 0, trong trường hợp này tài khoản sẽ được xem xét như phạm lỗi chểnh mảng, dây dưa" việc trả nợ (delinquent).

Ðể dễ dàng thao dõi, tất cả các bản ghi (record) sẽ được trữ như các phần tử của một mảng một chiều. Do vậy, chiến lược lập trình tổng thể sẽ như sau:

(1). Khai báo số lượng tài khoản (chính là số record) phải xử lý. (2). Trong mỗi bản ghi, đọc các hạng mục sau:

a. Tên khách hàng (name) b. Số nhà và tên đường (street) c. Tên thành phố (city)

d. Số tài khoản (account number) e. Nợ trước (previous balance)

f. Chi trả hiện hành (current payment) g. Ngày chi trả (payment date)

(3). Sau khi tất cả các bản ghi được nhập vào máy tính, xử lý mỗi bản ghi theo cách sau: a. So sánh chi trả hiện hành với số nợ tồn và định tình trạng nợ phù hợp.

b. Tính toán cân đối tài khoản mới bằng cách lấy nợ trước trừ đi số chi trả hiện hành (nếu ra số âm thì xem đó là một tín dụng - credit).

(4). Sau khi mỗi bản ghi đã được xử lý, hiện hình các thông tin sau cho mỗi bản: a. Tên khách hàng (name)

b. Số tài khoản (account number) c. Tên số nhà và tên đường (street) d. Tên thành phố (city)

e. Cân nợ cũ (old balance)

f. Chi trả hiện hành (current payment) g. Cân nợ mới (new balance)

h. Tình trạng tài khoản (account status)

Chúng ta sẽ lập trình theo cách thức module, với một thủ tục (procedure) riêng biệt để nhập dữ liệu, thủ tục xử lý dữ liệu và thủ tục in ra màn hình kết quả. Mỗi thủ tục sẽ viết theo lối thẳng tiến và không cần phải mô tả tỉ mỉ. Thân chương trình chính sẽ làm đơn giản nhập các dữ liệu record và sau đó truy xuất các thủ tục thích hợp. Các chữ viết tắt theo giải thích ở ví dụ 8.37. Sau đây là một trình Pascal về bài toán trên (viết theo Byron S. Gottried, xem sách tham khảo):

PROGRAM customers ; {Chương trình HỆ THỐNG HÓA ÐƠN KHÁCH HÀNG } {dùng minh họa cách sử dụng Record}

TYPE status = (current, overdue, delinquent) ; Date = RECORD day : 1 .. 31; month : 1 .. 12; year : 1900 .. 2100; END; Account = RECORD name : string ; street : string ;

city : string ; custno : 1 .. 9999 ; custtype : status ; oldbalance : real ; newbalance : real ; payment : real ; paydate : date ; END ;

VAR Customer : ARRAY [1 .. 10] OF account ; i, n : 1 .. 10 ;

PROCEDURE Readinput ; {Ðọc số liệu nhập cho mỗi bản ghi} VAR space : char ;

BEGIN

FOR i := 1 TO n DO

WITH customer[i] DO BEGIN

Writeln ('Khách hàng số :' , i:3) ;

Write(' Tên khách hàng : ');Readln(name) ; Write (' Số nhà và tên đường : ') ;Readln (street) ; Write ( 'Tên thành phố :' ) ;Readln (city) ;

Write (' Số tài khoản : ') ;Readln (custno) ; Write ( 'Cân nợ trước : ') ;Readln (oldbalance) ; Write ( 'Chi trả hiện hành : ') ;Readln (payment) ; Write ( 'Ngày trả (dd mm yyyy) : ') ;

WITH paydate DO

Readln(day,month, year) ;

END; {readinput}

PROCEDURE Processdata ; {Xác định tình trạng trả nợ và tính cân nợ mới cho mỗi bản ghi} BEGIN

FOR i := 1 TO n DO

WITH customer[i] DO BEGIN custtype := current ;

IF (payment > 0) AND (payment < 0.1* oldbalance) THEN custtype := overdue ;

IF (oldbalance > 0) AND (payment = 0) THEN custtype := delinquent ; newbalance := oldbalance - payment END ;

END ; {processdata}

PROCEDURE Writeoutput; In ra các thông tin hiện hành cho mỗi bản ghi } BEGIN

FOR i := 1 TO n DO

WITH customer[i] DO BEGIN

Writeln ;

Write(' Tên khách hàng :' , name) ; Writeln(' Số tài khoản : ' , custno) ; Writeln( 'Số nhà và tên đường :' , street) ; Writeln(' Tên thành phố :' , city) ;

Writeln ;

Write(' Tồn nợ cũ :' , oldbalance :7:2) ; Write(' Chi trả hiện hành :' , payment :7:2) ; Writeln(' Cân đối mới :' , newbalance :7:2) ; Writeln ;

Write(' Tình trạng tài khoản : ' ) ; CASE custtype OF

current : writeln(‘ CURRENT ’) ; overdue : writeln(‘ OVERDUE ‘) ; delinquent : writeln(‘ DELINQUENT ‘) ; END ; Writeln;

END ;

END ; {Writeoutput}

BEGIN {Thân chương trình chính}

Writeln(' HỆ THỐNG HÓA ÐƠN KHÁCH HÀNG ') ; Writeln ;

Writeln(' Có bao nhiêu khách hàng ? ') ; Readln (n) ;

Readinput ; Processdata ; Writeoutput ; END.

Giả sử chúng ta có số liệu 4 khách hàng nào đó. Nhập dữ liệu như bên dưới, lưu ý là các chữ số có gạch dưới là của người sử dụng nhập vào máy tính.

HỆ THỐNG HÓA ÐƠN KHÁCH HÀNG Có bao nhiêu khách hàng ? 4

Khách hàng số 1

Tên khách hàng : Ngô Hoàng Trọng Số nhà và tên đường : 123 Trần Hưng Ðạo Tên thành phố : Cần thơ Tài khoản số : 4208 Cân nợ trước : 247.88 Chi trả hiện hành : 25.00 Ngày trả (dd mm yyyy) : 14 6 1993 Khách hàng số 2

Tên khách hàng : Huỳnh Văn Tuấn Số nhà và tên đường : 151/53 Lộ Tầm vu Tên thành phố : Cần thơ Tài khoản số : 2219 Cân nợ trước : 135.00 Chi trả hiện hành : 135.00 Ngày trả (dd mm yyyy) : 10 8 1993 Khách hàng số 3 Tên khách hàng : Lê Tấn Sĩ

Số nhà và tên đường : 71 Phan Ðình Phùng Tên thành phố : Long xuyên

Tài khoản số : 8452 Cân nợ trước : 387.42 Chi trả hiện hành : 35.00

Ngày trả (dd mm yyyy) : 4 7 1993 Khách hàng số 4

Tên khách hàng : Tạ Quang Trinh Số nhà và tên đường : 82 Mậu thân Tên thành phố : Rạch giá

Tài khoản số : 711 Cân nợ trước : 260.00 Chi trả hiện hành : 0

Ngày trả (dd mm yyyy) : 27 11 1993

Chương trình khi chạy sẽ in ra kết quả tương ứng với số liệu nhập trên như sau: Tên khách hàng : Ngô Hoàng Trọng Số tài khoản : 4208

Số nhà và tên đường : 123 Trần Hưng Ðạo Tên thành phố : Cần thơ

Tồn nợ cũ : 247.88 Chi trả hiện hành : 25.00 Cân đối mới : 222.88 Tình trạng tài khoản : CURRENT

Tên khách hàng : Huỳnh Văn Tuấn Số tài khoản : 2219 Số nhà và tên đường : 151/53 Lộ Tầm vu

Tên thành phố : Cần thơ

Tồn nợ cũ : 135.00 Chi trả hiện hành : 135.00 Cân đối mới : 0.00 Tình trạng tài khoản : CURRENT

Tên khách hàng : Lê Tấn Sĩ Số tài khoản : 8452 Số nhà và tên đường : 71 Phan Ðình Phùng

Tên thành phố : Long xuyên

Tồn nợ cũ : 387.42 Chi trả hiện hành : 35.00 Cân đối mới : 352.42 Tình trạng tài khoản : OVERDUE

Tên khách hàng : Tạ Quang Trinh Số tài khoản : 711 Số nhà và tên đường : 82 Mậu thân

Tên thành phố :Rạch giá

Tồn nợ cũ : 260.00 Chi trả hiện hành : 0.00 Cân đối mới : 260.00 Tình trạng tài khoản : DELINQUENT

Sinh viên có thể thử lại và tự cải tiến chương trình này như một bài tập.

Một phần của tài liệu TIN HỌC ĐẠI CƯƠNG (TẬP 2) (Trang 44 - 50)

Tải bản đầy đủ (DOC)

(74 trang)
w