---
# System prepended metadata

title: 2024q1 Homework1 (lab0)

---

# 2024q1 Homework1 (lab0)
contributed by < [wayne10823014](https://github.com/wayne10823014) >

### Reviewed by `weihsinyeh`
1. 邊寫程式碼邊更新開發紀錄，很多程式沒被紀錄進來。
2. [commit 49f4d09](https://github.com/wayne10823014/lab0-c/commit/49f4d09eb9c1a6835f7b296c0b2e650404819815) 143行 `char *maxVal = NULL;` 這個拿掉。解決辦法就是每次 commit 前整理程式碼。
3. [commit 826d272](https://github.com/wayne10823014/lab0-c/commit/826d272ca606f81146c56e4676e640624cc1a497) 寫程式前先看好規則的優點：避免浪費時間。
4. 減少多餘的大括號，判斷式裡面只有一行就可以拿掉。優點無用的大括號一旦減少，那就有更多的行來寫註解。

## 開發環境

```shell
$ gcc --version
(Ubuntu 11.4.0-1ubuntu1~22.04) 11.4.0

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) i5-8265U CPU @ 1.60GHz
    CPU family:          6
    Model:               142
    Thread(s) per core:  2
    Core(s) per socket:  4
    Socket(s):           1
    Stepping:            11
    CPU max MHz:         3900.0000
    CPU min MHz:         400.0000
    BogoMIPS:            3600.00
```


:::warning
將語系設定為 `C`，亦即執行 `export LC_ALL=C`，再執行上方的命令，這樣才會得到英文的訊息。
:::


## 針對佇列操作的程式碼實作
### `q_insert_head`
一開始的程式碼為以下
```c
bool q_insert_head(struct list_head *head, char *s)
{
    element_t *node = malloc(sizeof(element_t));
    if (!node) {
        return false;
    }
    char *str = malloc(sizeof(char) * strlen(s) + 1);
    if (!str) {
        return false;
    }
    strcpy(str, s);
    node->value = str;
    list_add(&node->list, head);
    return true;
}
```

:::danger
無論標題和內文中，中文和英文字元之間要有空白字元 (對排版和文字搜尋有利)
:::

出現了兩個問題
1. strcpy <s>函數</s> 函式被警告為危險函式，建議使用 strncpy 進行替代。 strncpy 允許指定最大複製<s>字符數</s> 位元組的數量，從而避免緩衝區溢出的問題。
2. 在檢查 str 是否成功配置的條件中，遇到 "記憶體洩漏: node" 的問題。發現 str 在 malloc <s>分配</s> 配置時失敗，應該釋放先前為 node 配置的空間。

:::warning
function 一字多義，務必依據場景提供合適的翻譯。對應到數學公式，function 應翻譯為「函數」，後者就像是台「機器」，它能夠將集合 A 裡面的每個元素「唯一地」對應到集合 B 裡的一個元素。但在 C 語言一類的通用程式語言中，function 未必具備數學函數的意涵，也就是缺乏「唯一對應」的特性，例如對於 time 來說，給定同樣的輸入，卻會在不同時間點得到不同的結果，在 C 語言一類的通用程式語言中，甚至可省略傳回值，後者就不符合「函數」的行為。因此，當在通用的程式設計中，function 應翻譯為「函式」，表示「衍生自數學函數的常式 (routine)」。
$\to$ [資訊科技詞彙翻譯](https://hackmd.io/@sysprog/it-vocabulary)

allocate 翻譯為「配置」，而非「分配」，是為了跟「分發」(dispatch) 區隔，二者都會在作業系統領域多次出現。
:::

:::danger
避免過多的中英文混用，已有明確翻譯詞彙者，例如「鏈結串列」(linked list) 和「佇列」(queue)，就使用該中文詞彙，英文則留給變數名稱、人名，或者缺乏通用翻譯詞彙的場景。
:::

修正後
```diff
     char *str = malloc(sizeof(char) * strlen(s) + 1);     
     if (!str) {
+        free(node);
         return false;
     }
-    strcpy(str, s);     
+    strncpy(str, s,strlen(s) + 1);
     node->value = str;
     list_add(&node->list, head);
     return true;
```

:::warning
使用 diff 工具程式來產生程式碼差異，注意縮排
:::

:::danger
改進你的漢語表達。
:::

### `q_free`
一開始的程式碼為以下
```c
void q_free(struct list_head *l)
{
    if (!l) {
        return;
    }
    element_t *entry, *safe;
    list_for_each_entry_safe (entry, safe, l, list) {
        free(entry);
    }
    free(l);
}
```

出現 "已釋放佇列，但仍分配 52199562 個區塊" 的錯誤。檢查後發現已釋放 entry 配置的空間，但 entry 內的 value 所使用的空間並未一併釋放。因此需要添加程式碼來釋放 value 所擁有的空間

修正後
```diff
     }
     element_t *entry, *safe;
     list_for_each_entry_safe (entry, safe, l, list) {
+        if (entry->value) {
+            free(entry->value);
+        }
         free(entry);
     }
     free(l);
```

:::warning
參閱 [free(3)](https://man7.org/linux/man-pages/man3/free.3.html) 可知 "If ptr is NULL, no operation is performed."，意味著你不用撰寫形如 `if (entry->value) { free(entry->value); }` 的程式碼，直接呼叫 `free` 即可，不用額外的 `if` 敘述。
:::

根據規格書中
>The free() function frees the memory space pointed to by ptr,which must have been returned by a previous call to malloc() or related functions. Otherwise, or if ptr has already been freed,undefined behavior occurs.  If ptr is NULL, no operation is performed.

在 ptr 為 NULL 的情況下，使用 free() 釋放 ptr 不會有任何作用。

修正多餘的 if 判斷式
```diff
     }
     element_t *entry, *safe;
     list_for_each_entry_safe (entry, safe, l, list) {
-        if (entry->value) {
-            free(entry->value);
-        }
+        free(entry->value);
         free(entry);
     }
     free(l);
```

### `q_delete_mid`
一開始的程式碼為以下
```c
bool q_delete_mid(struct list_head *head)
{
    if (!head || list_empty(head)) {
        return false;
    }
    struct list_head *node = head;
    for (struct list_head *fast = head; fast && fast->next;
        fast = fast->next->next) {
        node = node->next;
    }
    element_t *tmp = list_entry(node, element_t, list);
    list_del(node);
    free(tmp->value);
    free(tmp);
    return true;
}
```

出現 "錯誤：時間限制已超過。可能是你的程式碼進入了無限迴圈，或者你的程式碼效率不足" 。發現因為題目是雙向鏈結串列，若繼續使用原本在 LeetCode 上的寫法，會造成 for 迴圈永遠無法停止。同時，修正了 fast 與 node 初始位置設定錯誤造成的問題。

修正後
```diff
     if (!head || list_empty(head)) {
         return false;
     }
-    struct list_head *node = head;
-    for (struct list_head *fast = head; fast && fast->next;
+    struct list_head *node = head->next;
+    for (struct list_head *fast = head->next;
+         fast != head->prev && fast->next != head->prev;
          fast = fast->next->next) {
          node = node->next;
     }
```

:::warning
善用 List API，撰寫更精簡的程式碼。
:::

### `q_sort`
