contributed by < rebvivi
>
linux2019
FIFO 和 LIFO 實作 queue
我們是用 linked list 來實現
解釋自動評分系統運作的原理
以及提及 qtest 的行為和裡頭的技巧
所需要的 C 語言認知 :
不要過度簡化作業要求,明明 CMU lab0 要求很多,為何你只看到這句話?工程人員實事求是的精神去哪了?及早脫離「文組TM」
基本的程式碼架構老師已經都建好了,必須先了解 linked list 以及 queue 的架構才能實作
queue 的基本架構
新增 size 讓 queue 隨時紀錄現在 queue 的大小,
不用從頭到尾跑一遍才能知道 queue 的大小
計算 queue 中有幾個 element
因為 queue_t 有新增 size 的 index,讓 q_size 的時間複雜度能維持在
新增一個 empty 的 queue
要注意 malloc 有沒有配置到記憶體
清除整個 queue
記得要先把 element 的 value free 掉之後才能 free 掉 element,
最後再釋放 queue 之前配置的記憶體。
使用 LIFO 的方法新增 element
過程中犯的錯誤
第 7 行的 if ,如果已經判斷 newnode == NULL ,再 free(newnode) 的話 ,會出現以下的錯誤
每次 malloc 都要確認有沒有配置到記憶體,如果配置失敗就要回傳 false 並且 free 剛才 malloc 的東西,避免產生 memory leak 的問題
如果一開始 queue 的 size 是 0 的話,記得要調整 tail
移除 queue 的第一個 element
記得要 free 第一個 element 的 value 再 free 掉 element
使用 FIFO 的方法新增 element
每次 malloc 都要確認有沒有配置到記憶體,如果配置失敗就要回傳 false 並且 free 剛才 malloc 的 node,避免產生 memory leak 的問題
如果一開始 queue 的 size 是 0 的話,記得要調整 head
過程中犯的錯誤
除了 malloc newinsert 之外, newinsert 的 value 也要配置記憶體
第 12 行使用到 strdup(), 但是會造成 memory allocate 的錯誤
strdup()不是標準的 C 函式,在 strdup() 的 Linux Man Page 的 Description 中提到:
The strdup() function returns a pointer to a new string
which is a duplicate of the string s.
Memory for the new string is obtained with malloc(3),
and can be freed with free(3).
我們在 queue.c 所呼叫的 malloc
和 free
在 qtest 都會改成呼叫 test_malloc
和 test_free
,所以如果我們使用 strdup(),就用不到真正的malloc
和 free
,導致配置記憶體出問題
而 strcpy() 是標準的 C 函式,所以應該改成:
「strdup()不是標準的 C 函数,所以在 linux 上使用會有問題」這句陳述的「所以」有問題,GNU/Linux 是符合 POSIX 標準的作業系統,語言標準 (如 C99) 和標準執行環境 (如 POSIX) 之間的關聯,你需要描述。請查證並列出 POSIX.1-2001 規格書描述。在你「舉燭」之前,要讀書。
function 用於數學領域,譯作「函數」,但在程式設計中作為通用 subroutine 的話,譯作「函式」
把 queue 裡面的 element 反轉
如果 queue 是空的或是 queue 只有一個 element 就不用 reverse
在 harness.h 中,我們在 queue.c 所用的
malloc
和free
都被改成呼叫test_malloc
和test_free
block_ele_t
是一個doubly linked list
的結構
test_malloc
實際上需要配置的空間=
(我們所要求的 size 大小) + (block_ele_t
所需要的空間) + (sizeof(size_t)的空間),而 sizeof(size_t) 的空間是為了紀錄magic_footer
magic_header
和magic_footer
是用來紀錄所配置的記憶體的前後位置,我們將兩者定義為常數
如果
magic_header
和magic_footer
的數值被更改了,代表我們寫入的位址超過我們配置記憶體的範圍
如果是magic_header
被更動數值,就是寫入的記憶體向前
超過我們配置的範圍,如果是magic_footer
被更動數值,就是寫入的記憶體向後
超過我們配置的範圍
Q&A
Q:為什麼當初宣告block_ele_t
的 structure 的時候不宣告 magic_footer
?
A:因為我們每次用 malloc
所輸入的 size 都不一樣,所以配置空間的結尾
也會不同,magic_footer
位置也就不同,所以我們ㄧ要幫magic_footer
預留一個sizeof(size_t)的空間,之後再用find_footer
去找到magic_footer
的位置
需要解釋 magic 的用途,最好搭配用另外一個獨立的試驗 (及相關記憶體分析工具) 來說明,避免「舉燭」。
test_malloc
所配置的空間紀錄在叫做allocated
的doubly linked list
中,這個doubly linked list
中的payload[0]
代表我們在 queue.c 用malloc
呼叫的記憶體的開頭
用
allocate_count
紀錄所配置的記憶體長度,如果沒有歸還完全malloc
所配置的記憶體,allocate_count
的長度就會大於 1 ,並且出現以下的錯誤訊息
exception 的設置目的:
在處理 exception 的時候用到了 sigsetjmp ,如果 sigsetjmp
的值不是 0 ,代表是從 siglongjmp
回來的
setjmp() and sigsetjmp() return 0 if returning directly, and nonzero when returning from longjmp(3) or siglongjmp(3) using the saved context
而 siglongjmp
不 return,在 siglongjmp的 Linux Man Page 的 Return Value 有提到:
These functions never return.
主要概念
如果 limit_time=true,代表程式是有時間限制的,如果在時間限制內沒有呼叫 exception_cancel
的話,就會觸發 trigger_exception
產生錯誤訊息
在 qtest 中我們都把
exception_setup
中的 limit_time 設成 true
- 因為並不是從
setlongjmp
跳回來的,所以sigsetjmp
的值是 0- 跳到
exception_setup
的 17 行執行,此時 jmp_ready = true , 而 time_limited 最初設定是 false ,現在被改成 time_limited = true- 因為 jmp_ready = true 所以執行
trigger_exception
第 6 行的siglongjmp
- 此時因為是從
setlongjmp
跳回來的,sigsetjmp
的值變成不是 0 ,所以會執行exception_setup
的第 3 行的 if 的內容- jmp_ready = false , time_limited 從 true 被改成 false,report_event 產生錯誤訊息
在 console.h 中,command 和 parameter 都是一個
linked list
的結構
我們利用add_cmd
和add_param
來將 command 和 parameter 加入linked list
在 console.c 中,有一個
linked list
的結構用來儲存 input
parse_args
把所有的 input 都轉換成 (int argc, char *argv[]) 的形式,將所有的 input 都用同一種形式存取,這樣對於呼叫任意 qtest 中的函式也會更加方便
在
console_init
裡頭,設定輸入 input 和測試函式的連結
例如:輸入 input "new",會執行測試函式"do_new"測試我們在 queue.c 中所打的 q_new