# 2024q1 Homework1 (lab0)
contribute by < `benjue123` >
:::danger
依據作業要求,變更本筆記的標題。
:::
## 開發環境
gcc --version
gcc (Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0
$ lscpu
Architecture: x86_64
CPU op-mode(s): 32-bit, 64-bit
Address sizes: 39 bits physical, 48 bits virtual
Byte Order: Little Endian
CPU(s): 8
On-line CPU(s) list: 0-7
Vendor ID: GenuineIntel
Model name: Intel(R) Core(TM) i7-1065G7 CPU @ 1.30GHz
CPU family: 6
Model: 126
Thread(s) per core: 2
Core(s) per socket: 4
Socket(s): 1
Stepping: 5
CPU max MHz: 3900.0000
CPU min MHz: 400.0000
BogoMIPS: 2995.20
## 佇列操作的程式碼實作
### q_new
```c
struct list_head *head = malloc(sizeof(struct list_head));
if (!head)
return head;
INIT_LIST_HEAD(head);
return head;
```
根據 C11 7.22.3.4 **The malloc function** 中的內容,我們可以得知使用 malloc function 可能會回傳 `null`,所以在使用巨集 `INIT_LIST_HEAD()` 前需要回傳值的內容
> The malloc function allocates space for an object whose size is specified by size and
whose value is indeterminate.
>#### Returns
>The malloc function returns either a null pointer or a pointer to the allocated space.
### q_free
```c
element_t *temp, *safe;
if (!head)
return;
list_for_each_entry_safe (temp, safe, head, list)
q_release_element(temp);
free(head);
return;
```
由於使用了 `q_release_element`,所以要注意 `q_release_element` 引入的是 `element_t`,而使用此函式會先釋放 `value`,再來釋放 `element`,因此最後需要再釋放 `head` 才是完整的釋放完畢
:::danger
`q_release_element` 不是巨集。
:::
### q_insert_head
```c
element_t *element = malloc(sizeof(element_t));
if (!element)
return false;
element->value = malloc(sizeof(char) + strlen(s) + 1);
element->value = strncpy(element->value, s, strlen(s) + 1);
if (!element->value) {
free(element);
return false;
}
list_add(&element->list, head);
return true;
```
`strdup` 會先配置與參數的字串相同的空間大小,然后將參数的字符串的内容複製到新配置的空間的地址,然后把该地址返回,相較於 strncpy ,這能夠少 malloc 一次
:::danger
string 的翻譯是「字串」,沒有鬼畫「符」。
注意用語,不該有簡體中文字。
:::
不過使用 strdup 會在釋放位址遇到問題,會有提示說某個位址的區塊偵測到損毀,而用 `make check` 來測試時,也會遇到儲存的字串為亂碼的問題,<s>這可能是因為 `strdup` 不是標準的 C 函式庫函式所導致的</s>
```c
char *copy = strdup(s);
element->value = copy;
// free(copy);
list_add(&element->list, head);
return true;
```
在查閱 Linux man page 中的 `strdup` 的描述後,我得知亂碼的出現是因為這裡是將 element->value 指向 copy,但是這邊後來直接對 copy 做釋放空間的操作,所以會有上述在釋放位址時所遇到的問題
:::danger
查閱 Linux man page 並細讀。
:::
因此需要考慮平台相容性的問題,所以後來改用 `strncpy` 代替 `strdup`,而上述的問題也就沒遇到了
:::danger
compatibility 的翻譯是「相容性」。
:::
:::danger
注意項目縮排 (即 `# `, `## `, `### `),筆記標題用一個 `#`,項目標題用二個 `#`,子項目則用三個 `#`,避免過高的深度。
:::
```c
element_t *element = malloc(sizeof(element_t));
if (!element) {
return false;
}
char *str = malloc(sizeof(char) * strlen(s) + 1);
if (!str) {
free(element);
return false;
}
strncpy(str, s, strlen(s) + 1);
element->value = str;
```
雖然執行 qtest 時並無異狀,但執行 make chech時會出現 Segmentation fault occurred. You dereferenced a NULL or invalid pointer,在參考wayne10823014的github後,發現是因為順序而導致的記憶體洩漏問題,需要先確認 str 和 element的空間中有無東西才能使用 strncpy,而且不能直接使用 `element->value = strncpy(str, s, strlen(s) + 1);`,否則也會出現 Segmentation fault occurred
### q_insert_tail
邏輯和 q_insert_head 一致,只是將 巨集 `list_add_head` 變更為 `list_add_tail`
### q_remove_head
```c
element_t *tmp = list_first_entry(head, element_t, list);
strncpy(sp, tmp->value, bufsize - 1);
sp[bufsize - 1] = '\0';
list_del_init(&tmp->list);
```
雖然 `strncpy` 會自動在複製的字串尾端加上空字元,但為了避免複製的字串大小超出給定的空間大小,因此保留給定空間的最後位置並設定為 `'\0'`
### q_remove_tail
邏輯和 q_remove_head 一致
### q_delete_dup
在進行 qtest測試時一直出現 error : Segmentation fault occurred. You dereferenced a NULL or invalid pointerAborted ,尚未找出導致error的原因
### q_swap
```c
while (prev->next != head && prev->next->next != head) {
struct list_head *node = prev->next;
list_move_tail(node, node->next->next);
prev = node;
}
```
使用 while 和函式 `list_move_tail` 將兩個相鄰的節點互換