Lỗi trình tự:

Một phần của tài liệu Phát hiện và sửa chữa sai lầm cho học sinh THPT khi lập trình bằng ngôn ngữ turbo pascal (Trang 58 - 63)

V- Chạy thử, thay đổi chơng trình:

2.2.2-Lỗi trình tự:

TURBO PASACL là ngôn ngữ lập trình có cấu trúc, các câu lệnh trong CT đợc thực hiện theo một trình tự trên xuống, nên việc viết sai vị trí câu lệnh trong CT sẽ cho ta kết quả sai không nh mong muốn. Lỗi này xảy ra ở các em khi học lập trình do ý thức cha đầy đủ về cách đặt câu lệnh. Một số chơng trình sau nhằm minh hoạ cho nhận lỗi trên.

Bài 2.1:Cho trớc một dãy số nhập từ bàn phím. Hãy thiết lập dãy thứ 2 bao gồm các giá trị khác nhau của dãy thứ nhất và đợc sắp xếp theo thứ tự tăng dần.

Chơng trình minh hoạ bằng ngôn ngữ TP:

(?): 1) Program day_so; 2)Uses crt;

3)Var a,b:array[1..100] of integer; 4) n,i,j:byte;

5) tg:integer; 6)Begin

7) write(' nhap do dai cua day n='); readln(n); 8) for i:=1 to n do

9)begin

10) write(' a[',i:2,']='); readln(a[i]); 11) end; 12) for j:=1 to n-1 do 13) for i:=j+1 to n do 14) if a[j]>a[i] then 15) begin 16) tg:=a[j]; 17) a[j]:=a[i]; 18) a[i]:=tg; 19) end; 20) j:=j+1; 21) end; 22) j:=1; 23) b[1]:=a[1]; 24) for i:=2 to n do

25) if a[i]>b[j] then 26) begin

27) j:=j+1; 28) b[j+1]:=a[i]; 29) end;

30) for i:=1 to j do write(b[i]:4); 31) Readln;

32)End.

(!): Sau khi chơng trình dịch xong và chạy thử chơng trình với n nhập vào là: với n=9: 1 2 3 4 2 3 5 6 5

Kết quả cho ta dãy 2 là: 1 0 2 3 4 5 5.

Lỗi này do đâu? Khi kiểm tra thuật toán không có vấn đề gì. Vậy ta thử chạy chậm chơng trình để xem kết quả ra sao:

Đầu tiên ta nhập cho n một giá trị cụ thể, cho vào một mảng.

Cho j chạy từ 1 đến n-1 để sắp xếp dãy 1, còn biến i chạy từ j+1 đến n, để thực hiện thao tác sắp xếp.

Cho dãy cần sắp xếp lại là b[i].

Bắt đầu ghi lại phần tử đầu tiên của dãy2 cho biến j trỏ vào phần tử cuối cùng của dãy 2 và thực hiện b[1]:=a[1]; ghi lại phần tử đầu tiên của dãy2.

Sau đó kiểm tra a[i]> b[j]? nếu còn lớn hơn thì ta tiếp tục cho j tăng lên 1: j:=j+1 nó sẽ chỉ vào vị trí phần tử cuối dãy2. Sau đó thì b[j+1]:= a[i]. Ghi tiếp phần tử này vào dãy 2.

Nó sẽ thực hiện cho đến khi nào a[i]< b[j] thì dừng và đa ra màn hình dãy 2 vừa thu đợc từ dãy 1. Trên t tởng của thuật toán nh thế không có vấn đề gì? Nhng tại sao lại cho ta kết quả sai nh vậy. Điều đáng nghi ngờ nhất là dòng lệnh : j:= 1; b[1]:=a[1] và dòng lệnh j:=j+1, b[j+1]:=a[i], lệnh nào sẽ đợc thực hiện trớc?

ở các lệnh trớc thì a[i] đã nhận đợc giá trị bé nhất do đó ta phải thực hiện lệnh: b[1]:= a[1] trớc, tơng tự câu lệnh b[j+1]:=a[i] thực hiện trớc khi thực hiện lệnh j:=j+1. Vậy sau khi thay đổi vị trí các câu lệnh này. Thì kết quả thu đợc nh mong muốn.

Bài 2.2: Hai quả cầu nhỏ giống nhau cùng có khối lợng m (gam) và điện tích Q culông, đợc treo tại cùng một điểm bằng hai sợi dây mảnh

đội dài 1 cm. Do lực đẩy tĩnh điện, hai quả cầu tách ra xa nhau. Ngời ta đo đợc góc lệch giữa hai sợi dậy là α độ.

Lập trình nhập m, l từ bàn phím, sau đó đa ra màn hình giá trị điện tích Q theo các giá trị của α . Các giá trị của α đợc cho liên tiếp từ bàn phím cho đến khi vào giá trị α <=0 thì chơng trình dừng.

Chơng trình minh hoạ bằng ngôn ngữ TP: (?): 1) Program Qua_cau; 2) Uses Crt; 3) Const g=9.8; 4) k=9e9; 5) Var m,l,q,anfa,r,sina,cosa,d:real; 6) Begin 7) Clrscr;

8) Write('Khoi luong qua cau (gam)'); Readln(m); 9) Write(' Chieu dai day treo (cm)'); Readln(l); 10) r:=pi/180;

