Скачать презентацию 偵錯的技巧 南台科大 黎靖 偵錯的 鄰近原理 v 語句的鄰近 Скачать презентацию 偵錯的技巧 南台科大 黎靖 偵錯的 鄰近原理 v 語句的鄰近

5901e856a912f7096b1093ff2ac54726.ppt

  • Количество слайдов: 29

偵錯的技巧 南台科大 黎靖 偵錯的技巧 南台科大 黎靖

偵錯的 鄰近原理 v 語句的鄰近 v 執行順序 的鄰近 v 空間的鄰近 偵錯的 鄰近原理 v 語句的鄰近 v 執行順序 的鄰近 v 空間的鄰近

語句的鄰近 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. #include <stdio. 語句的鄰近 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. #include #include int main() { int i ; for (i = 0; i < 5; i++) printf("n. Hellow World") printf("n. Goodbye Worldn"); system("PAUSE"); return 1; } v v 錯誤訊息指出第 8行 expected `; ‘ before “printf” 。 因此實際錯誤是第 7行末尾 忘了加 ‘; ’

執行順序 的鄰近 int main() 2. { … 40. while(k < 7) 41. { 42. 執行順序 的鄰近 int main() 2. { … 40. while(k < 7) 41. { 42. dotest(); …. 240. proc 1(); 241. } 242. } 1. v proc 1()執行完後,若 k<7則 執行 dotest() ,所以proc 1() 及 dotest() 為 執行順序 的 鄰近,因此當錯誤訊息指 出第 42行有錯時,實際錯 誤可能在 240行。

空間的鄰近 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 空間的鄰近 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. #include #include int main() { int i, j, k ; i = 0; for(j = 0; j < 19; j++) { for(k = 0; k < j; k++) { putchar(' '); } printf("*n"); } printf("%dn", i); system("PAUSE"); return 1; } v 第 6行及第 15行空間的鄰 近,因此找錯誤時,第 6行 及第 15行應同時檢查。

偵錯的方法 v 縮小範圍法 v 程式結構追蹤法 v 資料流程追蹤 法 v 快照 (Snapshots) 偵錯的方法 v 縮小範圍法 v 程式結構追蹤法 v 資料流程追蹤 法 v 快照 (Snapshots)

縮小範圍法 v 當編譯器無法正確指出錯誤所在時,可以 利用去除部份程式碼的方式,找出錯誤的 可能範圍。 縮小範圍法 v 當編譯器無法正確指出錯誤所在時,可以 利用去除部份程式碼的方式,找出錯誤的 可能範圍。

找出下列程式的錯誤 1. 2. 3. #include <stdio. h> #include <stdlib. h> #include <string. h> 24. 找出下列程式的錯誤 1. 2. 3. #include #include #include 24. 25. 26. 27. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. #define HEAD 4 #define LENGTH 24 #define P 0 5 #define WIDTH 95 #define ERROR -1 #define MAXLINES 10 char *lines[MAXLINES]; FILE *fd, *printer; int main() { char buff[80]; int max, j, offset, len, count; if ((fd = fopen("address", "r")) == 0) { / * give the user some lelp. . . * / printf("address file does not exist. n"); exit(ERROR); } printer = fopen("LPT 1", "w"); 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. for (count = 0, max = 0; count < MAXLINES; count++) { if (fgets(buff, 80, fd) == 0) break; else { len = strlen(buff); lines[count] = (char *)malloc(80); if (len > max) max = len; strcpy(lines[count], buff); } } offset = ((WIDTH - max)/2)+P 0; for (j = 0; j < offset; j++) buff[j] = ' '; buff[j] = ''; offset = (LENGTH - count)/2 - HEAD; for (j = 0; j < offset; j++) fputs("n", printer); for( j = 0; j < count; j++) fprintf(printer, "%s%s", buff, lines[j]); fputs("14", printer); fclose(fd); fclose(printer); system("PAUSE"); return 1; }

錯誤訊息 v 19: error C 2143: syntax error : missing '; ' before '/‘ 錯誤訊息 v 19: error C 2143: syntax error : missing '; ' before '/‘ v 經檢查發現並沒有少 ‘; ’ 的情況,錯誤在別 的地方

先略去紅色部分程式 1. 2. 3. #include <stdio. h> #include <stdlib. h> #include <string. h> 24. 先略去紅色部分程式 1. 2. 3. #include #include #include 24. 25. 26. 27. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. #define HEAD 4 #define LENGTH 24 #define P 0 5 #define WIDTH 95 #define ERROR -1 #define MAXLINES 10 char *lines[MAXLINES]; FILE *fd, *printer; int main() { char buff[80]; int max, j, offset, len, count; if ((fd = fopen("address", "r")) == 0) { / * give the user some lelp. . . * / printf("address file does not exist. n"); exit(ERROR); } printer = fopen("LPT 1", "w"); 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. for (count = 0, max = 0; count < MAXLINES; count++) { if (fgets(buff, 80, fd) == 0) break; else { len = strlen(buff); lines[count] = (char *)malloc(80); if (len > max) max = len; strcpy(lines[count], buff); } } offset = ((WIDTH - max)/2)+P 0; for (j = 0; j < offset; j++) buff[j] = ' '; buff[j] = ''; offset = (LENGTH - count)/2 - HEAD; for (j = 0; j < offset; j++) fputs("n", printer); for( j = 0; j < count; j++) fprintf(printer, "%s%s", buff, lines[j]); fputs("14", printer); fclose(fd); fclose(printer); system("PAUSE"); return 1; }

錯誤訊息 v 19: error C 2143: syntax error : missing '; ' before '/‘ 錯誤訊息 v 19: error C 2143: syntax error : missing '; ' before '/‘ v 由於 錯誤訊息沒有改變, 顯然 錯誤不在刪 除的地方。

再略去藍色部分程式 1. 2. 3. #include <stdio. h> #include <stdlib. h> #include <string. h> 24. 再略去藍色部分程式 1. 2. 3. #include #include #include 24. 25. 26. 27. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. 22. 23. #define HEAD 4 #define LENGTH 24 #define P 0 5 #define WIDTH 95 #define ERROR -1 #define MAXLINES 10 char *lines[MAXLINES]; FILE *fd, *printer; int main() { char buff[80]; int max, j, offset, len, count; if ((fd = fopen("address", "r")) == 0) { / * give the user some lelp. . . * / printf("address file does not exist. n"); exit(ERROR); } printer = fopen("LPT 1", "w"); 28. 29. 30. 31. 32. 33. 34. 35. 36. 37. 38. 39. 40. 41. 42. 43. 44. 45. 46. for (count = 0, max = 0; count < MAXLINES; count++) { if (fgets(buff, 80, fd) == 0) break; else { len = strlen(buff); lines[count] = (char *)malloc(80); if (len > max) max = len; strcpy(lines[count], buff); } } offset = ((WIDTH - max)/2)+P 0; for (j = 0; j < offset; j++) buff[j] = ' '; buff[j] = ''; offset = (LENGTH - count)/2 - HEAD; for (j = 0; j < offset; j++) fputs("n", printer); for( j = 0; j < count; j++) fprintf(printer, "%s%s", buff, lines[j]); fputs("14", printer); fclose(fd); fclose(printer); system("PAUSE"); return 1; }

錯誤訊息 v 錯誤訊息消失, 顯然 錯誤在刪除的地方, 即藍色程式碼的地方。 錯誤訊息 v 錯誤訊息消失, 顯然 錯誤在刪除的地方, 即藍色程式碼的地方。

只留下藍色部分程式 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 只留下藍色部分程式 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. 20. 21. #include #include #include #define ERROR -1 FILE *fd, *printer; int main() { char buff[80]; int max, j, offset, len, count; if ((fd = fopen("address", "r")) == 0) { / * give the user some lelp. . . * / printf("address file does not exist. n"); exit(ERROR); } printer = fopen("LPT 1", "w"); fclose(fd); fclose(printer); system("PAUSE"); return 1; }

錯誤訊息 v 19: error C 2143: syntax error : missing '; ' before '/‘ 錯誤訊息 v 19: error C 2143: syntax error : missing '; ' before '/‘ v 由於 錯誤訊息沒有改變, 顯然 錯誤只在 10 至 15行之間。 v 由於 錯誤訊息被限制在很短的程式碼中, 可以直接小心的檢查程式碼找出錯誤。

追蹤程式的結構 v 追蹤程式的結構可以觀察程式執行的順 序是否符合設計。 追蹤程式的結構 v 追蹤程式的結構可以觀察程式執行的順 序是否符合設計。

追蹤 if-else的結構 v 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 追蹤 if-else的結構 v 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 原始程式 if (person. age < 5) { addtopreschool(person); } else if (person. age < 14) { addtogrades(person); } else { addtohigh(person); } v 追蹤程式的結構 1. printf("n Approaching age branch, person. age = %d", person. age); if (person. age < 5) { printf("n. Calling addtopreschool"); addtopreschool(person); } else if (person. age < 14) { printf("n. Calling addtogrades"); addtogrades(person); } else { printf("n. Calling addtohigh"); addtohigh(person); } printf("nreturned from call in age branch"); 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17.

追蹤 do-while的結構 v 原始程式 v 1. do { 1. 2. part 1(); part 2(); 追蹤 do-while的結構 v 原始程式 v 1. do { 1. 2. part 1(); part 2(); part 3(); k = part 4(); } while(k < 15); 3. 4. 5. 6. 2. 3. 4. 5. 6. 7. 8. 9. 追蹤程式的結構 printf("n. Approaching 4 -part loop"); do { part 1(); part 2(); part 3(); k = part 4(); printf("n. In 4 -part loop, after part 4, k = %d", k); } while(k < 15); printf("n. Past four part loop");

追蹤 break & continue的結構 v 1. 2. 3. 4. 5. 6. 7. 8. 9. 追蹤 break & continue的結構 v 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 原始程式 while(k--) { checka(); if ((stat = checkb()) == 13) { break; } else if (stat > 25) { continue; } checkc(); } v 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 追蹤程式的結構 printf("n. Approaching checkit loop, k = %d", k); while(k--) { checka(); if ((stat = checkb()) == 13) { printf("nbreaking, stat = 13"); break; } else if (stat > 25) { printf("ncontinuing, stat = %d, k = %d", stat, k); continue; } checkc(); printf("nat end of checks, k = %d", k); } printf("n. Past checkit loop");

找出下列程式的錯誤 1. 2. 3. 4. 5. 6. 7. 8. 9. while (c = getchar() 找出下列程式的錯誤 1. 2. 3. 4. 5. 6. 7. 8. 9. while (c = getchar() != 'X') { switch(c) { case 'R': dorwork(); break; case 'L': dolwork(); break; case 'Z': dozwork(); break; } }

加入追蹤結構 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 加入追蹤結構 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 15. printf("n. Approaching while-loop"); while (c = getchar() != 'X') { switch(c) { case 'R': printf("n. In R case"); dorwork(); break; case 'L': printf("n. In L case"); dolwork(); break; case 'Z': printf("n. In Z case"); dozwork(); break; default: printf("n. Enter an error character %c“, c); exit(); } } printf("n. Exiting while-loop");

加入追蹤結構的結果 v 錯誤仍然存在 v 加入的追蹤程式未發生作用 v 結論: 第 2行可能有問題 v 動作: 加入第 2行之追蹤 加入追蹤結構的結果 v 錯誤仍然存在 v 加入的追蹤程式未發生作用 v 結論: 第 2行可能有問題 v 動作: 加入第 2行之追蹤

新的追蹤結構 v v v v v printf( 新的追蹤結構 v v v v v printf("n. Approaching while-loop"); char ch = getchar(); printf("ngetchar returns %c", ch); while (c = ch != 'X') { printf("n. Loop entered, selecting on %c %d", c, c); switch(c) { case 'R': printf("n. In R case"); dorwork(); break; case 'L': printf("n. In L case"); dolwork(); break; case 'Z': printf("n. In Z case"); dozwork(); break; default: printf("n. Enter an error character“); exit(); } } printf("n. Exiting while-loop");

由鍵盤輸入 R,追蹤結果 預期輸出 : Approaching while-loop getchar returns R Loop entered, selecting on R 由鍵盤輸入 R,追蹤結果 預期輸出 : Approaching while-loop getchar returns R Loop entered, selecting on R 52 Enter an error character 實際輸出 : Approaching while-loop getchar returns R Loop entered, selecting on 1 Enter an error character

找到錯誤 while (c = getchar() != ‘X’) 應改為 while ((c = getchar()) != ‘X’) 找到錯誤 while (c = getchar() != ‘X’) 應改為 while ((c = getchar()) != ‘X’)

函數的追蹤 v v 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 加入追蹤結構的 函數的追蹤 v v 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 加入追蹤結構的 程式 原始程式 k = n+j; m = foobar(k); k = m+j; . . . 1. k = n+j; int foobar(int parm) { int result; result = table[parm]; return result; } 7. 2. 3. 4. 5. 6. 8. 9. 10. 11. 12. 13. 14. 15. 16. 17. 18. 19. printf("nready to call foobar with %d", k); m = foobar(k); printf("nreturned %d from foobar", m); k = m+j; . . . int foobar(int parm) { int result; printf("nenter foobar with %d", parm); result = table[parm]; if (result >= 0) { printf("npositive exit, result=%d", result); return result; } printf("nneg result, returning %d", parm); return parm; }

資料流程追蹤 (變數追蹤 ) v 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 資料流程追蹤 (變數追蹤 ) v 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 原始程式 k=process(m); . . // no references to k in missing code . proc 2(k); . . // no references to k in missing code . j = k + m; k = 2 * process(n); v 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. 13. 14. 加入追蹤結構的 程式 k=process(m); printf("nafter process k = %d", k); . . // no references to k in missing code . printf("nbefore proc 2 k = %d", k); proc 2(k); . . // no references to k in missing code . printf("nin addition, k = %d", k); j = k + m; k = 2 * process(n); printf("nafter 2&process, k = %d", k);

快照 (Snapshots) 原始程式 #include <stdio. h> #include <stdlib. h> void main() { int x[10]; 快照 (Snapshots) 原始程式 #include #include void main() { int x[10]; for (int i=1; i <= 10; i++) x[i] += i*i; } v v 加入快照的 程式 #include #include void snaptable(int x[], int n) { for (int i = 0; i < n; i++) printf(“%d “, x[i]); } void main() { int x[10]; snaptable(x, 10); for (int i=1; i <= 10; i++) x[i] += i*i; snaptable(x, 10); }