Hướng dẫn biến toàn cục pascal

End ;

Procedure AB ;

Var M,N : Integer ;

Begin

...

End ;

Begin

End ; (* Procedure A *)

(* -------------------------------------------- *)

Procedure B ;

Var X,Z : Integer ;

Procedure BA ;

Begin

End ;

Begin

End ; (* Procedure B *)

(* --------------------------------------------- *)

BEGIN

END. (* Chương trình chính *)

Như ta đã biết, các biến được khai báo trong chương trình chính

được gọi là biến toàn cục. Các biến này có thể được dùng ở mọi nơi

trong chương trình. Các biến được khai báo trong một CTC được gọi

là các biến địa phương và nó chỉ có tác dụng trong phạm vi CTC đó

hay trong Bloc đó. Khi CTC kết thúc thì các biến này cũng mất tác

dụng theo. Để diễn tả tầm tác dụng của các biến, của các khai báo,

người ta đưa ra khái niệm mức : chương trình chính có mức 0, các

chương trình tiếp theo có mức là 1,2,… tùy theo vị trí khai báo. Trong

hình 2, chương trình con A và B có mức là 1, chương trình con AA,

AB, BA có mức là 2.

Sau đây là một số quy tắc sử dụng :

36

Võ Văn Dũng - Ngôn ngữ lập trình Pascal.

+ Tầm tác dụng của 1 tên (biến, hằng, kiểu…) được xác định bằng

mức Bloc trong đó tên được khai báo và bằng các mức Bloc khác có

mức cao hơn và nằm trong Bloc chứa khai báo.

Trong ví dụ vừa rồi, biến Y được khai báo trong CTC A (có mức là

1). Như vậy biến Y có thể được sử dụng ở trong CTC AA và AB (là 2

CTC có mức cao hơn và nằm trong CTC A). Ngoài ra Y không thể sử

dụng ở CTC B, BA, BB vì chúng không phải là CTC của A.

+ Tầm quan trọng của các biến khai báo ở mức 0 (chương trình

chính)là toàn bộ chương trình.

+ Ở các mức khác nhau của các CTC, ta có thể khai báo 1 biến có

cùng tên với biến ở mức khác. Tên biến này không phải là một biến

duy nhất mà là hai biến khác nhau với tầm quan trọng khác nhau. Ví

dụ trong hình 2, CTC B có biến địa phương X và trong chương trình

chính có biến toàn cụa cũng có là X. Khi đó trong CTc thì biến X địa

phương có tác dụng, còn khi CTC kết thúc thì biến toàn cục lại lấy lại

tác dụng của nó. Hãy xét ví dụ cụ thể như sau :

Program Tam_Tac_Dung) ;

Var I : Integer ; (* Biến I toàn cục *)

(* ------------------------------------------------- *)

Procedure Dia_Phuong ;

Var I : Integer ; (* Biến I địa phương *)

Begin

I := 7 ;

Writeln (I : 6) ;

End ;

(* ------------------------------------------------ *)

BEGIN

I :=5 ;

Writeln(I : 6) ;

Dia_Phuong ;

Writeln(I : 6) ;

END.

Kết quả cho ra :

5 (* giá trị của I toàn cục *)

7 (* giá trị của I địa phương *)

Võ Văn Dũng - Ngôn ngữ lập trình Pascal.

37

5 (* giá trị của I toàn cục *)

Tên biến I được dùng cho cả biến toàn cục và biến địa phương. Đầu

tiên biến I toàn cục nhận giá trị bằng 5. Sau đó thủ tục Dia_Phuong

được gọi, vì thủ tục này cũng có biến là I (biến địa phương) nên biến I

toàn cục được xem như tạm bị treo không dùng đến. Biến địa phương

lấy giá trị bằng 7. Sau khi kết thúc chương trình con, biến I địa phương

bị mất và biến I toàn cục lại được khôi phục lại tác dụng. Tất nhiên nó

vẫn giữ giá trị bằng 5 là giá trị có được trước khi gọi thủ tục

Dia_phuong.

Trong trường hợp trong thủ tục Dia_phuong, ta muốn chiếu đến

biến I toàn cục, ta vẫn có thể dùng nó bằng cách chỉ rõ tên chương

trình ngoài tên biến : Tam_tac_dung.i. Cách tham chiếu như trên cũng

tương tự như khi ta chỉ ra đường dẫn trực tiếp trên DOS.

IV/ Tính đệ qui của chương trình con

Trong Procedure và Function có thể có lời gọi của chính nó. Tính

chất này dược gọi là tính đệ qui.

Thí dụ tính giai thừa qua định nghĩa :

N! = 1 x 2 x... x ( N - 1 ) x N

hoặc định nghĩa :

1

khi N = 0

N! =

N x ( N - 1 )! khi N >= 1

Khi đó, hàm Giai_thua được định nghĩa như sau :

Function Giai_thua( N : Integer ) : Integer ;

Begin

If N = 0 Then Giai_thua := 1 ;

Else Giai_thua := N * Giai_thua( N-1 ) ;

End ;

Một điều cần lưu ý là ta phải hết sức thận trọng lường trước việc kết

thúc của quá trình đệ qui này. Trong thí dụ trên, lệnh gán :

K := Giai_thua( -1 ) ;

sẽ khởi động một quá tình đệ qui rất dài về mặt lý thuyết vì tham số

âm bị xử lý sai.

38

Võ Văn Dũng - Ngôn ngữ lập trình Pascal.

Ở thí dụ trên, ta đã khai báo giai_thua là Integer nên sẽ bị một hạn

chế : chỉ có thể tính với N < 8 vì nếu N >= 8, Giai_thua sẽ mang giá

trị lớn hơn 32767 là giới hạn trên của số nguyên. Một trong các biện

pháp khắc phục là ta khai báo Giai_thua là Real.

Function Giai_thua( N : Integer ) : Real ;

Khi sử dụng Giai_thua là Real, ta phải chú ý sử lý thêm một ít. Ví

dụ, để viết giá trị của Giai_thua là số thực sang số nguyên, ta phải sử

dụng cách viết có quy cách với phần thập phân bị cắt :

Writeln ( Giai_thua(12) : 0 : 0 ) ;

Thí dụ tính giai thừa ở trên về phương diện ví dụ nó rất đơn giản và

dể hiểu. Song về phương diện kĩ thuật lập trình thì đấy là một thí dụ

không đẹp lắm vì người ta có thể tính giai thừa một cách tiết kiệm hơn

bằng chương trình sau khi sử dụng lệnh lặp While :

Function Giai_thua( N : Integer ) : Integer ;

Var I, K :Integer ;

Begin

I := 0 ;

K := 1 ; {Phải dùng biến địa phương K để chứa kết quả

trung gian}

While I < N Do

Begin

I := I + 1 ;

K := K * I ;

End ;

Giai_thua := K ; (* Gán kết quả từ biến trung gian K vào

tên hàm*)

End ;

Trong cách dùng sau, ta chỉ mất hai ô nhớ địa phương tương ứng với

hai biến I và K. Còn trong cách dùng trước, mỗi lần dùng

Giai_thua(N), máy lại phải bố trí thêm một ô nhớ chứa kết quả

Giai_thua trung gian.

Nói chung nên tránh dùng đệ qui khi mà ta có thể dùng phép lặp để

tính toán.

Võ Văn Dũng - Ngôn ngữ lập trình Pascal.

39