# 2019q1 Homework1 (lab0) contributed by < [ `ndsl7109256` ](https://github.com/ndsl7109256) > [作業說明](https://hackmd.io/s/BJp_jq-tm) [C Programming Lab](http://www.cs.cmu.edu/~213/labs/cprogramminglab.pdf) ## 環境 ``` $ uname -a Linux bk 4.15.0-39-generic #42-Ubuntu SMP Tue Oct 23 15:48:01 UTC 2018 x86_64 x86_64 x86_64 GNU/Linux $ gcc --version gcc (Ubuntu 7.3.0-16ubuntu3) 7.3.0 ``` ## 作業目標 - 英文閱讀 - C 語言程式設計基礎 - 準備 GNU/Linux 開發工具 - 學習使用 Git 與 GitHub - 學習效能分析 - 研究自動測試機制 ## 作業要求 - 實驗目標為實作 queue * first in, first out (FIFO) * last in, first out (LIFO) ## 實際過程 此次作業主要編輯的部分其實只有 `queue.c` 和 `queue.h` 其他有趣的部分留在後面探討。 - queue.h 在 queue.h 裡只更動了 queue_t 的 structure部分,在裡面加入一個指向指標 tail 的指標和一個 integer 的 size 。其目的主要為了達成 $O(1)$ 的 q_insert_tail 和 q_size 否則每次都必須遍尋整串 linked list 使時間複雜度變成 $O(n)$。 ``` c= typedef struct { list_ele_t *head; /* Linked list of elements */ list_ele_t **tail; // To implement q_insert_tail quickly int size; // To know the q_size quickly } queue_t; ``` - queue.c * q_new 初始化 queue ,記得檢查有沒有 malloc 成功和將 size 設為 0。 (這裡的 q->tail 不能初始化為 NULL 否則如果一開始就 insert tail 的話會失敗 ) ``` c= queue_t *q_new() { queue_t *q = (queue_t *) malloc(sizeof(queue_t)); /* What if malloc returned NULL? */ if (q != NULL) { q->head = NULL; q->tail = &q->head; q->size = 0; return q; } else return NULL; } ``` * q_free 如果 queue 存在的話,不斷檢查其 head 是否 NULL ,如果是就不斷切掉頭,再將 head 指向原本 head 的下一個 element。最後再 free 掉 queue 本身。 記得如果只 free head 本身,其裡面的 value **並不會** 被一起 free 掉。要連同 value 一起做 free 的動作。 ```c= void q_free(queue_t *q) { /* How about freeing the list elements and the strings? */ /* Free queue structure */ if (q != NULL) { list_ele_t *next = NULL; while (q->head != NULL) { next = q->head->next; free(q->head->value); free(q->head); q->head = next; } free(q); } } ``` * q_insert_head 一開始要逐步確認 queue 是否存在、 malloc node 是否成功、 malloc value 是否成功 (如果 malloc 失敗記得 free 掉 node再結束否則會有 memory leak)。 而這裡 malloc 和 copy 字串的長度記得要再加 1 給終結字元否則會有亂碼錯誤出現。 ``` ERROR: Removed value dolphin��� != expected value dolphin ``` ```c= bool q_insert_head(queue_t *q, char *s) { /* What should you do if the q is NULL? */ if (q == NULL) return false; list_ele_t *new_node = (list_ele_t *) malloc(sizeof(list_ele_t)); /* What if either call to malloc returns NULL? */ if (new_node == NULL) return false; /* Don't forget to allocate space for the string and copy it */ new_node->value = (char *) malloc((strlen(s) + 1) * sizeof(char)); if (new_node->value == NULL) { free(new_node); return false; } memcpy(new_node->value, s, (strlen(s) + 1)); new_node->next = q->head; q->head = new_node; if (q->size == 0) { q->tail = &new_node->next; } ++q->size; return true; } ``` * q_insert_tail 跟 q_insert_head 類似,感謝 tail。 可以直接串在 tail 指向的位置就好。 ```c= bool q_insert_tail(queue_t *q, char *s) { /* You need to write the complete code for this function */ /* Remember: It should operate in O(1) time */ if (q == NULL) return false; list_ele_t *new_node = (list_ele_t *) malloc(sizeof(list_ele_t)); if (new_node == NULL) return false; new_node->value = (char *) malloc((strlen(s) + 1) * sizeof(char)); if (new_node->value == NULL) { free(new_node); return false; } memcpy(new_node->value, s, (strlen(s) + 1)); new_node->next = NULL; *(q->tail) = new_node; q->tail = &new_node->next; ++q->size; return true; } ``` * q_remove_head ```c= bool q_remove_head(queue_t *q, char *sp, size_t bufsize) { if (q == NULL || q->size == 0) { return false; } list_ele_t *ptr; ptr = q->head; q->head = q->head->next; if (sp != NULL) { strncpy(sp, ptr->value, bufsize - 1); sp[bufsize - 1] = '\0'; } free(ptr->value); free(ptr); q->size--; if (q->size == 0) { q->tail = &q->head; } return true; } ``` * q_size ``` c= int q_size(queue_t *q) { return (q != NULL) ? q->size : 0; } ``` * q_reverse ```c= void q_reverse(queue_t *q) { if (q != NULL && q->size > 1) { list_ele_t *prev = q->head, *next; q->tail = &(prev->next); q->head = q->head->next; *q->tail = NULL; while (q->head != NULL) { next = q->head->next; q->head->next = prev; prev = q->head; q->head = next; } q->head = prev; } } ``` ## 時間複雜度分析 隔每個 1000000 個 element 測量 insert tail 和 計算 size 的時間 - insert_tail ``` cmd>new q = [] cmd>ih a 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] cmd>time it a q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] Delta time = 0.026 cmd>ih a 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] cmd>time it a q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] Delta time = 0.044 cmd>ih a 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] cmd>time it a q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] Delta time = 0.078 cmd>ih a 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] cmd>time it a q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] Delta time = 0.094 ``` | Element 數 | 1000000 | 2000000 | 3000000 | 4000000 | | -------- | -------- | -------- |-------- | -------- | | **Delta time** | 0.026 | 0.044 |0.078 | 0.094 | - size ``` cmd>new q = [] cmd>ih a 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] cmd>time size Queue size = 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] Delta time = 0.023 cmd>ih a 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] cmd>time size Queue size = 2000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] Delta time = 0.050 cmd>ih a 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] cmd>time size Queue size = 3000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] Delta time = 0.067 cmd>ih a 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] cmd>time size Queue size = 4000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] Delta time = 0.088 cmd>ih a 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] cmd>time size Queue size = 5000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] Delta time = 0.128 cmd>ih a 1000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] cmd>time size Queue size = 6000000 q = [a a a a a a a a a a a a a a a a a a a a a a a a a a a a a a ... ] Delta time = 0.149 ``` | Element 數 | 1000000 | 2000000 | 3000000 | 4000000 |5000000 | 6000000 | | -------- | -------- | -------- |-------- | -------- | -------- |-------- | -------- | | **Delta time** | 0.023 | 0.050 |0.067 | 0.088 | 0.0128 | 0.149 | 這裡發現每次所花的時間跟我們預期的還是有所差距,明顯會隨著 element 數而增加。 尚須思考為何有這樣的情形發生。 ## 自動評分系統運作的原理 CPP check 靜態分析 Vargilind 動態分析 git stash? oom killer sat formal verification ###### tags: `sysprog`,`2019spring`