實習目標 | 本實驗接續Lab 1-1, 在 Visual C++ 環境中熟悉使用 assert() macro 來驗證/確保 C/C++ 程式在開發過程中不斷修改或是增加功能時的正確性 |
---|---|
步驟一 | 請下載 statisticsAndSort.exe 程式, 這個程式基本上讀取一個資料檔案raw1.dat, 預備計算檔案內所有資料的平均值, 各種資料出現的中間值, 以及出現頻率最高的數值。 在 Lab 1-1 中我們完成了一個分開在多個 .cpp 檔案裡的 程式, 但是這個程式基本上還有很多的假設與很多的漏洞: 請下載資料檔案raw2.dat 以及 raw3.dat 執行後你會發現有一些問題。 例如輸入 raw2.dat 時有一些資料好像超過範圍 (1-9), 輸入 raw3.dat 時好像資料量太多了, 或是輸入一個不存在的檔案名稱 (例如 raw4.dat) 時程式都應該會有問題。 請依照下列的步驟在程式適當的地方加入 assert() 的敘述來確保我們在撰寫程式時的一些假設: |
步驟二 |
在 readFile() 函式中有下列敘述:
gets(filename); fp = fopen(filename, "rt"); fscanf(fp, "%d", dataSize);在撰寫上述程式片段時其實有一個假設存在, 就是 "gets(filename) 所讀到使用者輸入的檔案名稱所相對應的檔案是存在的", 所以程式才沒有去偵測如果呼叫 fopen() 開啟檔案時失敗的話該如何處理。 假設我們希望在錯誤的時候直接結束程式的話, 我們可以運用 assert() 函式來確保這個假設。 我們將程式改為 gets(filename); fp = fopen(filename, "rt"); assert(fp != 0); fscanf(fp, "%d", dataSize); 就可以自動的驗證這個假設。 請修改你的程式加上 assert() 函式呼叫, 注意要使用 assert() 必須要加上 #include<assert.h> , assert() 函式的用法如果 不曉得的話, 請查詢 MSDN Library, 然後再試看看輸入一個錯誤的檔案名稱會發生什麼事情 通常發生 assert 錯誤時有經驗的設計者會直接按 "重試" 進入 debugger 確定到底是哪裡出錯了(以後再談) |
步驟三 | 請在程式適當的地方加上 assert() 敘述以保證檔案中讀到的資料個數不大於陣列的大小 DATASIZE |
步驟四 | 請在程式適當的地方加上 assert() 敘述以保證檔案中讀到的資料範圍都在 1 和 9 之間 |
步驟六 | 請在程式適當的地方加上 assert() 敘述以保證 sort() 函式所得到的結果是對的 (我們不希望每次都用眼睛檢查那些輸出來的幾百筆資料來驗證排序是否正確)。 通常我們會用別的演算法來驗證, 例如一個排序過後的陣列裡面的元素應該是由大到小的排列, 所以我們可以另外寫一個函式來驗證陣列中第 i 個元素是不是大於等於第 i+1 個元素。 |
步驟七 | 因為你在上一個步驟已經加上驗證 sort() 結果的 assert() 敘述了, 所以你現在可以輕鬆地應付兩種狀況:
#include <stdlib.h> int compare(const void *elem1, const void *elem2 ); void main() { int a[] = {5, 3, 4, 1, 2}; int numElements = 5; qsort(a, numElements, sizeof(int), compare); for (i=0; i<numElements; i++) printf("%d ", a[i]); printf("\n"); } int compare(const void *elem1, const void *elem2 ) { if (*(int *)elem1 < *(int *)elem2) return -1; else if (*(int *)elem1 == *(int *)elem2) return 0; else return 1; } |
步驟八 |
想想看這個程式裡還有什麼地方有假設可以確認的?
|
步驟九 | 請助教檢查後, 將所完成的 project (去掉 debug/ 資料匣下的所有內容) 壓縮起來 選取 Lab1-2 上傳, 下星期的實習課程需要使用你今天所完成的程式 |
步驟十 | 請注意, assert() 是程式開發人員用的工具, 在程式開發完成交給使用者的時候, 程式裡不應該有這樣子的敘述..., 難道好不容易加進去的東西還要一列一列拿掉嗎? 不不不!!! 用下面的敘述可以讓某一個檔案裡所有的 assert() 敘述都不發生作用, #define NDEBUG 需要在每一個檔案的開頭 (#include <assert.h> 之前) 都定義一次。 另外一種方法是使用編譯的旗標來控制, 在選單中選取 專案 / lab1-2 屬性 / 組態屬性 / C/C++ / 前置處理器 => 在前置處理器定義最後 加入 |
回
C++ 程式設計課程
首頁
製作日期: 2004/02/16
by 丁培毅 (Pei-yih Ting)
E-mail: [email protected]
TEL: 02 24622192x6615
海洋大學
電機資訊學院
資訊工程系
Lagoon