contributed by < AmyLin0210
>
2021q1 Linux
為了要達成時間複雜度 ,加上 *tail
與 size
。
需要更多解釋,包含後續的使用和資料更新方式。
tail
指向 linked list 的最末端,用途為在尾端插入數值時,可以不用從最前方走訪所有節點,使得時間複雜度降為 。它會在 list 的最末端有變動時,例如q_insert_tail
,q_sort
,q_reverse
等函式執行時變更他的位置,以確保它正確指向最末端。
size
用於紀錄 linked list 的長度,所以在呼叫q_size
時,不用遍歷整串 linked list,時間複雜度降為 。它會在 linked list 的長度有變化時被改變,例如q_insert_tail
,q_insert_head
,q_remove_head
。
確認 malloc 的回傳值是否合法,然後將所有參數初始化。
將所有動態分配 ( malloc ) 的空間給釋放。
這兩個函式實做的部份差不多,在第 13 行與 41 行的部份曾經犯過一個錯誤,記得檢查是否有成功 malloc 給 value,但在發現 malloc 失敗時直接 return false,忘記先清掉前面 malloc 給 list_element_t 的空間。
避免說「採過一個坑」這樣不精準的話,請記住,這份共筆可能是日後代表你程度的作品,務必斟酌用詞。
已修正
為了實做時間複雜度 ,故在 queue_t 中新增size
,儲存目前 list 的長度。
有想過否要使用遞迴的方式,程式碼會比較直覺簡單,但是空間複雜度會變成 ,相比較之下,迴圈的空間複雜度為 ,所以最終是使用迴圈來實做。
最初是使用 quick sort,但它的 worst case 可能發生在大多數需要被排序的數的優先序相同,時間複雜度為 ,而在測試資料中就有對應的項目,故之後會改用時間複雜度為 的 merge sort 來實做。
參考資料:
Makefile 語法和示範
gcc(1) — Linux manual page
開始看 Makefile 之後又發現自己的一無所知,接下來就是一連串找資料、學習、寫筆記的開始,在此感謝同學 randy870819 與 KYG-yaya573142 的共筆!
-O1
: 在編譯器裡有 -O0
-O1
-O2
-O3
四個優化程度可以選擇,-O0
為不優化而 -O3
的優化級別最高-g
: 產生 debugging information-Werror
: 讓每個 warnings 變成 error-Idir
: 會在編譯時先在 dir 尋找有沒有符合的 header file,找不到才會依照常規順序繼續尋找在編譯時加入一些 sanitizer 的參數
在這裡決定要不要印出詳細的編譯過程
@
的作用是不顯示執行的指令@true
可以使該行命令被視作成成功這邊使用了 Auto-Dependency Generation 來處理 dependency 的問題
OBJS
中的 .o
檔代換成 .檔案名稱.o.d
-MMD
the driver uses its argument but with a suffix of .d, and mention only user header files, not system header files-MF
overrides the default dependency output file當目標 ( target ) 比起自己的相依項目 ( dependency ) 還要建立的更早時,表示其相依項目已經被修改,在此利用 GNU make 中 auto-rebuild 的特徵重新建立目標。
// 施工研究中
先執行 qtest 再於命令提示列輸入 help 命令,會使 開啟 Address Sanitizer 觸發錯誤
以下是錯誤訊息的節錄
從第 11 行來看,我們要從 console.c
去尋求進一步的線索。
在 console.c
的第 59 行,有一個變數宣告
往下搜尋還有其他哪些地方有用到這個 echo
變數,發現以下程式碼的第 21 行對 echo
進行了強制轉型,但是原 echo
的型態為 bool ,它卻將指向 bool 位置的指標改成指向 int 位置的指標。
當 add_param 以為該指標指向 integer 但實際上是指向 bool 時,就有可能會發生 buffer overflow 的問題。
在我的電腦中執行以下程式碼, int 和 bool 的大小不同增強了我對那段程式碼的懷疑。
在 console.c
中有一段程式碼
在第 12 行中的 *plist->valp
存取到的就是上述所提的 echo
變數,但它卻是用 %d 來讀取一個 1 byte 的數值,因此 buffer overflow。
目前我想到的改善方式是改變該程式碼中 echo
與有相同問題的 simulation
,將他們由 bool 改為 int ,但改變資料型態後可能會造成其餘相關程式碼出現問題,所以還在思考有沒有更優雅的改法。
以下擷取自 make valgrind
後得到的訊息
首先我們看到 valgrind 的錯誤訊息,still reachable
表示程式結束時有未釋放的記憶體,不過卻還有指標指著。
接下來我們找到 qtest.c
的第 769 行。
接下來看看 linenoise.c
的 1325 行,可以發現又呼叫了另一個函式。
在這份程式碼中,有使用一個名為 history 的參數,型態為 char**
,當中做的事情是儲存字串,而 linenoiseHistoryAdd
做的就是將這些字串加入 history。
因此我猜測由於 history
所指向的記憶體空間在程式結束前沒有被成功的清掉,所以才會出現 still reachable
這項錯誤。
最後我在程式結束前將 history 指向的空間清掉,就不會再跳出錯誤訊息了。