11) Write(' Goc lech giua hai day (do)'); Readln(anfa); 12) if anfa>0 then 13) Repeat 14) Begin 15) anfa:=r*anfa/2; 16) sina:= sin(anfa); 17) cosa:= cos(anfa); 18) {anfa:=r*anfa/2;} 19) d:= 2*l*sina*1e-2; 20) q:=d*sqrt(m*g*1e-3*sina/cosa/k);

21) Writeln(' dien tich moi qua cau=', q:3,'(culong)'); 22) end;

23) Until anfa<0; 24) Readln;

25) End.

(!): Khi ta dịch chơng trình TP không phát hiện đợc lỗi của chơng trình nhng cho ta kết quả không đúng. Vậy lỗi do đâu?. Ta thử chạy chậm chơng trình sẽ rõ:

Khối lợng quả cầu: 100 (gam). Chiều dài của dây treo : 1 (cm). Tính giá trị: r:=pi/180;

Nhập góc lệch giữa hai dây : 45 (độ). Kiểm tra: 45>0. Bắt đầu lặp.

Lặp: anfa:= r*anfa/2; Sina:= sin(anfa); Cosa:= cos(anfa); D:= 2*l*sina*1e-2;

Q:=d*sqrt(m*g*1e-3*sina/cosa/k).

In ra điện tích quả cầu. Tiếp đến kiểm tra: anfa <=0? Nếu sai quay trở lại vòng đầu vòng lặp thực hiện các lệnh trong thân REPEAT. Điều này có vẻ không mẫu thuẫn nhng thực sự là sai lầm.

Sai lầm ngay ở vòng lặp, chính vì thế nên vòng lặp lặp vô hạn mà kết quả thu đợc là toàn 0.0e+00. Lỗi ở đây là do các đặt vòng lặp sau khi nhập độ lệch của quả cầu. Mà các em quên rằng: độ lệch này lại là biến điều khiển vòng lặp. Sau khi nhập anfa máy kiểm tra anfa>0 ? đúng thì thực hiện cho đến khi anfa<=0 mới kết thúc. Mà anfa là một số dơng, r cũng là một số dơng nên phép gán anfa:= r*anfa/2 luôn dơng, kết quả là anfa mang một giá trị này nên vòng lặp trở nên luẩn quẩn.

Vậy để vòng lặp có thể dừng sau hữu hạn bớc, chúng ta phải để lệnh REPEAT trớc câu lệnh nhập độ lệch anfa của hai dây.

Chỉ do sơ suất trong khi viết trình tự của câu lệnh trong chơng trình mà kết quả của nó thật là tai hại.

Bài 2.3: Một ôtô đang chạy bị hãm lại đột ngột. Bánh xe không lăn nữa mà chỉ trợt trên đờng nhựa. Ngời ta căn cứ vào độ dài s của vết trợt để tính vận tốc của xe trớc lúc bị hãm. Hãy lập trình đa ra màn hình các vận tốc này (tính theo km/giờ) ứng với các giá trị s biến thiên trong khoảng s1 đến s2 với bớc nhảy d (tính theo mét).

Lấy gia tốc rơi tự do là 9.8 mét/giây2 và hệ số ma sát trợt của lốp cao su trên đờng nhựa là 0.6.

Các giá trị s1, s2 và d nhập từ bàn phím. Yêu cầu các số đợc in ra với 1 chữ số lẻ.

(?): 1) Program Van_toc; 2) Uses Crt; 3) Const g= 9.8; 4) k=0.6; 5) Var a,s1,s2,s,v,d:real; 6) Begin 7) Clrscr;

8) Write(' khoang bien thien s1, s2 (met)= '); readln(s1,s2); 9) Write(' Buoc nhay d (met)= '); readln(d);

10) a:=k*g; 11) s:=s1;

12) Writeln(' Vet truot (m) ---- Van toc (km/gio)'); 13) Writeln; 14) Repeat 15) v:=3.6* sqrt(2*a*s); 16) s:=s+d; 17) Writeln( s:6:1,'', v:6:1); 18) Until s>s2; 19) Readln; 20) End.

(!): Sau khi dịch chơng trình TP thông báo dịch thành công, bớc tiếp theo là ta chạy thử chơng trình với: s1= 10; s2= 20; d=1; kết quả hiện trên màn hình là:

Vết trợt : 11 12 13 14 15 16 17 18 19 20 21 Vận tốc (km/gio): 39 40,9 42,8 44,5 46,2 47,8 49,4 50,9 52,4 53,8 55,2

Tại sao kết quả lại không đúng: Theo câu lệnh lặp thì khi s>s2 thì kết thúc vòng lặp nhng trên màn hình hiện là s=21>s2=20 mà kết quả vẫn đợc thực hiện. Lỗi này xảy ra do học đặt câu lệnh tính s=s+d trớc vận tốc, và trớc câu lệnh in ra màn hình s và v. Do sau khi thực hiện câu lệnh s=s1, máy sẽ tính giá trị của

v= 3.6 * sqrt (2*a*s); tăng biến s=s+d, rồi mới đến câu lệnh viết lên màn hình kết quả thu đợc giữa s và v. Do đó, sau khi tính v với giá trị s= s+1=21 và thoát khỏi vòng lặp REPEAT. Vậy để sửa lại, ta đổi câu lệnh in

kết quả lên màn hình trớc tiếp đến mới tăng giá trị của s và trở lên tiếp tục tính vận tốc. Kết quả ta thu đợc nh sau là hoàn toàn đúng:

Một phần của tài liệu Phát hiện và sửa chữa sai lầm cho học sinh THPT khi lập trình bằng ngôn ngữ turbo pascal (Trang 58 - 63)