Bạn đang xem bản rút gọn của tài liệu. Xem và tải ngay bản đầy đủ của tài liệu tại đây (182.6 KB, 9 trang )
<span class='text_page_counter'>(1)</span><div class='page_container' data-page=1>
Khi giảng dạy về phần chơng trình con ( CTC ) Tin học 11 tôi nhận thấy
hầu hết học sinh rất bỡ ngỡ với các khái niệm hoàn toàn mới mẻ mang tính trừu
t-ợng nh: D<i>anh sách tham số, tham số giá trị, tham số biến, tham số hình thức,</i>
<i>tham số thùc sù…</i>
Điều làm tơi khơng khỏi băn khoăn đó là làm thế nào để học sinh hiểu và
nắm bắt đợc các khái niệm này một cách hiệu quả nhất, nhằm tránh những sự hiểu
lầm giữa các khái niệm tham biến và tham trị .
Hiện nay hầu hết các ngôn ngữ bậc cao đều tổ chức hai cách truyền tham số
khi gọi một CTC, đó là truyền theo trị và truyền theo biến. Việc truyền tham chiếu
theo hai cách khác nhau nhiều khi gây ra những kết quả khác nhau không mong
muốn, điều này dẫn đến những lỗi logic rất khó phát hiện. Dới đây trình bày
những sai lầm có thể xảy ra khi sử dụng hai cách truyền tham chiếu và cách dùng
chúng cho đúng để đạt đợc múc đích đã đề ra của chơng trình.
Bài viết này khơng nghiêng về thuật tốn của các bài tốn khó mà chỉ đa ra
các bài tốn có thuật tốn đơn giản nhất để học sinh khơng rơi vào việc giải quyết
thuật tốn mà chú trọng đến vấn đề của bài viết: “<i>Một số sai lầm khi dùng tham</i>
<i>biến và tham trị trong PASCAL</i>”
Nếu một CTC có danh sách tham số thì các tham số phải đợc khai báo ở
phần đầu sau tên CTC, trong cặp dấu ngoặc trịn. Khai báo một tham số có nghĩa
là chỉ ra nó thuộc loại tham số nào ( tham số biến hay tham số trị ) và nó có kiểu
dữ liệu là gì?
<i>VÝ dơ</i>: Procedure Delta(Var x: integer ; y: real);
Danh sách tham số là x, y, a, b. Với x có kiểu dữ liệu Integer y, a, b, có kiểu số
thực. Vậy trong danh sách tham số x, y, a, b đâu là tham biến, đâu là tham trị?
Bằng trực quan ta dễ dàng nhận thấy x là tham biến vì x có từ khố Var đứng trớc;
y, a, b là tham trị vì khơng có từ khố Var đứng trớc. Để thấy rõ hơn về bản chất
sự khác nhau giữa tham biến và tham trị ta xét ví dụ sau:
<b>VÝ dô1:</b>
<b>Progam Vidu1;</b>
<b>Procedure Tong_hieu(a, b: Integer; Var c, d: Integer ); </b>
<b>Begin</b>
c:= a – b ;
d:= a + b ;
a:= a*b ;
<b>End;</b>
<b>Begin clrscr;</b>
a:= 10; b:= 3; c:= 5; d:= 6;
Tong_hieu(a,b,c,d);
Write(a,b,c,d);
Readln;
<b>End.</b>
Mới nhìn vào chơng trình nhiều học sinh có thể chủ quan đa ra các giá trị <i>30,</i>
<i>3, 7, 13</i> tơng ứng với các tham số <i>a, b, c, d.</i> Nhng kết qủa nhận đợc sau khi chạy
chơng trình lại là <i>10, 3, 7, 13</i> tơng ứng với các tham số <i>a, b, c, d</i>. Vậy tại sao lại
có kết quả này?
Thật vậy, do <i>a, b</i> đợc truyền theo trị nên khi có lời gọi Tong_hieu(<i>a,b,c,d</i>) thì
giá trị của <i>a, b</i> vẫn đợc giữ nguyên nh ban đầu <i>a = 10, b = 3</i> còn <i>c, d</i> đợc truyền
theo biến nên khi có lời gọi Tong_hieu(<i>a,b,c,d</i>) thì các giá trị của <i>c, d</i> thay đổi <i>c =</i>
<i>7, d = 13</i>
<b>VÝ dơ 2: </b>
<b>Program VD2;</b>
<b>Var x,y: Integer ;</b>
<b>Procedure Thamso(Var Z: Integer ; W: Integer);</b>
<b>Begin</b>
Z:= 1; W:=1;
<b>End;</b>
<b>Begin</b> {chuong trinh chinh}
Writeln(x:5,y:5);
Thamso(x,y);
Writeln(x:5,y:5);
<b>Readln;</b>
<b>End.</b>
Kết quả nào sẽ xuất hiện trên màn hình khi chơng trình đợc thực hiện:
0 0 0 0 0 0 0 0
1 0 1 1 0 1 0 0
Bớc vào thân chơng trình chính ban đầu x và y đều có giá trị là 0 (do các lệnh
x:= 0, y:= 0). Khi gọi thủ tục Thamso(x,y), tham số biến đợc thay bởi biến x. Điêù
này có nghĩa là mọi thao tác đối với z trong thủ tục sẽ xẩy ra đối với x; cụ thể là
lệnh gán z:= 1 bây giờ sẽ là x:= 1, tức gán giá trị 1 cho biến x. Còn khi gọi thủ tục
Thamso(x,y) tham số w đợc thay bởi biến y; giá trị của biến y đợc sao chép sang
cho biến w. Tức là w có giá trị 0. Khi bớc vào thân thủ tục khơng có một liên quan
nào nữa giữa biến y với w, vì vậy lệnh gán w:= 1 khơng ảnh hởng gì đến giá trị
của y. Nh vậy, giá trị của x đợc in ra là 1, còn y là 0.
Với thủ tục Procedure Thamso(Var z: Integer ; w: Integer ) thì các lời gọi sau
đây có hợp lý không? Thamso(x + 1, y) hay Thamso(2, y). Khi thay lời gọi
Thamso(x,y) bằng 2 lời gọi trên thì máy sẽ báo lỗi. Bởi trong lời gọi CTC các
tham số biến chỉ đợc phép thay bởi các biến cùng kiểu, khơng đợc là hằng(2) hay
biểu thức(x+1), cịn các tham số giá trị đợc phép thay thế bởi hằng, biểu thức hoặc
biến đơn. Sự thay thế phải theo đúng trật tự các tham số đã khai báo trong đầu
của CTC. Ngồi lời gọi Thamso(x,y) thì các lời gọi Thamso(x,y+1); Thamso(x,3);
đều khơng hợp lý. Đây chính là một sự khác nhau nữa giữa tham biến và tham trị.
<b>VÝ dô 3: </b>
<b>Program VD3;</b>
Var x,y: Integer;
<b>Procedure Hoandoi(x,y:Integer);</b>
<b>Var t:Integer;</b>
<b>Begin</b>
t:= x; x:= y; y:= t;
<b>End;</b>
<b>Begin</b>
x:=1; y:= 2;
Hoandoi(x,y);
Writeln(‘Hai so chua hoandoi:’,x:2,y:2);
Write('x=',x:2,' y=',y:2);
Readln;
<b>End</b>.
Vậy lỗi xẩy ra do thủ tục Hoandoi(x,y) tổ chức truyền theo trị nên các giá trị
của các biến x và y không bị ảnh hởng bởi các lệnh đổi giá trị trong thủ tục này.
VÝ dô 4:
<b>Program VD4;</b>
<b>Var tu,mau,d:word;</b>
<b>Function UCLN(Var a,b:Word):Word;</b>
<b>Begin</b>
While a<>b Do
If a>b Then a:= a-b
Else b:= b-a;
UCLN:= a;
<b>End;</b>
<b>Begin</b>
Write('nhap tu so:'); Readln(tu);
Write('nhap mau so:'); Readln(Mau);
d:= UCLN(tu,mau); writeln('d =:',d);
<b>If d>1 Then</b>
<b>Begin</b>
Tu:= tu Div d;
mau:= mau Div d;
<b>End;</b>
Writeln('phan so duoc toi gian la:',tu,'/',mau);
Readln;
<b>End.</b>
Chơng trình trên sử dụng hàm UCLN(<i>a, b</i>) để tối giản một phân số khi nhập từ
bàn phím các giá trị tử số và mẩu số của nó.
Nhìn vào chơng trình ta khơng phải bàn đến tính đúng đắn của cơng thức. Vì
ta thấy chơng trình trên trả về UCLN của hai số nguyên dơng <i>a</i> và <i>b</i> và dùng hàm
này để tính <i>d</i> là UCLN của tử và mẫu. Phân số tối giản nhận đợc bằng cách cùng
chia tử và mẫu cho <i>d</i>. Tuy nhiên khi chạy chơng trình, ta ln nhận đợc kết quả
khơng mong muốn là 1/1 cho mọi phân số. Vậy lỗi do đâu?
Lỗi logic này xẩy ra do hàm UCLN đợc tổ chức truyền theo tham biến, nên
sau lời gọi <i>d</i>:<i>=</i> UCLN(<i>tu,mau</i>) , ta đợc đồng thời các giá trị <i>d, tu, mau</i> bằng nhau
và bằng <i>d</i>. Để chơng trình cho kết quả đúng ta phải sửa lại việc khai báo các tham
số trong hàm UCLN là truyền theo tham trị ( bỏ từ khoá Var trớc <i>a, b</i>).
<b>Var a: Byte;</b>
<b>Function F(Var x:Byte):Byte;</b>
<b>Begin</b>
x:=x+1; F:=x;
<b>End;</b>
<b>Begin</b>
a:=5; Writeln(F(a)+F(a));
Readln;
<b>End.</b>
Chơng trình đơn giản trên đa ra màn hình giá trị F(a)+F(a) với <i>a</i> = 5. Bằng suy
luận thông thờng, kết quả đúng phải là 12 vì tại <i>a</i> = 5, F (a) cho giá trị 6. Tuy nhiên
khi chạy chơng trình ta sẽ nhận đợc kết quả 13. Có thể sửa biểu thức F(a)+F(a)
thành biểu thức 2*F(a) lúc này ta sẽ nhận đợc kết quả là 12. Chơng trình vẫn thực
hiện đúng những lệnh mà ta viết, chỉ có điều ở đây xuất hiện hiệu ứng phụ do hàm
F đợc tổ chức truyền theo biến đối với tham biến x của nó. Lệnh <i>x:= x + 1</i> trong
hàm F sẽ làm biến <i>a</i> tăng lên một đơn vị mỗi khi gọi F(a) khi thực hịên biểu thức
F(a)+F(a), giá trị F(a) đợc gọi hai lần. Tại lần thứ nhất <i>a</i> = 5, do đó F(a) = 6 , tại lần
gọi thứ hai lúc đó <i>a</i> = 6 do đó F(a) = 7 và ta nhận đợc kết quả 13.
Trong khi đó biểu thức 2*F(a) chỉ gọi giá trị F(a) một lần vì thế mà ta nhận đợc
kết quả là 12. Nếu sửa lại việc truyền cho tham biến x của hàm F là theo trị thì
khơng cịn sự khác nhau nh vậy nữa.
<b>Câu 1: Với a là tham biến, b là tham trị thì khai báo phần đầu cho thủ tục nào sau</b>
đây là đúng? (a, b đều có kiểu DL Integer)
A. Procedure M(Var a:Integer ; b: Integer );
B. Procedure M(a,b: Integer );
C. Procedure M(Var a,b: Integer );
D. Procedure M(a: Integer ; Var b: Integer ) ;
<i>Đáp án:</i> A
<b>Câu2: Cho biết giá trị tơng ứng cho các biến a, b, c, d sau khi chạy thử chơng</b>
trình :
<b>Progam Vidu1;</b>
<b>Procedure Tong_hieu(a, b: Integer; Var c, d: Integer ); </b>
<b>Begin</b>
c:= a – b ;
d:= a + b ;
a:= a*b ;
<b>End;</b>
a:= 10; b:= 3; c:= 5; d:= 6;
Tong_hieu(a,b,c,d);
Write(a,b,c,d);
Readln;
<b>End.</b>
A. 30, 3, 7, 13 B. 10, 3, 7, 13 C. 10, 3, 5, 6 D. 30, 3, 5, 6
<i>Đáp án:</i> B
<b>Cõu 3: S no c in ra màn hình khi thực hiện chơng trình sau?</b>
<b>Program c3;</b>
<b>Var a,b:byte;</b>
<b>Procedure Thu1(Var a:byte);</b>
<b>Begin</b>
a:= 2*a; b:=b+5;
<b>Begin</b>
a:= 3; b:= 7; Thu1(b);
a:= a+b; Writeln(a);
Readln;
<b>End.</b>
A. 13 B. 19 C. 22 D. (Mt ỏp ỏn khỏc)
<i>Đáp ¸n:</i> C
<b>Câu 4: Số nào đợc in ra màn hình khi thực hiện chơng trình sau?</b>
<b>program C4;</b>
<b>Var x:integer;</b>
<b>Procedure Thaydoi( x:integer);</b>
<b>Begin</b>
x:=1;
<b>end;</b>
<b>Begin</b>
x:=0; Thaydoi(x); Writeln(x:3);
readln
<b>End.</b>
A. 1 B. 0 C. 1 0 D. 0 1
<i>Đáp án:</i> B
<b>Câu 5: Chơng trình sau cho kết quả gì? </b>
<b>Program VD5;</b>
<b>Var a: Byte;</b>
<b>Function F(Var x:Byte):Byte;</b>
<b>Begin</b>
x:=x+1; F:=x;
<b>End;</b>
<b>Begin</b>
a:=5; Writeln(F(a)+F(a));
Readln;
A. 10 B. 11 C. 12 D. 13
<i>Đáp án:</i> D
<b>Cõu 6: (Ta cng cú th có câu hỏi nh sau đối với Vd5):</b>
Hãy sửa lỗi chơng trình trên để chơng trình có kết quả là 12 ?
<i>Đáp án</i>: Cách 1: <b>Function F( x:Byte):Byte;</b>
Cách 2: Thay biểu thức (F(a)+F(a))thành biểu thức (2*F(a))
<b>Câu 7: Với đầu thủ tục: </b>
Procedure N( x:Integer ; Var y:Integer );
m là biến nguyên, các lời gọi sau đây lời gọi nào là hợp lệ?
A. N(m,m+3);
B. N(2,m);
C. N(m+1,4);
D. N(2,3*m+5);
<i>Đáp án</i>: B
<b>Câu 8: HÃy sữa lỗi chơng trình sau và cho biết chơng trình sau làm việc gì?</b>
<b>Program </b> C8;
<b>Var n:integer;</b>
<b>Begin</b>
<b>Function fibo( Var n: longint):longint;</b>
<b>Begin</b>
<b>If n<3 then fibo:= 1</b>
<b>Else fibo:= fibo(n-1)+fibo(n-2);</b>
<b>End;</b>
Write(‘nhap n:’); Readln;
Writeln(fibo(n));
<b>Readln;</b>
<b>End</b>.
<i>Đáp án</i>: Chơng trình đợc sữa lỗi:
<b>Program </b> C8;
<b>Var n:integer;</b>
<b>Function fibo(n: longint):longint;</b>
<b>Begin</b>
<b>If n<3 then fibo:= 1</b>
<b>Else fibo:= fibo(n-1)+fibo(n-2);</b>
<b>End;</b>
<b>Begin</b>
Write(‘nhap n:’); Readln(n);
Writeln(fibo(n));
<b>Readln;</b>
<b>End</b>.
Chơng trình dùng hàm để tính dãy số Fibonaxi F1, F2, …, Fn
víi F1= F2=1
Đề tài đã thu đợc một số kết quả sau:
Xây dựng đợc hệ thống câu hỏi, bài tập để giảng dạy chơng
VI – phần CTC và lập trình có cấu trúc,
Sử dụng các ví dụ này vào trong các đề kiểm tra: tìm đáp án
đúng hay sửa lỗi chơng trình…
Đề tài đã đợc ứng dụng để giảng dạy và đạt kết quả tốt
trong năm học vừa qua. Phần lớn học sinh đã phân biệt đợc
bản chất của sự khác nhau giữa tham biến và tham trị và
cách sử dụng chúng.
Để tiết kiệm thời gian và các giờ học đạt kết quả cao, giáo
viên cần chuẩn bị sẵn các chơng trình vào máy hay trên khổ
giấy lớn. Học sinh có thể chạy chơng trình và thử với các
bộ test khác nhau (Tốt hơn là dạy bằng máy chiếu vì hầu
hết trờng nào cũng đã có).
Bài viết này mới chỉ là một phần của CTC, chúng tôi mong
rằng có nhiều bài viết về những vấn đề cịn lại của CTC để
hồn thiện cả phần CTC.
<i>Th¸ng 4 / 2008</i>
1. Hå Sĩ Đàm Hồ Cẩm Hà - Trần Đỗ Hùng Nguyễn Đức Nghĩa
Nguyễn Thành Tùng Ngô ¸nh Tut . Tin häc 11(SGK thÝ ®iĨm),
NXB Gi¸o dục.
2. Hồ Sĩ Đàm Hồ Cẩm Hà - Trần Đỗ Hùng Nguyễn Đức Nghĩa
Nguyễn Thành Tùng Ngô ánh Tuyết . Tin học 11(SGV thí điểm),
NXBGD.
3. Lê Khắc Thành Hồ Cẩm Hà - Nguyễn Vũ Quốc Hng. Tài liệu bồi
d-ỡng thờng xuyên cho GV THPT chu kú III (2004 – 2007).