Kỹ thuật Debug trong C
Hướng dẫn debug :
- Đầu tiên nhấn Ctrl-F9 để thực thi toàn bộ chương trình.
- Chương trình yêu cầu nhập hai hệ số a, b. Nhập “1 1” rồi ENTER.
Chương trình xuất ra câu “Phuong trinh vo so nghiem”. Rõ ràng đây là kết quả sai, với hệ số 1 1 thì nghiệm phải là x = -1.
Nhấn Enter để quay trở lại màn hình soạn thảo để dò tìm lỗi.
Kiểm tra phần nhập.
- Di chuyển con trỏ đến dòng 54 (tức là ngay sau lời gọi hàm nhap()), nhấn phím F4.
- Chương trình yêu cầu nhập hai hệ số a, b. Nhập lại “1 1” rồi ENTER.
- Trong màn hình soạn thảo, nhấn phím Ctrl-F4, trong ô nhập “Expression” nhập “a” rồi ENTER. Trong ô “Result” là giá trị hiện thời của biến “a”, giá trị là “0.0”.
- Làm tương tự với biến “b”, ta cũng có kết quả tương tự b = 0.0. Nhấn ESC để thoát khỏi hộp thoại tính giá trị.
Hai giá trị a, b không đúng với giá trị nhập, chứng tỏ hàm nhap() có lỗi.
- Nhấn Ctrl-F2 để bắt đầu lại việc thực thi.
Kiểm tra hàm nhap().
- Di chuyển con trỏ đến dòng 53 (ngay tại lời gọi hàm nhap()), nhấn F4. Rồi nhấn F7 để thực hiện lời gọi hàm. Dòng xanh được di chuyển đến dòng 12).
- Nhấn F7, dòng xanh di chuyển đến dòng 14 : lệnh printf.
- Nhấn F7, C vừa thực thi xong lệnh printf. Nhấn Alt-F5 để xem màn hình thực thi.
Trên màn hình sẽ có câu “Nhap 2 he so a, b :”
- Nhấn ESC để quay trở lại màn hình soạn thảo.
- Nhấn F7, C thi hành lệnh scanf. Màn hình được chuyển sang màn hình thực thi, nhập “1 1” rồi ENTER.
Kỹ thuật Debug trong C Đối với lập trình viên, việc đề ra ý tưởng để giải quyết vấn đề đã là khó khăn, nhưng việc cài đặt được ý tưởng đó cũng không đơn giản. Đôi khi chỉ vì một dấu “;” hay sai kiểu dữ liệu cũng có thể biến bản cài đặt trở nên vô nghĩa vì không thể hiện đúng ý tưởng đề ra. Nhưng làm sao để phát hiện ra một con sâu (lỗi-bug) trong một “rừng lệnh”? Câu trả lời rất đơn giản nhưng khó thực hiện : chúng ta phải kiên nhẫn “vạch lá tìm sâu” ! Đó là lý do tại sao chúng ta phải nắm kỹ thuật debug. Bài viết này nhằm hướng dẫn các bạn sử dụng kỹ thuật debug để tìm lỗi thông qua việc phân tích các ví dụ, đồng thời cũng đưa ra một số bài tập từ dễ đến khó để các bạn có thể từng bước nắm vững kỹ thuật debug. Hi vọng bài viết này sẽ giúp ích được cho các bạn. Mọi thắc mắc hoặc ý kiến đóng góp xin gửi về địa chỉ mail : nvhoang@fit.hcmuns.edu.vn. Các loại lỗi trong chương trình: Lỗi sai cú pháp: Đây là những lỗi sai xảy ra khi biên dịch chương trình (sau khi nhấn F9). Khi gặp lỗi này, chúng ta nên nhấn Ctrl-F1 để gọi giúp đỡ hoặc xem lại tài liệu tham khảo. Ở đây không để cập chi tiết đến vấn đề này. Lỗi sai logic: Khái niệm : Các lỗi sai logic là những lỗi khi biên dịch, trình biên dịch không báo lỗi. Những lỗi này nằm tiềm ẩn trong chương trình và làm cho chương trình của chúng ta đưa ra những kết quả không như mong muốn. Các lỗi sai logic thường xuất phát từ 2 nguyên nhân : Do “nhầm” (nhầm chứ không sai) cú pháp dẫn đến sai logic. Do ý tưởng để giải quyết bài toán đã sai ngay từ đầu. Loại lỗi này bình thường rất khó nhận ra. Dĩ nhiên, nếu tinh ý đôi khi chúng ta vẫn có thể phát hiện ra những lỗi này, nhưng việc phát hiện này đòi hỏi chúng ta phải nắm rất vững cú pháp C, cũng như logic của chương trình cộng thêm một chút kinh nghiệm. Tuy nhiên, trong đa số các trường hợp chúng ta phải thực hiện công đoạn debug để tìm ra các lỗi sai logic này. Một số ví dụ về lỗi sai logic : Sau đây là một số ví dụ về lỗi sai logic: VD1 : Xét hàm hoán vị 2 số nguyên void HoanVi(int a, int b) { int c = a; a = b; b = c; } Thoạt nhìn, chúng ta hàm này không có vấn đề gì cả ! Nhưng nếu tinh ý một chút chúng ta sẽ thấy cách truyền tham số của hàm là sai, đây là cách truyền tham trị chứ không phải truyền tham biến, do đó giá trị của a, b sẽ không thay đổi sau khi hàm thực hiện xong. Chúng ta phải sửa lại như sau : void HoanVi(int &a, int &b) { int c = a; a = b; b = c; } VD2 : Xét hàm sắp xếp mảng một chiều các số nguyên theo thứ tự tăng dần /* Hàm sắp xếp mảng Tham số vào : n – số lượng số nguyên a - mảng một chiều các số nguyên, từ a[0]...a[n-1] */ void SapXepMangTangDan(int n, int a[]) { int i, j; for (int i = 0; i < n; i++); for (int j = 0; j < n; j++) if (a[i] > a[j]) HoanVi(a[i], a[j]); } Nếu như chúng ta chưa từng gõ đoạn mã hàm sắp xếp thì có lẽ chúng ta khó phát hiện ra chỗ sai. Nhưng cho dù như vậy chúng ta vẫn có thể phát hiện ra dòng lệnh “for (int i = 0; i < n; i++);” là có vấn đề, tại sao lại có dấu “;” ở cuối dòng lặp “for” ? Nhưng cho dù bạn có bỏ dấu “;” đi thì hàm này vẫn sai. Trong trường hợp này chúng ta bắt buộc phải debug để loại đi những lỗi logic. Các bạn có thể tham khảo phục lục để xem một số lỗi sai logic thường gặp. Cơ chế thực thi chương trình : Để có thể thực hiện công việc debug, trước hết chúng ta sẽ tìm hiểu cơ chế thực thi của một chương trình C. (Để cho đơn giản, tôi xin phép chỉ trình bày việc thực thi mức ngôn ngữ C, chứ không trình bày ở mức ngôn ngữ assembly). Cơ chế chính thực thi trong chương trình C là thực thi từng dòng lệnh từ trên xuống dưới, chỉ khi gặp những lệnh rẽ nhánh (if), những lệnh lặp (for, while), những lời gọi hàm, hay lệnh nhảy (goto) thì C sẽ chuyển đến thực thi dòng lệnh đã được chỉ định, rồi lại tuân theo cơ chế từ trên xuống dưới. C luôn luôn bắt đầu thực thi từ hàm main(). Cơ chế chính của việc thực thi : Thực thi từ trên xuống dưới, bắt đầu từ hàm main() 1 #include 2 #include 3 void main() 4 { 5 clrscr(); 6 printf(“Đây là chương trình ví dụ\n”); 7 getch(); 8 } Như đã nói trên, C sẽ bắt đầu thực thi chương trình từ hàm void main() : dòng lệnh 4. Sau đó C sẽ tiếp tục thực thi từ trên xuống dưới. Tức là tiếp tục thực thi dòng lệnh 5 : clrscr(), rồi đến dòng lệnh 6 : printf , rồi đến dòng lệnh 7 : getch(). Sau khi thực thi xong dòng lệnh 8 : dấu “}”, không còn gì thực thi nữa C sẽ kết thúc việc thực thi. Các lệnh if...else, while, do..while : Các lệnh này các có tham khảo lý thuyết, xin phép không nêu ra ở đây. Tuy nhiên, có một vài lưu ý sau : Các lệnh lặp cũng được thực thi theo cơ chế từ trên xuống dưới, nhưng khi đến cuối khối lệnh lặp, C sẽ quay lại đầu khối để thực thi (nếu biểu thức điều kiện trong while thỏa) Sau khi thực thi xong các lệnh này (tức là các biểu thức trong if, while đều thực thi xong), C sẽ tiếp tục thực thi khối lệnh ngay tiếp sau những lệnh này. VD : Nhập một mảng các số nguyên dương A, việc nhập kết thúc khi nhập một số âm. Sau đó kiểm tra xem dãy A đó có tăng hay không, xuất ra màn hình “DÃY TĂNG” hoặc “DÃY KHÔNG TĂNG”. #include #include 1 void main() 2 { 3 int a[100]; // mang cac so nguyen duong 4 int n; // so luong phan tu 5 int x; 6 int daytang; 7 clrscr(); 8 9 // nhap 10 n = 0; 11 do 12 { 13 printf("nhap a[%d] : ", n); 14 scanf("%d", &x); 15 if (x >= 0) 16 { 17 a[n] = x; 18 n++; 19 } 20 } 21 while (x >= 0); 22 // xu ly 23 daytang = 1; // gia su day tang 24 for (int i = 0; i < n-1; i++) 25 if (a[i] > a[i+1]) // kiem tra tinh tang 26 daytang = 0; 27 // xuat 28 if (daytang) 29 printf("DAY TANG\n"); 30 else 31 printf("DAY KHONG TANG\n"); 32 33 getch(); 34 } Đầu tiên C sẽ bắt đầu thực hiện từ hàm main() (dòng 1). Xét khi C thực hiện tới vòng lặp do...while (dòng 11). C sẽ lần lượt thực hiện các dòng lệnh 12, 13, 14. Đến dòng 15 là dòng lệnh if, C sẽ tính toán xem (x >= 0) hay không, nếu x >= 0 C sẽ tiếp tục thực thi dòng lệnh 17, 18, 19, rồi sang dòng 20, còn nếu x < 0 thì C sẽ chuyển sang thực thi dòng 20 (xin lưu ý dòng 20 chính là lệnh tiếp sau lệnh if). Khi C thực hiện tới dòng 21, chính là cuối khối lệnh do..while, C sẽ kiểm tra biểu thức điều kiện trong while (x >= 0), nếu biểu thức này thỏa C sẽ quay lại lệnh 11, nếu không C sẽ thực hiện lệnh 23. Khi C thực hiện tới dòng 24 : lệnh lặp for. Đầu tiên C sẽ thực hiện int i = 0. Sau đó kiểm tra i < n-1, nếu đúng thì qua dòng 25, nếu không thì kết thúc dòng for (dòng 28). Khi đến dòng 25 : lệnh rẽ nhánh if, C sẽ kiểm tra điều kiện (a[i] > a[i+1]) nếu đúng thì qua dòng 26 rồi kết thúc lệnh if, còn nếu sai thì cũng thúc lệnh if. Nhưng do lệnh if nằm trong for cho nên C sẽ tiếp tục thực thi dòng for, tức là quay lại dòng 24. Các đoạn sau tương tự như trên. Lệnh gọi hàm : Khi gặp một lệnh gọi hàm f, C sẽ thực thi như sau : .... void f() { } .... void main() { .... f(); lệnh; ... } 1 2 3 4 Đầu tiên C sẽ di chuyển đến đầu hàm f và thực thi từ trên xuống dưới hàm này. Sau khi thực thi xong hàm, C sẽ quay trở lại thực thi lệnh ngay sau lệnh gọi hàm. Qui trình được diễn tả trong sơ đồ sau : Cách sử dụng debug trong Borland C++ 3.1 : Đây là các chức năng dùng để debug trong BC3.1 Phím tắt Chức năng Ý nghĩa F7 Trace into Dò từng dòng lệnh một. Nếu gặp hàm thì sẽ dò vào trong hàm. F8 Step over Tương tự Trace into, nhưng không dò vào trong hàm. F4 Go to cursor Yêu cầu C thực thi cho đến khi gặp dòng lệnh ngay tại vị trí con trỏ thì ngừng để dò vết. Ctrl-F8 Breakpoint Đặt những điểm dừng tương tự như F4. Ctrl-F2 Program reset Dừng việc debug. Đây là bảng các chức năng xem giá trị trong khi debug. Phím tắt Chức năng Ý nghĩa Ctrl-F4 Evaluate/Modify Xem giá trị của một biểu thức có các biến hiện thời hoặc sửa giá trị của một biến Ctrl-F7 Watch Đưa một biến/biểu thức vào cửa sổ watch để theo dõi khi debug. Các phím chức năng thường sử dụng cho thao tác Debug tương ứng trong VC 6.0 (chỉ có tác dụng khi chạy bằng F5) Visual C++ Borland C++ Ý nghĩa F7 F9 Dịch chương trình F4 Alt + F8 Di chuyển đến vị trí lỗi khi dịch CTRL + F5 CTRL+ F9 Thực thi chương trình F5 Chạy chương trình ở chế độ debug F9 Đặt breakpoint F10 F8 Step over F11 F7 Step into Ctrl + F10 F4 Goto Mở cửa sổ Watch (Menu View à Debug à Watch) Gõ tên biến cần xem Hoặc: đánh dấu biến cần biết giá trị, dùng chuột kéo và cửa sổ này Hoặc: đưa con trỏ chuột vào vị trí có tên biến, giá trị của biến sẽ hiện ra Ctrl + F7 Xem giá trị 1 biến SHIFT + F5 CTRL + F2 Kết thúc debug CTRL + TAB F6 Chuyển đổi cửa sổ Chiến thuật dò tìm lỗi theo vùng: Mục đích chính của debug là tìm ra được những lỗi sai logic để từ đó có biện pháp giải quyết thích hợp. Tuy nhiên, trong một chương trình lớn việc tìm ra một lỗi là không dễ. Do đó việc tìm lỗi đòi hỏi phải có một chiến thuật thích hợp. Mỗi người có thể có một cách tìm lỗi khác nhau, nhưng ở đây chúng ta chỉ sẽ khảo sát chiến thuật tìm lỗi theo vùng. Ý tưởng chính Ý tưởng chính của chiến thuật này là kiểm tra lỗi trong từng vùng một, từ trên xuống dưới, vùng nào đã kiểm tra rồi sẽ không quay lại kiểm tra nữa. Áp dụng : Thông thường thân một chương trình có dạng sau : void main() { Nhap(); Xuly(); Xuat(); } Giả sử với bộ kiểm tra T nào đó, chương trình này cho kết quả không như mong muốn. Như vậy, một trong 3 phần này sẽ có một sự sai sót nào đó, vấn đề là chúng ta phải khoanh vùng để phát hiện lỗi. Bắt đầu từ phần nhập, di chuyển con trỏ đến đầu phần xử lý (tức là cuối phần nhập), rồi nhấn F4 để C thực thi phần nhập : Nhập đúng những giá trị của bộ kiểm tra T. Sau khi C thực thi xong, nhấn phím Ctrl-F4, rồi kiểm tra lần lượt từng thành phần (các biến) vừa nhập (hoặc có thể dùng Watch Window để theo dõi), nếu tất cả các thành phần nhập đều đúng, chứng tỏ phần nhập đúng với bộ kiểm tra T và như vậy phần nhập coi như kiểm tra xong. Nếu có một thành phần sai, chứng tỏ phần nhập có lỗi, khi đó chúng ta lại áp dụng đúng chiến thuật này đối với phần nhập, khoanh vùng hẹp dần cho đến khi chỉ còn một hay một vài lệnh mà bảo đảm có lỗi. Lúc này, chúng ta sẽ kiểm tra cú pháp, logic của từng lệnh một trong vùng cho đến khi phát hiện lỗi. Sau khi phát hiện lỗi và sửa lỗi, chúng ta kiểm tra lại lần nữa xem phần nhập còn lỗi nào khác hay không, cho đến khi chắc chắn rằng phần nhập đã đúng với bộ dữ liệu T. Sau khi kiểm tra xong phần nhập với bộ dữ liệu T, tiếp tục kiểm tra các thành phần còn lại. Nếu sau khi kiểm tra kỹ tất cả các phần mà kết quả vẫn sai, điều này chứng tỏ ý tưởng ban đầu để giải quyết bài toán đã sai. Nếu bài toán đúng với bộ kiểm tra T, chúng ta phải tiếp tục kiểm tra với các bộ T1, T2...để kiểm tra toàn bộ các khía cạnh của chương trình. Một số ví dụ minh họa : Sau đây là một số ví dụ để minh họa, xin lưu ý các chương trình trong ví dụ đều có ít nhất một lỗi. Chúng ta sẽ áp dụng kỹ thuật debug và chiến thuật tìm lỗi theo vùng để phát hiện ra lỗi. Giải phương trình bậc nhất Mô tả chương trình : Đây là chương trình giải phương trình bậc nhất. Chương trình yêu cầu nhập vào 2 hệ số a, b thực rồi in kết quả ra màn hình. Tổ chức chương trình như sau : hàm nhap() Nhập 2 hệ số a, b. Hàm giaiptbn() Đưa vào hê số a, b. Hàm sẽ trả về giá trị VONGHIEM nếu phương trình vô nghiệm; VOSONGHIEM nếu phương trình vô số nghiệm; CONGHIEM nếu phương trình có nghiệm, trong trường hợp này giá trị nghiệm được lưu trong biến x. Hàm xuat() Đưa vào số nghiệm, và nghiệm, hàm sẽ xuất ra màn hình các câu tương ứng. Hướng dẫn debug : Đầu tiên nhấn Ctrl-F9 để thực thi toàn bộ chương trình. Chương trình yêu cầu nhập hai hệ số a, b. Nhập “1 1” rồi ENTER. Chương trình xuất ra câu “Phuong trinh vo so nghiem”. Rõ ràng đây là kết quả sai, với hệ số 1 1 thì nghiệm phải là x = -1. Nhấn Enter để quay trở lại màn hình soạn thảo để dò tìm lỗi. Kiểm tra phần nhập. Di chuyển con trỏ đến dòng 54 (tức là ngay sau lời gọi hàm nhap()), nhấn phím F4. Chương trình yêu cầu nhập hai hệ số a, b. Nhập lại “1 1” rồi ENTER. Trong màn hình soạn thảo, nhấn phím Ctrl-F4, trong ô nhập “Expression” nhập “a” rồi ENTER. Trong ô “Result” là giá trị hiện thời của biến “a”, giá trị là “0.0”. Làm tương tự với biến “b”, ta cũng có kết quả tương tự b = 0.0. Nhấn ESC để thoát khỏi hộp thoại tính giá trị. Hai giá trị a, b không đúng với giá trị nhập, chứng tỏ hàm nhap() có lỗi. Nhấn Ctrl-F2 để bắt đầu lại việc thực thi. Kiểm tra hàm nhap(). Di chuyển con trỏ đến dòng 53 (ngay tại lời gọi hàm nhap()), nhấn F4. Rồi nhấn F7 để thực hiện lời gọi hàm. Dòng xanh được di chuyển đến dòng 12). Nhấn F7, dòng xanh di chuyển đến dòng 14 : lệnh printf. Nhấn F7, C vừa thực thi xong lệnh printf. Nhấn Alt-F5 để xem màn hình thực thi. Trên màn hình sẽ có câu “Nhap 2 he so a, b :” Nhấn ESC để quay trở lại màn hình soạn thảo. Nhấn F7, C thi hành lệnh scanf. Màn hình được chuyển sang màn hình thực thi, nhập “1 1” rồi ENTER. Trong màn hình soạn thảo, nhấn Ctrl-F4, rồi xem 2 giá trị a, b như đã làm ở trên. Giá trị a = 1.0 và b = 1.0, hàm scanf thực hiện đúng chức năng. Nhưng tại sao sau khi ra hàm nhập a, b lại có giá trị 0 ? Lúc này chúng ta sẽ xem xét kỹ từng dòng lệnh của hàm và phát hiện ra rằng hàm nhap() truyền tham số sai, phải là nhap(float &a, float &b) bởi vì chúng ta muốn thay đổi giá trị 2 biến a, b truyền vào. Sửa hàm “void nhap(float a, float b)” thành “nhap(float &a, float &b)”. Nhấn Ctrl-F2 để thực thi lại từ đầu. Kiểm tra lại hàm nhập để xem giá trị của a, b có đúng hay không như đã làm ở trên. Chúng ta thấy rằng hàm nhập đúng. Nhấn Ctrl-F9 rồi nhập “1 1” ENTER. Chương trình cho kết quả là “Phuong trinh co nghiem la x = 0”. Như vậy kết quả vẫn sai. Kiểm tra hàm giaiptbn(). Di chuyển đến dòng 55, nhấn F4. Nhập “1 1” rồi ENTER. Nhấn Ctrl-F4 để xem giá trị a, b, x, kq. Ta sẽ được a = 1.0, b = 1.0, x = -1.0, kq = 1. Nhấn Ctrl-F2. Như vậy giá trị x =-1.0 là đúng trong trường hợp này. nên chúng ta bỏ qua hàm giaiptbn(). Khả năng gây lỗi là hàm xuat(). Kiểm tra hàm xuat() Di chuyển đến dòng 55, nhấn F4. Nhập “1 1” rồi ENTER. Khi vào màn hình soạn thảo, nhấn F7 để vào hàm xuat(). Nhấn F7 để bắt đầu thực thi dòng “if” thứ 1. Nhấn F7, biểu thức điều kiện “kq == VONGHIEM” có giá trị sai nên C sẽ bỏ qua dòng if thứ 1. Nhấn F7, biểu thức điều kiện “kq == VOSONGHIEM” có giá trị sai nên C sẽ bỏ qua dòng if thứ 2. Nhấn F7, biểu thức điều kiện đúng, dòng xanh di chuyển đến dòng 44 : lệnh printf. Nhấn F7, rồi nhấn Alt-F5 để xem màn hình thực thi. Khả năng gây lỗi chỉ còn có thể là dòng lệnh printf(). Kiểm tra thật kỹ lại cú pháp, chúng ta sẽ thấy lệnh printf là sai : x là biến kiểu số thực nhưng lại dùng chỉ thị xuất là %d. Sửa dòng lệnh printf : “%d” thành “%f.” Nhấn Ctrl-F9, rồi nhập “1 1” ENTER. Kết quả đúng “Phuong trinh co nghiem x = -1.000000” Chạy thử bộ “1 2”, kết quả vẫn đúng. Chạy thử bộ “2 3”, kết quả x = -1.000000. Đây là kết quả sai ! (kết quả đúng là x=-1.5) Như vậy chương trình vẫn còn lỗi. Chúng ta lại tiếp tục debug, nhưng xin để dành công việc này cho các bạn. Xin gợi ý là lỗi nằm trong hàm “giaiptbn()”, đáp án được cho ở phần 7. Sắp xếp mảng tăng dần: Mô tả chương trình : Đây là chương trình sắp xếp mảng tăng dần. Chương trình yêu cầu nhập mảng một chiều các số nguyên. Chương trình sẽ sắp xếp lại theo thứ tự tăng dần, rồi xuất kết quả ra màn hình. Hướng dẫn debug : Phần này không hướng dẫn chi tiết như trên, mà chỉ đưa ra những hướng để debug. Đầu tiên, nhấn Ctrl-F9 để thực thi toàn bộ chương trình. Chương tình yêu cầu nhập n. Nhập “3” rồi ENTER. Chương trình yêu cầu nhập “a[3]”. Nhập “3” rồi ENTER. Chương trình xuất ra số “0”. Nhấn ENTER để kết thúc. Rõ ràng chương trình không cho ra một kết quả nào có vẻ là “đúng đắn”. Nếu chịu khó để ý, chúng ta sẽ thấy sau khi nhập n = 3, chương trình yêu cầu nhập a[3], như vậy dễ dàng thấy dự đoán rằng phần nhập có vấn đề, cụ thể hơn sẽ là vòng lặp nhập mảng có lỗi. Sau khi xem kỹ lại hàm nhập mảng, chúng ta sẽ phát hiện ra lỗi “;” ở cuối dòng for. Sửa lại dòng for trong hàm nhập : bỏ đi dấu “;” cuối dòng for. Kiểm tra các hàm còn lại xem có bị lỗi tương tự hay không. Dễ thấy các hàm sapxepmang() và xuatmang() cũng bị lỗi tương tự. Sửa các lỗi “;” ở các hàm sapxepmang() và xuatmang() Nhấn Ctrl-F9 để thực thi lần nữa. Chương tình yêu cầu nhập n. Nhập “3” rồi ENTER. Chương trình yêu cầu nhập a[0], a[1], a[2]. Nhập lần lượt 2, 1, 3. Chương trình không xuất ra gì cả. Chúng ta có thể dự đoán hàm xuatmang() có lỗi. Nhưng nếu xem xét kỹ, ta thấy hàm xuatmang() không có lỗi gì cả. Như vậy vấn đề còn lại chỉ có thể là phần nhapmang() (do nhập mảng liên quan đến n - ảnh hưởng trực tiếp đến dòng for). Xem xét kỹ lại hàm nhập mảng, nếu vẫn không thấy vấn đề gì thì có lẽ bạn nên debug. (Xem đáp án ở phần 7). Sau khi sửa xong lỗi ở hàm nhập mảng. Nhấn Ctrl-F9 để thực thi chương trình. Nhập n = 3 và a = {3, 1, 1}. Kết quả xuất ra là “3 2 1”. Vẫn sai ! Chúng ta có thể dự đoán lỗi này nằm trong hàm sapxepmang(). Các bạn tự kiểm tra lỗi hàm này. Bài tập : Bao gồm 4 bài tập được kèm theo đây. Đáp án : Ví dụ 5.1 : Lỗi nằm ở dòng 20 : a, b là số thực nên phải sửa lại là “int giaiptbn(float a, float b, float &x)” Ví dụ 5.2 : Lỗi dòng 15,25,26,37 : bỏ dấu “;” cuối dòng for. Lỗi dòng 11 : n là biến cục bộ sẽ không thay đổi giá trị của biến n toàn cục. Bỏ dòng khai lệnh báo “int n”. Lỗi dòng 26 : “for (int j = i + 1 ...” Phụ lục Các lỗi sai cú pháp dẫn tới sai logic thường gặp : Sau đây là danh sách lỗi sai cú pháp dẫn tới sai logic thường gặp trong khi cài đặt chương trình. Danh sách này không hoàn toàn đầy đủ : Lỗi Tình huống minh họa Cách giải quyết Biến toàn cục và biến cục bộ int n; void nhap() { int n; scanf(“%d”, &n}; } ... Bỏ khai báo cục bộ int n, hoặc cho hàm nhập có tham số n. Tham trị và tham biến xem ví dụ hoán vị ở trên thêm dấu “&”, “*” hoặc bỏ 2 dấu này. Dấu “;” for (int i = 0; i < n; i++); xuly(); hoặc if (a > b); xuly(); ... Bỏ dấu “;” thích hợp. Nhập, xuất sai kiểu float f; printf(“%d”, f); hoặc scanf(“%c”, f); ... Sửa cho đúng kiểu Sai chỉ số mảng int a[100]; a[-1] = 0; sửa chỉ số mảng. Dấu “{“ và “}” các dấu “{“, “}” không khớp nhau. Độ ưu tiên phép toán Ckn = gt(n)/gt(k)*gt(n-k). Ckn = gt(n)/(gt(k)*gt(n-k)); Phép toán và kiểu dữ liệu int a, b; float thuong = a/b; ép cho đúng kiểu. float thuong = (float) a/b;
File đính kèm:
- Test_dua_bai.doc